Scippy

SCIP

Solving Constraint Integer Programs

cons_knapsack.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-2025 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file cons_knapsack.c
26 * @ingroup DEFPLUGINS_CONS
27 * @brief Constraint handler for knapsack constraints of the form \f$a^T x \le b\f$, x binary and \f$a \ge 0\f$.
28 * @author Tobias Achterberg
29 * @author Xin Liu
30 * @author Kati Wolter
31 * @author Michael Winkler
32 * @author Tobias Fischer
33 */
34
35/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
36
38#include "scip/cons_knapsack.h"
39#include "scip/cons_linear.h"
40#include "scip/cons_logicor.h"
41#include "scip/cons_setppc.h"
42#include "scip/pub_cons.h"
43#include "scip/pub_event.h"
44#include "scip/pub_implics.h"
45#include "scip/pub_lp.h"
46#include "scip/pub_message.h"
47#include "scip/pub_misc.h"
49#include "scip/pub_misc_sort.h"
50#include "scip/pub_sepa.h"
51#include "scip/pub_var.h"
52#include "scip/scip_branch.h"
53#include "scip/scip_conflict.h"
54#include "scip/scip_cons.h"
55#include "scip/scip_copy.h"
56#include "scip/scip_cut.h"
57#include "scip/scip_event.h"
58#include "scip/scip_general.h"
59#include "scip/scip_lp.h"
60#include "scip/scip_mem.h"
61#include "scip/scip_message.h"
62#include "scip/scip_nlp.h"
63#include "scip/scip_numerics.h"
64#include "scip/scip_param.h"
65#include "scip/scip_prob.h"
66#include "scip/scip_probing.h"
67#include "scip/scip_sol.h"
69#include "scip/scip_tree.h"
70#include "scip/scip_var.h"
71#include "scip/symmetry_graph.h"
73#include <ctype.h>
74#include <string.h>
75
76#ifdef WITH_CARDINALITY_UPGRADE
78#endif
79
80/* constraint handler properties */
81#define CONSHDLR_NAME "knapsack"
82#define CONSHDLR_DESC "knapsack constraint of the form a^T x <= b, x binary and a >= 0"
83#define CONSHDLR_SEPAPRIORITY +600000 /**< priority of the constraint handler for separation */
84#define CONSHDLR_ENFOPRIORITY -600000 /**< priority of the constraint handler for constraint enforcing */
85#define CONSHDLR_CHECKPRIORITY -600000 /**< priority of the constraint handler for checking feasibility */
86#define CONSHDLR_SEPAFREQ 0 /**< frequency for separating cuts; zero means to separate only in the root node */
87#define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
88#define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
89 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
90#define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
91#define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
92#define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
93#define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
94
95#define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
96#define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
97
98#define EVENTHDLR_NAME "knapsack"
99#define EVENTHDLR_DESC "bound change event handler for knapsack constraints"
100#define EVENTTYPE_KNAPSACK SCIP_EVENTTYPE_LBCHANGED \
101 | SCIP_EVENTTYPE_UBTIGHTENED \
102 | SCIP_EVENTTYPE_VARFIXED \
103 | SCIP_EVENTTYPE_VARDELETED \
104 | SCIP_EVENTTYPE_IMPLADDED /**< variable events that should be caught by the event handler */
105
106#define LINCONSUPGD_PRIORITY +100000 /**< priority of the constraint handler for upgrading of linear constraints */
107
108#define MAX_USECLIQUES_SIZE 1000 /**< maximal number of items in knapsack where clique information is used */
109#define MAX_ZEROITEMS_SIZE 10000 /**< maximal number of items to store in the zero list in preprocessing */
110
111#define KNAPSACKRELAX_MAXDELTA 0.1 /**< maximal allowed rounding distance for scaling in knapsack relaxation */
112#define KNAPSACKRELAX_MAXDNOM 1000LL /**< maximal allowed denominator in knapsack rational relaxation */
113#define KNAPSACKRELAX_MAXSCALE 1000.0 /**< maximal allowed scaling factor in knapsack rational relaxation */
114
115#define DEFAULT_SEPACARDFREQ 1 /**< multiplier on separation frequency, how often knapsack cuts are separated */
116#define DEFAULT_MAXROUNDS 5 /**< maximal number of separation rounds per node (-1: unlimited) */
117#define DEFAULT_MAXROUNDSROOT -1 /**< maximal number of separation rounds in the root node (-1: unlimited) */
118#define DEFAULT_MAXSEPACUTS 50 /**< maximal number of cuts separated per separation round */
119#define DEFAULT_MAXSEPACUTSROOT 200 /**< maximal number of cuts separated per separation round in the root node */
120#define DEFAULT_MAXCARDBOUNDDIST 0.0 /**< maximal relative distance from current node's dual bound to primal bound compared
121 * to best node's dual bound for separating knapsack cuts */
122#define DEFAULT_DISAGGREGATION TRUE /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
123#define DEFAULT_SIMPLIFYINEQUALITIES TRUE/**< should presolving try to simplify knapsacks */
124#define DEFAULT_NEGATEDCLIQUE TRUE /**< should negated clique information be used in solving process */
125
126#define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds used for knapsack relaxation */
127#define USESUPADDLIFT FALSE /**< should lifted minimal cover inequalities using superadditive up-lifting be separated in addition */
128
129#define DEFAULT_PRESOLUSEHASHING TRUE /**< should hash table be used for detecting redundant constraints in advance */
130#define HASHSIZE_KNAPSACKCONS 500 /**< minimal size of hash table in linear constraint tables */
131
132#define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
133#define NMINCOMPARISONS 200000 /**< number for minimal pairwise presolving comparisons */
134#define MINGAINPERNMINCOMPARISONS 1e-06 /**< minimal gain per minimal pairwise presolving comparisons to repeat pairwise
135 * comparison round */
136#define DEFAULT_DUALPRESOLVING TRUE /**< should dual presolving steps be performed? */
137#define DEFAULT_DETECTCUTOFFBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
138 * function defining an upper bound and prevent these constraints from
139 * entering the LP */
140#define DEFAULT_DETECTLOWERBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
141 * function defining a lower bound and prevent these constraints from
142 * entering the LP */
143#define DEFAULT_CLIQUEEXTRACTFACTOR 0.5 /**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
144#define MAXCOVERSIZEITERLEWI 1000 /**< maximal size for which LEWI are iteratively separated by reducing the feasible set */
145
146#define DEFAULT_USEGUBS FALSE /**< should GUB information be used for separation? */
147#define GUBCONSGROWVALUE 6 /**< memory growing value for GUB constraint array */
148#define GUBSPLITGNC1GUBS FALSE /**< should GNC1 GUB conss without F vars be split into GOC1 and GR GUB conss? */
149#define DEFAULT_CLQPARTUPDATEFAC 1.5 /**< factor on the growth of global cliques to decide when to update a previous
150 * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
151#define DEFAULT_UPDATECLIQUEPARTITIONS FALSE /**< should clique partition information be updated when old partition seems outdated? */
152#define MAXNCLIQUEVARSCOMP 1000000 /**< limit on number of pairwise comparisons in clique partitioning algorithm */
153#ifdef WITH_CARDINALITY_UPGRADE
154#define DEFAULT_UPGDCARDINALITY FALSE /**< if TRUE then try to update knapsack constraints to cardinality constraints */
155#endif
156
157/* @todo maybe use event SCIP_EVENTTYPE_VARUNLOCKED to decide for another dual-presolving run on a constraint */
158
159/*
160 * Data structures
161 */
162
163/** constraint handler data */
164struct SCIP_ConshdlrData
165{
166 int* ints1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
167 * you have to clear it at the end, exists only in presolving stage */
168 int* ints2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
169 * you have to clear it at the end, exists only in presolving stage */
170 SCIP_Longint* longints1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
171 * you have to clear it at the end, exists only in presolving stage */
172 SCIP_Longint* longints2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
173 * you have to clear it at the end, exists only in presolving stage */
174 SCIP_Bool* bools1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
175 * you have to clear it at the end, exists only in presolving stage */
176 SCIP_Bool* bools2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
177 * you have to clear it at the end, exists only in presolving stage */
178 SCIP_Bool* bools3; /**< cleared memory array, all entries are set to zero in initpre, if you use this
179 * you have to clear it at the end, exists only in presolving stage */
180 SCIP_Bool* bools4; /**< cleared memory array, all entries are set to zero in initpre, if you use this
181 * you have to clear it at the end, exists only in presolving stage */
182 SCIP_Real* reals1; /**< cleared memory array, all entries are set to zero in consinit, if you use this
183 * you have to clear it at the end */
184 int ints1size; /**< size of ints1 array */
185 int ints2size; /**< size of ints2 array */
186 int longints1size; /**< size of longints1 array */
187 int longints2size; /**< size of longints2 array */
188 int bools1size; /**< size of bools1 array */
189 int bools2size; /**< size of bools2 array */
190 int bools3size; /**< size of bools3 array */
191 int bools4size; /**< size of bools4 array */
192 int reals1size; /**< size of reals1 array */
193 int* probtoidxmap; /**< cleared memory array with default values -1; used for clique partitions */
194 int probtoidxmapsize; /**< size of probtoidxmap */
195 SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
196 SCIP_Real maxcardbounddist; /**< maximal relative distance from current node's dual bound to primal bound compared
197 * to best node's dual bound for separating knapsack cuts */
198 int sepacardfreq; /**< multiplier on separation frequency, how often knapsack cuts are separated */
199 int maxrounds; /**< maximal number of separation rounds per node (-1: unlimited) */
200 int maxroundsroot; /**< maximal number of separation rounds in the root node (-1: unlimited) */
201 int maxsepacuts; /**< maximal number of cuts separated per separation round */
202 int maxsepacutsroot; /**< maximal number of cuts separated per separation round in the root node */
203 SCIP_Bool disaggregation; /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
204 SCIP_Bool simplifyinequalities;/**< should presolving try to cancel down or delete coefficients in inequalities */
205 SCIP_Bool negatedclique; /**< should negated clique information be used in solving process */
206 SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
207 SCIP_Bool presolusehashing; /**< should hash table be used for detecting redundant constraints in advance */
208 SCIP_Bool dualpresolving; /**< should dual presolving steps be performed? */
209 SCIP_Bool usegubs; /**< should GUB information be used for separation? */
210 SCIP_Bool detectcutoffbound; /**< should presolving try to detect constraints parallel to the objective
211 * function defining an upper bound and prevent these constraints from
212 * entering the LP */
213 SCIP_Bool detectlowerbound; /**< should presolving try to detect constraints parallel to the objective
214 * function defining a lower bound and prevent these constraints from
215 * entering the LP */
216 SCIP_Bool updatecliquepartitions; /**< should clique partition information be updated when old partition seems outdated? */
217 SCIP_Real cliqueextractfactor;/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
218 SCIP_Real clqpartupdatefac; /**< factor on the growth of global cliques to decide when to update a previous
219 * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
220#ifdef WITH_CARDINALITY_UPGRADE
221 SCIP_Bool upgdcardinality; /**< if TRUE then try to update knapsack constraints to cardinality constraints */
222 SCIP_Bool upgradedcard; /**< whether we have already upgraded knapsack constraints to cardinality constraints */
223#endif
224};
225
226
227/** constraint data for knapsack constraints */
228struct SCIP_ConsData
229{
230 SCIP_VAR** vars; /**< variables in knapsack constraint */
231 SCIP_Longint* weights; /**< weights of variables in knapsack constraint */
232 SCIP_EVENTDATA** eventdata; /**< event data for bound change events of the variables */
233 int* cliquepartition; /**< clique indices of the clique partition */
234 int* negcliquepartition; /**< clique indices of the negated clique partition */
235 SCIP_ROW* row; /**< corresponding LP row */
236 SCIP_NLROW* nlrow; /**< corresponding NLP row */
237 int nvars; /**< number of variables in knapsack constraint */
238 int varssize; /**< size of vars, weights, and eventdata arrays */
239 int ncliques; /**< number of cliques in the clique partition */
240 int nnegcliques; /**< number of cliques in the negated clique partition */
241 int ncliqueslastnegpart;/**< number of global cliques the last time a negated clique partition was computed */
242 int ncliqueslastpart; /**< number of global cliques the last time a clique partition was computed */
243 SCIP_Longint capacity; /**< capacity of knapsack */
244 SCIP_Longint weightsum; /**< sum of all weights */
245 SCIP_Longint onesweightsum; /**< sum of weights of variables fixed to one */
246 unsigned int presolvedtiming:5; /**< max level in which the knapsack constraint is already presolved */
247 unsigned int sorted:1; /**< are the knapsack items sorted by weight? */
248 unsigned int cliquepartitioned:1;/**< is the clique partition valid? */
249 unsigned int negcliquepartitioned:1;/**< is the negated clique partition valid? */
250 unsigned int merged:1; /**< are the constraint's equal variables already merged? */
251 unsigned int cliquesadded:1; /**< were the cliques of the knapsack already added to clique table? */
252 unsigned int varsdeleted:1; /**< were variables deleted after last cleanup? */
253 unsigned int existmultaggr:1; /**< does this constraint contain multi-aggregations */
254};
255
256/** event data for bound changes events */
257struct SCIP_EventData
258{
259 SCIP_CONS* cons; /**< knapsack constraint to process the bound change for */
260 SCIP_Longint weight; /**< weight of variable */
261 int filterpos; /**< position of event in variable's event filter */
262};
263
264
265/** data structure to combine two sorting key values */
266struct sortkeypair
267{
268 SCIP_Real key1; /**< first sort key value */
269 SCIP_Real key2; /**< second sort key value */
270};
271typedef struct sortkeypair SORTKEYPAIR;
272
273/** status of GUB constraint */
275{
276 GUBVARSTATUS_UNINITIAL = -1, /** unintitialized variable status */
277 GUBVARSTATUS_CAPACITYEXCEEDED = 0, /** variable with weight exceeding the knapsack capacity */
278 GUBVARSTATUS_BELONGSTOSET_R = 1, /** variable in noncovervars R */
279 GUBVARSTATUS_BELONGSTOSET_F = 2, /** variable in noncovervars F */
280 GUBVARSTATUS_BELONGSTOSET_C2 = 3, /** variable in covervars C2 */
281 GUBVARSTATUS_BELONGSTOSET_C1 = 4 /** variable in covervars C1 */
284
285/** status of variable in GUB constraint */
287{
288 GUBCONSSTATUS_UNINITIAL = -1, /** unintitialized GUB constraint status */
289 GUBCONSSTATUS_BELONGSTOSET_GR = 0, /** all GUB variables are in noncovervars R */
290 GUBCONSSTATUS_BELONGSTOSET_GF = 1, /** all GUB variables are in noncovervars F (and noncovervars R) */
291 GUBCONSSTATUS_BELONGSTOSET_GC2 = 2, /** all GUB variables are in covervars C2 */
292 GUBCONSSTATUS_BELONGSTOSET_GNC1 = 3, /** some GUB variables are in covervars C1, others in noncovervars R or F */
293 GUBCONSSTATUS_BELONGSTOSET_GOC1 = 4 /** all GUB variables are in covervars C1 */
296
297/** data structure of GUB constraints */
299{
300 int* gubvars; /**< indices of GUB variables in knapsack constraint */
301 GUBVARSTATUS* gubvarsstatus; /**< status of GUB variables */
302 int ngubvars; /**< number of GUB variables */
303 int gubvarssize; /**< size of gubvars array */
304};
306
307/** data structure of a set of GUB constraints */
309{
310 SCIP_GUBCONS** gubconss; /**< GUB constraints in GUB set */
311 GUBCONSSTATUS* gubconsstatus; /**< status of GUB constraints */
312 int ngubconss; /**< number of GUB constraints */
313 int nvars; /**< number of variables in knapsack constraint */
314 int* gubconssidx; /**< index of GUB constraint (in gubconss array) of each knapsack variable */
315 int* gubvarsidx; /**< index in GUB constraint (in gubvars array) of each knapsack variable */
316};
318
319/*
320 * Local methods
321 */
322
323/** comparison method for two sorting key pairs */
324static
325SCIP_DECL_SORTPTRCOMP(compSortkeypairs)
326{
327 SORTKEYPAIR* sortkeypair1 = (SORTKEYPAIR*)elem1;
328 SORTKEYPAIR* sortkeypair2 = (SORTKEYPAIR*)elem2;
329
330 if( sortkeypair1->key1 < sortkeypair2->key1 )
331 return -1;
332 else if( sortkeypair1->key1 > sortkeypair2->key1 )
333 return +1;
334 else if( sortkeypair1->key2 < sortkeypair2->key2 )
335 return -1;
336 else if( sortkeypair1->key2 > sortkeypair2->key2 )
337 return +1;
338 else
339 return 0;
340}
341
342/** creates event data */
343static
345 SCIP* scip, /**< SCIP data structure */
346 SCIP_EVENTDATA** eventdata, /**< pointer to store event data */
347 SCIP_CONS* cons, /**< constraint */
348 SCIP_Longint weight /**< weight of variable */
349 )
350{
351 assert(eventdata != NULL);
352
353 SCIP_CALL( SCIPallocBlockMemory(scip, eventdata) );
354 (*eventdata)->cons = cons;
355 (*eventdata)->weight = weight;
356
357 return SCIP_OKAY;
358}
359
360/** frees event data */
361static
363 SCIP* scip, /**< SCIP data structure */
364 SCIP_EVENTDATA** eventdata /**< pointer to event data */
365 )
366{
367 assert(eventdata != NULL);
368
369 SCIPfreeBlockMemory(scip, eventdata);
370
371 return SCIP_OKAY;
372}
373
374/** sorts items in knapsack with nonincreasing weights */
375static
377 SCIP_CONSDATA* consdata /**< constraint data */
378 )
379{
380 assert(consdata != NULL);
381 assert(consdata->nvars == 0 || consdata->vars != NULL);
382 assert(consdata->nvars == 0 || consdata->weights != NULL);
383 assert(consdata->nvars == 0 || consdata->eventdata != NULL);
384 assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
385
386 if( !consdata->sorted )
387 {
388 int pos;
389 int lastcliquenum;
390 int v;
391
392 /* sort of five joint arrays of Long/pointer/pointer/ints/ints,
393 * sorted by first array in non-increasing order via sort template */
395 consdata->weights,
396 (void**)consdata->vars,
397 (void**)consdata->eventdata,
398 consdata->cliquepartition,
399 consdata->negcliquepartition,
400 consdata->nvars);
401
402 v = consdata->nvars - 1;
403 /* sort all items with same weight according to their variable index, used for hash value for fast pairwise comparison of all constraints */
404 while( v >= 0 )
405 {
406 int w = v - 1;
407
408 while( w >= 0 && consdata->weights[v] == consdata->weights[w] )
409 --w;
410
411 if( v - w > 1 )
412 {
413 /* sort all corresponding parts of arrays for which the weights are equal by using the variable index */
415 (void**)(&(consdata->vars[w+1])),
416 (void**)(&(consdata->eventdata[w+1])),
417 &(consdata->cliquepartition[w+1]),
418 &(consdata->negcliquepartition[w+1]),
419 SCIPvarComp,
420 v - w);
421 }
422 v = w;
423 }
424
425 /* we need to make sure that our clique numbers of our normal clique will be in increasing order without gaps */
426 if( consdata->cliquepartitioned )
427 {
428 lastcliquenum = 0;
429
430 for( pos = 0; pos < consdata->nvars; ++pos )
431 {
432 /* if the clique number in the normal clique at position pos is greater than the last found clique number the
433 * partition is invalid */
434 if( consdata->cliquepartition[pos] > lastcliquenum )
435 {
436 consdata->cliquepartitioned = FALSE;
437 break;
438 }
439 else if( consdata->cliquepartition[pos] == lastcliquenum )
440 ++lastcliquenum;
441 }
442 }
443 /* we need to make sure that our clique numbers of our negated clique will be in increasing order without gaps */
444 if( consdata->negcliquepartitioned )
445 {
446 lastcliquenum = 0;
447
448 for( pos = 0; pos < consdata->nvars; ++pos )
449 {
450 /* if the clique number in the negated clique at position pos is greater than the last found clique number the
451 * partition is invalid */
452 if( consdata->negcliquepartition[pos] > lastcliquenum )
453 {
454 consdata->negcliquepartitioned = FALSE;
455 break;
456 }
457 else if( consdata->negcliquepartition[pos] == lastcliquenum )
458 ++lastcliquenum;
459 }
460 }
461
462 consdata->sorted = TRUE;
463 }
464#ifndef NDEBUG
465 {
466 /* check if the weight array is sorted in a non-increasing way */
467 int i;
468 for( i = 0; i < consdata->nvars-1; ++i )
469 assert(consdata->weights[i] >= consdata->weights[i+1]);
470 }
471#endif
472}
473
474/** calculates a partition of the variables into cliques */
475static
477 SCIP* scip, /**< SCIP data structure */
478 SCIP_CONSHDLRDATA* conshdlrdata, /**< knapsack constraint handler data */
479 SCIP_CONSDATA* consdata, /**< constraint data */
480 SCIP_Bool normalclique, /**< Should normal cliquepartition be created? */
481 SCIP_Bool negatedclique /**< Should negated cliquepartition be created? */
482 )
483{
484 SCIP_Bool ispartitionoutdated;
485 SCIP_Bool isnegpartitionoutdated;
486 assert(consdata != NULL);
487 assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
488
489 /* rerun eventually if number of global cliques increased considerably since last partition */
490 ispartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->ncliques > 1
491 && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastpart));
492
493 if( normalclique && ( !consdata->cliquepartitioned || ispartitionoutdated ) )
494 {
495 SCIP_CALL( SCIPcalcCliquePartition(scip, consdata->vars, consdata->nvars, &conshdlrdata->probtoidxmap, &conshdlrdata->probtoidxmapsize,
496 consdata->cliquepartition, &consdata->ncliques) );
497 consdata->cliquepartitioned = TRUE;
498 consdata->ncliqueslastpart = SCIPgetNCliques(scip);
499 }
500
501 /* rerun eventually if number of global cliques increased considerably since last negated partition */
502 isnegpartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->nnegcliques > 1
503 && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastnegpart));
504
505 if( negatedclique && (!consdata->negcliquepartitioned || isnegpartitionoutdated) )
506 {
507 SCIP_CALL( SCIPcalcNegatedCliquePartition(scip, consdata->vars, consdata->nvars, &conshdlrdata->probtoidxmap, &conshdlrdata->probtoidxmapsize,
508 consdata->negcliquepartition, &consdata->nnegcliques) );
509 consdata->negcliquepartitioned = TRUE;
510 consdata->ncliqueslastnegpart = SCIPgetNCliques(scip);
511 }
512 assert(!consdata->cliquepartitioned || consdata->ncliques <= consdata->nvars);
513 assert(!consdata->negcliquepartitioned || consdata->nnegcliques <= consdata->nvars);
514
515 return SCIP_OKAY;
516}
517
518/** installs rounding locks for the given variable in the given knapsack constraint */
519static
521 SCIP* scip, /**< SCIP data structure */
522 SCIP_CONS* cons, /**< knapsack constraint */
523 SCIP_VAR* var /**< variable of constraint entry */
524 )
525{
526 SCIP_CALL( SCIPlockVarCons(scip, var, cons, FALSE, TRUE) );
527
528 return SCIP_OKAY;
529}
530
531/** removes rounding locks for the given variable in the given knapsack constraint */
532static
534 SCIP* scip, /**< SCIP data structure */
535 SCIP_CONS* cons, /**< knapsack constraint */
536 SCIP_VAR* var /**< variable of constraint entry */
537 )
538{
539 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
540
541 return SCIP_OKAY;
542}
543
544/** catches bound change events for variables in knapsack */
545static
547 SCIP* scip, /**< SCIP data structure */
548 SCIP_CONS* cons, /**< constraint */
549 SCIP_CONSDATA* consdata, /**< constraint data */
550 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
551 )
552{
553 int i;
554
555 assert(cons != NULL);
556 assert(consdata != NULL);
557 assert(consdata->nvars == 0 || consdata->vars != NULL);
558 assert(consdata->nvars == 0 || consdata->weights != NULL);
559 assert(consdata->nvars == 0 || consdata->eventdata != NULL);
560
561 for( i = 0; i < consdata->nvars; i++)
562 {
563 SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[i], cons, consdata->weights[i]) );
565 eventhdlr, consdata->eventdata[i], &consdata->eventdata[i]->filterpos) );
566 }
567
568 return SCIP_OKAY;
569}
570
571/** drops bound change events for variables in knapsack */
572static
574 SCIP* scip, /**< SCIP data structure */
575 SCIP_CONSDATA* consdata, /**< constraint data */
576 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
577 )
578{
579 int i;
580
581 assert(consdata != NULL);
582 assert(consdata->nvars == 0 || consdata->vars != NULL);
583 assert(consdata->nvars == 0 || consdata->weights != NULL);
584 assert(consdata->nvars == 0 || consdata->eventdata != NULL);
585
586 for( i = 0; i < consdata->nvars; i++)
587 {
589 eventhdlr, consdata->eventdata[i], consdata->eventdata[i]->filterpos) );
590 SCIP_CALL( eventdataFree(scip, &consdata->eventdata[i]) );
591 }
592
593 return SCIP_OKAY;
594}
595
596/** ensures, that vars and vals arrays can store at least num entries */
597static
599 SCIP* scip, /**< SCIP data structure */
600 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
601 int num, /**< minimum number of entries to store */
602 SCIP_Bool transformed /**< is constraint from transformed problem? */
603 )
604{
605 assert(consdata != NULL);
606 assert(consdata->nvars <= consdata->varssize);
607
608 if( num > consdata->varssize )
609 {
610 int newsize;
611
612 newsize = SCIPcalcMemGrowSize(scip, num);
613 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) );
614 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->weights, consdata->varssize, newsize) );
615 if( transformed )
616 {
617 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->eventdata, consdata->varssize, newsize) );
618 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->cliquepartition, consdata->varssize, newsize) );
619 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->negcliquepartition, consdata->varssize, newsize) );
620 }
621 else
622 {
623 assert(consdata->eventdata == NULL);
624 assert(consdata->cliquepartition == NULL);
625 assert(consdata->negcliquepartition == NULL);
626 }
627 consdata->varssize = newsize;
628 }
629 assert(num <= consdata->varssize);
630
631 return SCIP_OKAY;
632}
633
634/** updates all weight sums for fixed and unfixed variables */
635static
637 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
638 SCIP_VAR* var, /**< variable for this weight */
639 SCIP_Longint weightdelta /**< difference between the old and the new weight of the variable */
640 )
641{
642 assert(consdata != NULL);
643 assert(var != NULL);
644
645 consdata->weightsum += weightdelta;
646
647 if( SCIPvarGetLbLocal(var) > 0.5 )
648 consdata->onesweightsum += weightdelta;
649
650 assert(consdata->weightsum >= 0);
651 assert(consdata->onesweightsum >= 0);
652}
653
654/** creates knapsack constraint data */
655static
657 SCIP* scip, /**< SCIP data structure */
658 SCIP_CONSDATA** consdata, /**< pointer to store constraint data */
659 int nvars, /**< number of variables in knapsack */
660 SCIP_VAR** vars, /**< variables of knapsack */
661 SCIP_Longint* weights, /**< weights of knapsack items */
662 SCIP_Longint capacity /**< capacity of knapsack */
663 )
664{
665 int v;
666 SCIP_Longint constant;
667
668 assert(consdata != NULL);
669
670 SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
671
672 constant = 0L;
673 (*consdata)->vars = NULL;
674 (*consdata)->weights = NULL;
675 (*consdata)->nvars = 0;
676 if( nvars > 0 )
677 {
678 SCIP_VAR** varsbuffer;
679 SCIP_Longint* weightsbuffer;
680 int k;
681
682 SCIP_CALL( SCIPallocBufferArray(scip, &varsbuffer, nvars) );
683 SCIP_CALL( SCIPallocBufferArray(scip, &weightsbuffer, nvars) );
684
685 k = 0;
686 for( v = 0; v < nvars; ++v )
687 {
688 assert(vars[v] != NULL);
689 assert(SCIPvarIsBinary(vars[v]));
690
691 /* all weight have to be non negative */
692 assert( weights[v] >= 0 );
693
694 if( weights[v] > 0 )
695 {
696 /* treat fixed variables as constants if problem compression is enabled */
698 {
699 /* only if the variable is fixed to 1, we add its weight to the constant */
700 if( SCIPvarGetUbGlobal(vars[v]) > 0.5 )
701 constant += weights[v];
702 }
703 else
704 {
705 varsbuffer[k] = vars[v];
706 weightsbuffer[k] = weights[v];
707 ++k;
708 }
709 }
710 }
711 assert(k >= 0);
712 assert(constant >= 0);
713
714 (*consdata)->nvars = k;
715
716 /* copy the active variables and weights into the constraint data structure */
717 if( k > 0 )
718 {
719 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, varsbuffer, k) );
720 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->weights, weightsbuffer, k) );
721 }
722
723 /* free buffer storage */
724 SCIPfreeBufferArray(scip, &weightsbuffer);
725 SCIPfreeBufferArray(scip, &varsbuffer);
726 }
727
728 (*consdata)->varssize = (*consdata)->nvars;
729 (*consdata)->capacity = capacity - constant;
730 (*consdata)->eventdata = NULL;
731 (*consdata)->cliquepartition = NULL;
732 (*consdata)->negcliquepartition = NULL;
733 (*consdata)->row = NULL;
734 (*consdata)->nlrow = NULL;
735 (*consdata)->weightsum = 0;
736 (*consdata)->onesweightsum = 0;
737 (*consdata)->ncliques = 0;
738 (*consdata)->nnegcliques = 0;
739 (*consdata)->presolvedtiming = 0;
740 (*consdata)->sorted = FALSE;
741 (*consdata)->cliquepartitioned = FALSE;
742 (*consdata)->negcliquepartitioned = FALSE;
743 (*consdata)->ncliqueslastpart = -1;
744 (*consdata)->ncliqueslastnegpart = -1;
745 (*consdata)->merged = FALSE;
746 (*consdata)->cliquesadded = FALSE;
747 (*consdata)->varsdeleted = FALSE;
748 (*consdata)->existmultaggr = FALSE;
749
750 /* get transformed variables, if we are in the transformed problem */
752 {
753 SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
754
755 for( v = 0; v < (*consdata)->nvars; v++ )
756 {
757 SCIP_VAR* var = SCIPvarGetProbvar((*consdata)->vars[v]);
758 assert(var != NULL);
759 (*consdata)->existmultaggr = (*consdata)->existmultaggr || (SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
760 }
761
762 /* allocate memory for additional data structures */
763 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->nvars) );
764 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->nvars) );
765 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->nvars) );
766 }
767
768 /* calculate sum of weights and capture variables */
769 for( v = 0; v < (*consdata)->nvars; ++v )
770 {
771 /* calculate sum of weights */
772 updateWeightSums(*consdata, (*consdata)->vars[v], (*consdata)->weights[v]);
773
774 /* capture variables */
775 SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) );
776 }
777 return SCIP_OKAY;
778}
779
780/** frees knapsack constraint data */
781static
783 SCIP* scip, /**< SCIP data structure */
784 SCIP_CONSDATA** consdata, /**< pointer to the constraint data */
785 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
786 )
787{
788 assert(consdata != NULL);
789 assert(*consdata != NULL);
790
791 if( (*consdata)->row != NULL )
792 {
793 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->row) );
794 }
795 if( (*consdata)->nlrow != NULL )
796 {
797 SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
798 }
799 if( (*consdata)->eventdata != NULL )
800 {
801 SCIP_CALL( dropEvents(scip, *consdata, eventhdlr) );
802 SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->varssize);
803 }
804 if( (*consdata)->negcliquepartition != NULL )
805 {
806 SCIPfreeBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->varssize);
807 }
808 if( (*consdata)->cliquepartition != NULL )
809 {
810 SCIPfreeBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->varssize);
811 }
812 if( (*consdata)->vars != NULL )
813 {
814 int v;
815
816 /* release variables */
817 for( v = 0; v < (*consdata)->nvars; v++ )
818 {
819 assert((*consdata)->vars[v] != NULL);
820 SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->vars[v])) );
821 }
822
823 assert( (*consdata)->weights != NULL );
824 assert( (*consdata)->varssize > 0 );
825 SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->varssize);
826 SCIPfreeBlockMemoryArray(scip, &(*consdata)->weights, (*consdata)->varssize);
827 }
828
829 SCIPfreeBlockMemory(scip, consdata);
830
831 return SCIP_OKAY;
832}
833
834/** changes a single weight in knapsack constraint data */
835static
837 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
838 int item, /**< item number */
839 SCIP_Longint newweight /**< new weight of item */
840 )
841{
842 SCIP_Longint oldweight;
843 SCIP_Longint weightdiff;
844
845 assert(consdata != NULL);
846 assert(0 <= item && item < consdata->nvars);
847
848 oldweight = consdata->weights[item];
849 weightdiff = newweight - oldweight;
850 consdata->weights[item] = newweight;
851
852 /* update weight sums for all and fixed variables */
853 updateWeightSums(consdata, consdata->vars[item], weightdiff);
854
855 if( consdata->eventdata != NULL )
856 {
857 assert(consdata->eventdata[item] != NULL);
858 assert(consdata->eventdata[item]->weight == oldweight);
859 consdata->eventdata[item]->weight = newweight;
860 }
861
862 consdata->presolvedtiming = 0;
863 consdata->sorted = FALSE;
864
865 /* recalculate cliques extraction after a weight was increased */
866 if( oldweight < newweight )
867 {
868 consdata->cliquesadded = FALSE;
869 }
870}
871
872/** creates LP row corresponding to knapsack constraint */
873static
875 SCIP* scip, /**< SCIP data structure */
876 SCIP_CONS* cons /**< knapsack constraint */
877 )
878{
879 SCIP_CONSDATA* consdata;
880 int i;
881
882 consdata = SCIPconsGetData(cons);
883 assert(consdata != NULL);
884 assert(consdata->row == NULL);
885
886 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, cons, SCIPconsGetName(cons),
887 -SCIPinfinity(scip), (SCIP_Real)consdata->capacity,
889
890 SCIP_CALL( SCIPcacheRowExtensions(scip, consdata->row) );
891 for( i = 0; i < consdata->nvars; ++i )
892 {
893 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, consdata->vars[i], (SCIP_Real)consdata->weights[i]) );
894 }
895 SCIP_CALL( SCIPflushRowExtensions(scip, consdata->row) );
896
897 return SCIP_OKAY;
898}
899
900/** adds linear relaxation of knapsack constraint to the LP */
901static
903 SCIP* scip, /**< SCIP data structure */
904 SCIP_CONS* cons, /**< knapsack constraint */
905 SCIP_Bool* cutoff /**< whether a cutoff has been detected */
906 )
907{
908 SCIP_CONSDATA* consdata;
909
910 assert( cutoff != NULL );
911 *cutoff = FALSE;
912
913 consdata = SCIPconsGetData(cons);
914 assert(consdata != NULL);
915
916 if( consdata->row == NULL )
917 {
919 }
920 assert(consdata->row != NULL);
921
922 /* insert LP row as cut */
923 if( !SCIProwIsInLP(consdata->row) )
924 {
925 SCIPdebugMsg(scip, "adding relaxation of knapsack constraint <%s> (capacity %" SCIP_LONGINT_FORMAT "): ",
926 SCIPconsGetName(cons), consdata->capacity);
927 SCIPdebug( SCIP_CALL( SCIPprintRow(scip, consdata->row, NULL) ) );
928 SCIP_CALL( SCIPaddRow(scip, consdata->row, FALSE, cutoff) );
929 }
930
931 return SCIP_OKAY;
932}
933
934/** adds knapsack constraint as row to the NLP, if not added yet */
935static
937 SCIP* scip, /**< SCIP data structure */
938 SCIP_CONS* cons /**< knapsack constraint */
939 )
940{
941 SCIP_CONSDATA* consdata;
942
943 assert(SCIPisNLPConstructed(scip));
944
945 /* skip deactivated, redundant, or local linear constraints (the NLP does not allow for local rows at the moment) */
946 if( !SCIPconsIsActive(cons) || !SCIPconsIsChecked(cons) || SCIPconsIsLocal(cons) )
947 return SCIP_OKAY;
948
949 consdata = SCIPconsGetData(cons);
950 assert(consdata != NULL);
951
952 if( consdata->nlrow == NULL )
953 {
954 SCIP_Real* coefs;
955 int i;
956
957 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, consdata->nvars) );
958 for( i = 0; i < consdata->nvars; ++i )
959 coefs[i] = (SCIP_Real)consdata->weights[i]; /*lint !e613*/
960
961 SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
962 consdata->nvars, consdata->vars, coefs, NULL,
963 -SCIPinfinity(scip), (SCIP_Real)consdata->capacity, SCIP_EXPRCURV_LINEAR) );
964
965 assert(consdata->nlrow != NULL);
966
967 SCIPfreeBufferArray(scip, &coefs);
968 }
969
970 if( !SCIPnlrowIsInNLP(consdata->nlrow) )
971 {
972 SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
973 }
974
975 return SCIP_OKAY;
976}
977
978/** checks knapsack constraint for feasibility of given solution: returns TRUE iff constraint is feasible */
979static
981 SCIP* scip, /**< SCIP data structure */
982 SCIP_CONS* cons, /**< constraint to check */
983 SCIP_SOL* sol, /**< solution to check, NULL for current solution */
984 SCIP_Bool checklprows, /**< Do constraints represented by rows in the current LP have to be checked? */
985 SCIP_Bool printreason, /**< Should the reason for the violation be printed? */
986 SCIP_Bool* violated /**< pointer to store whether the constraint is violated */
987 )
988{
989 SCIP_CONSDATA* consdata;
990
991 assert(violated != NULL);
992
993 consdata = SCIPconsGetData(cons);
994 assert(consdata != NULL);
995
996 SCIPdebugMsg(scip, "checking knapsack constraint <%s> for feasibility of solution %p (lprows=%u)\n",
997 SCIPconsGetName(cons), (void*)sol, checklprows);
998
999 *violated = FALSE;
1000
1001 if( checklprows || consdata->row == NULL || !SCIProwIsInLP(consdata->row) )
1002 {
1003 SCIP_Real normsum = 0.0;
1004 SCIP_Real hugesum = 0.0;
1005 SCIP_Real absviol;
1006 SCIP_Real relviol;
1007 int v;
1008
1009 /* increase age of constraint; age is reset to zero, if a violation was found only in case we are in
1010 * enforcement
1011 */
1012 if( sol == NULL )
1013 {
1014 SCIP_CALL( SCIPincConsAge(scip, cons) );
1015 }
1016
1017 /* sum separately over normal and huge weight contributions in order to reduce numerical cancellation */
1018 for( v = consdata->nvars - 1; v >= 0; --v )
1019 {
1020 assert(SCIPvarIsBinary(consdata->vars[v]));
1021
1022 if( SCIPisHugeValue(scip, (SCIP_Real)consdata->weights[v]) )
1023 hugesum += consdata->weights[v] * SCIPgetSolVal(scip, sol, consdata->vars[v]);
1024 else
1025 normsum += consdata->weights[v] * SCIPgetSolVal(scip, sol, consdata->vars[v]);
1026 }
1027
1028 /* calculate constraint violation and update it in solution */
1029 normsum += hugesum;
1030
1031 if( normsum > consdata->capacity )
1032 {
1033 absviol = normsum - consdata->capacity;
1034 relviol = SCIPrelDiff(normsum, (SCIP_Real)consdata->capacity);
1035 }
1036 else
1037 {
1038 absviol = 0.0;
1039 relviol = 0.0;
1040 }
1041
1042 if( sol != NULL )
1043 SCIPupdateSolLPConsViolation(scip, sol, absviol, relviol);
1044
1045 if( SCIPisFeasPositive(scip, absviol) )
1046 {
1047 *violated = TRUE;
1048
1049 /* only reset constraint age if we are in enforcement */
1050 if( sol == NULL )
1051 {
1053 }
1054
1055 if( printreason )
1056 {
1057 SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
1058
1059 SCIPinfoMessage(scip, NULL, ";\n");
1060 SCIPinfoMessage(scip, NULL, "violation: the capacity is violated by %.15g\n", absviol);
1061 }
1062 }
1063 }
1064
1065 return SCIP_OKAY;
1066}
1067
1068/* IDX computes the integer index for the optimal solution array */
1069#define IDX(j,d) ((j)*(intcap)+(d))
1070
1071/** solves knapsack problem in maximization form exactly using dynamic programming;
1072 * if needed, one can provide arrays to store all selected items and all not selected items
1073 *
1074 * @note in case you provide the solitems or nonsolitems array you also have to provide the counter part, as well
1075 *
1076 * @note the algorithm will first compute a greedy solution and terminate
1077 * if the greedy solution is proven to be optimal.
1078 * The dynamic programming algorithm runs with a time and space complexity
1079 * of O(nitems * capacity).
1080 *
1081 * @todo If only the objective is relevant, it is easy to change the code to use only one slice with O(capacity) space.
1082 * There are recursive methods (see the book by Kellerer et al.) that require O(capacity) space, but it remains
1083 * to be checked whether they are faster and whether they can reconstruct the solution.
1084 * Dembo and Hammer (see Kellerer et al. Section 5.1.3, page 126) found a method that relies on a fast probing method.
1085 * This fixes additional elements to 0 or 1 similar to a reduced cost fixing.
1086 * This could be implemented, however, it would be technically a bit cumbersome,
1087 * since one needs the greedy solution and the LP-value for this.
1088 * This is currently only available after the redundant items have already been sorted out.
1089 */
1091 SCIP* scip, /**< SCIP data structure */
1092 int nitems, /**< number of available items */
1093 SCIP_Longint* weights, /**< item weights */
1094 SCIP_Real* profits, /**< item profits */
1095 SCIP_Longint capacity, /**< capacity of knapsack */
1096 int* items, /**< item numbers */
1097 int* solitems, /**< array to store items in solution, or NULL */
1098 int* nonsolitems, /**< array to store items not in solution, or NULL */
1099 int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1100 int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1101 SCIP_Real* solval, /**< pointer to store optimal solution value, or NULL */
1102 SCIP_Bool* success /**< pointer to store if an error occured during solving
1103 * (normally a memory problem) */
1104 )
1105{
1106 SCIP_RETCODE retcode;
1107 SCIP_Real* tempsort;
1108 SCIP_Real* optvalues;
1109 int intcap;
1110 int d;
1111 int j;
1112 int greedymedianpos;
1113 SCIP_Longint weightsum;
1114 int* myitems;
1115 SCIP_Longint* myweights;
1116 SCIP_Real* realweights;
1117 int* allcurrminweight;
1118 SCIP_Real* myprofits;
1119 int nmyitems;
1120 SCIP_Longint gcd;
1121 SCIP_Longint minweight;
1122 SCIP_Longint maxweight;
1123 int currminweight;
1124 SCIP_Longint greedysolweight;
1125 SCIP_Real greedysolvalue;
1126 SCIP_Real greedyupperbound;
1127 SCIP_Bool eqweights;
1128 SCIP_Bool intprofits;
1129
1130 assert(weights != NULL);
1131 assert(profits != NULL);
1132 assert(capacity >= 0);
1133 assert(items != NULL);
1134 assert(nitems >= 0);
1135 assert(success != NULL);
1136
1137 *success = TRUE;
1138
1139#ifndef NDEBUG
1140 for( j = nitems - 1; j >= 0; --j )
1141 assert(weights[j] >= 0);
1142#endif
1143
1144 SCIPdebugMsg(scip, "Solving knapsack exactly.\n");
1145
1146 /* initializing solution value */
1147 if( solval != NULL )
1148 *solval = 0.0;
1149
1150 /* init solution information */
1151 if( solitems != NULL )
1152 {
1153 assert(items != NULL);
1154 assert(nsolitems != NULL);
1155 assert(nonsolitems != NULL);
1156 assert(nnonsolitems != NULL);
1157
1158 *nnonsolitems = 0;
1159 *nsolitems = 0;
1160 }
1161
1162 /* allocate temporary memory */
1163 SCIP_CALL( SCIPallocBufferArray(scip, &myweights, nitems) );
1164 SCIP_CALL( SCIPallocBufferArray(scip, &myprofits, nitems) );
1165 SCIP_CALL( SCIPallocBufferArray(scip, &myitems, nitems) );
1166 nmyitems = 0;
1167 weightsum = 0;
1168 minweight = SCIP_LONGINT_MAX;
1169 maxweight = 0;
1170
1171 /* remove unnecessary items */
1172 for( j = 0; j < nitems; ++j )
1173 {
1174 assert(0 <= weights[j] && weights[j] < SCIP_LONGINT_MAX);
1175
1176 /* item does not fit */
1177 if( weights[j] > capacity )
1178 {
1179 if( solitems != NULL )
1180 nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
1181 }
1182 /* item is not profitable */
1183 else if( profits[j] <= 0.0 )
1184 {
1185 if( solitems != NULL )
1186 nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
1187 }
1188 /* item always fits */
1189 else if( weights[j] == 0 )
1190 {
1191 if( solitems != NULL )
1192 solitems[(*nsolitems)++] = items[j]; /*lint !e413*/
1193
1194 if( solval != NULL )
1195 *solval += profits[j];
1196 }
1197 /* all important items */
1198 else
1199 {
1200 myweights[nmyitems] = weights[j];
1201 myprofits[nmyitems] = profits[j];
1202 myitems[nmyitems] = items[j];
1203
1204 /* remember smallest item */
1205 if( myweights[nmyitems] < minweight )
1206 minweight = myweights[nmyitems];
1207
1208 /* remember bigest item */
1209 if( myweights[nmyitems] > maxweight )
1210 maxweight = myweights[nmyitems];
1211
1212 weightsum += myweights[nmyitems];
1213 ++nmyitems;
1214 }
1215 }
1216
1217 intprofits = TRUE;
1218 /* check if all profits are integer to strengthen the upper bound on the greedy solution */
1219 for( j = 0; j < nmyitems && intprofits; ++j )
1220 intprofits = intprofits && SCIPisIntegral(scip, myprofits[j]);
1221
1222 /* if no item is left then goto end */
1223 if( nmyitems == 0 )
1224 {
1225 SCIPdebugMsg(scip, "After preprocessing no items are left.\n");
1226
1227 goto TERMINATE;
1228 }
1229
1230 /* if all items fit, we also do not need to do the expensive stuff later on */
1231 if( weightsum > 0 && weightsum <= capacity )
1232 {
1233 SCIPdebugMsg(scip, "After preprocessing all items fit into knapsack.\n");
1234
1235 for( j = nmyitems - 1; j >= 0; --j )
1236 {
1237 if( solitems != NULL )
1238 solitems[(*nsolitems)++] = myitems[j]; /*lint !e413*/
1239
1240 if( solval != NULL )
1241 *solval += myprofits[j];
1242 }
1243
1244 goto TERMINATE;
1245 }
1246
1247 assert(0 < minweight && minweight <= capacity );
1248 assert(0 < maxweight && maxweight <= capacity);
1249
1250 /* make weights relatively prime */
1251 eqweights = TRUE;
1252 if( maxweight > 1 )
1253 {
1254 /* determine greatest common divisor */
1255 gcd = myweights[nmyitems - 1];
1256 for( j = nmyitems - 2; j >= 0 && gcd >= 2; --j )
1257 gcd = SCIPcalcGreComDiv(gcd, myweights[j]);
1258
1259 SCIPdebugMsg(scip, "Gcd is %" SCIP_LONGINT_FORMAT ".\n", gcd);
1260
1261 /* divide by greatest common divisor */
1262 if( gcd > 1 )
1263 {
1264 for( j = nmyitems - 1; j >= 0; --j )
1265 {
1266 myweights[j] /= gcd;
1267 eqweights = eqweights && (myweights[j] == 1);
1268 }
1269 capacity /= gcd;
1270 minweight /= gcd;
1271 }
1272 else
1273 eqweights = FALSE;
1274 }
1275 assert(minweight <= capacity);
1276
1277 /* if only one item fits, then take the best */
1278 if( minweight > capacity / 2 )
1279 {
1280 int p;
1281
1282 SCIPdebugMsg(scip, "Only one item fits into knapsack, so take the best.\n");
1283
1284 p = nmyitems - 1;
1285
1286 /* find best item */
1287 for( j = nmyitems - 2; j >= 0; --j )
1288 {
1289 if( myprofits[j] > myprofits[p] )
1290 p = j;
1291 }
1292
1293 /* update solution information */
1294 if( solitems != NULL )
1295 {
1296 assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1297
1298 solitems[(*nsolitems)++] = myitems[p];
1299 for( j = nmyitems - 1; j >= 0; --j )
1300 {
1301 if( j != p )
1302 nonsolitems[(*nnonsolitems)++] = myitems[j];
1303 }
1304 }
1305 /* update solution value */
1306 if( solval != NULL )
1307 *solval += myprofits[p];
1308
1309 goto TERMINATE;
1310 }
1311
1312 /* if all items have the same weight, then take the best */
1313 if( eqweights )
1314 {
1315 SCIP_Real addval = 0.0;
1316
1317 SCIPdebugMsg(scip, "All weights are equal, so take the best.\n");
1318
1319 SCIPsortDownRealIntLong(myprofits, myitems, myweights, nmyitems);
1320
1321 /* update solution information */
1322 if( solitems != NULL || solval != NULL )
1323 {
1324 SCIP_Longint i;
1325
1326 /* if all items would fit we had handled this case before */
1327 assert((SCIP_Longint) nmyitems > capacity);
1328 assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1329
1330 /* take the first best items into the solution */
1331 for( i = capacity - 1; i >= 0; --i )
1332 {
1333 if( solitems != NULL )
1334 solitems[(*nsolitems)++] = myitems[i];
1335 addval += myprofits[i];
1336 }
1337
1338 if( solitems != NULL )
1339 {
1340 /* the rest are not in the solution */
1341 for( i = nmyitems - 1; i >= capacity; --i )
1342 nonsolitems[(*nnonsolitems)++] = myitems[i];
1343 }
1344 }
1345 /* update solution value */
1346 if( solval != NULL )
1347 {
1348 assert(addval > 0.0);
1349 *solval += addval;
1350 }
1351
1352 goto TERMINATE;
1353 }
1354
1355 SCIPdebugMsg(scip, "Determine greedy solution.\n");
1356
1357 /* sort myitems (plus corresponding arrays myweights and myprofits) such that
1358 * p_1/w_1 >= p_2/w_2 >= ... >= p_n/w_n, this is only used for the greedy solution
1359 */
1360 SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nmyitems) );
1361 SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nmyitems) );
1362
1363 for( j = 0; j < nmyitems; ++j )
1364 {
1365 tempsort[j] = myprofits[j]/((SCIP_Real) myweights[j]);
1366 realweights[j] = (SCIP_Real)myweights[j];
1367 }
1368
1369 SCIPselectWeightedDownRealLongRealInt(tempsort, myweights, myprofits, myitems, realweights,
1370 (SCIP_Real)capacity, nmyitems, &greedymedianpos);
1371
1372 SCIPfreeBufferArray(scip, &realweights);
1373 SCIPfreeBufferArray(scip, &tempsort);
1374
1375 /* initialize values for greedy solution information */
1376 greedysolweight = 0;
1377 greedysolvalue = 0.0;
1378
1379 /* determine greedy solution */
1380 for( j = 0; j < greedymedianpos; ++j )
1381 {
1382 assert(myweights[j] <= capacity);
1383
1384 /* update greedy solution weight and value */
1385 greedysolweight += myweights[j];
1386 greedysolvalue += myprofits[j];
1387 }
1388
1389 assert(0 < greedysolweight && greedysolweight <= capacity);
1390 assert(greedysolvalue > 0.0);
1391
1392 /* If the greedy solution is optimal by comparing to the LP solution, we take this solution. This happens if:
1393 * - the greedy solution reaches the capacity, because then the LP solution is integral;
1394 * - the greedy solution has an objective that is at least the LP value rounded down in case that all profits are integer, too. */
1395 greedyupperbound = greedysolvalue + myprofits[j] * (SCIP_Real) (capacity - greedysolweight)/((SCIP_Real) myweights[j]);
1396 if( intprofits )
1397 greedyupperbound = SCIPfloor(scip, greedyupperbound);
1398 if( greedysolweight == capacity || SCIPisGE(scip, greedysolvalue, greedyupperbound) )
1399 {
1400 SCIPdebugMsg(scip, "Greedy solution is optimal.\n");
1401
1402 /* update solution information */
1403 if( solitems != NULL )
1404 {
1405 int l;
1406
1407 assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1408
1409 /* collect items */
1410 for( l = 0; l < j; ++l )
1411 solitems[(*nsolitems)++] = myitems[l];
1412 for ( ; l < nmyitems; ++l )
1413 nonsolitems[(*nnonsolitems)++] = myitems[l];
1414 }
1415 /* update solution value */
1416 if( solval != NULL )
1417 {
1418 assert(greedysolvalue > 0.0);
1419 *solval += greedysolvalue;
1420 }
1421
1422 goto TERMINATE;
1423 }
1424
1425 /* in the following table we do not need the first minweight columns */
1426 capacity -= (minweight - 1);
1427
1428 /* we can only handle integers */
1429 if( capacity >= INT_MAX )
1430 {
1431 SCIPdebugMsg(scip, "Capacity is to big, so we cannot handle it here.\n");
1432
1433 *success = FALSE;
1434 goto TERMINATE;
1435 }
1436 assert(capacity < INT_MAX);
1437
1438 intcap = (int)capacity;
1439 assert(intcap >= 0);
1440 assert(nmyitems > 0);
1441 assert(sizeof(size_t) >= sizeof(int)); /*lint !e506*/ /* no following conversion should be messed up */
1442
1443 /* this condition checks whether we will try to allocate a correct number of bytes and do not have an overflow, while
1444 * computing the size for the allocation
1445 */
1446 if( intcap < 0 || (intcap > 0 && (((size_t)nmyitems) > (SIZE_MAX / (size_t)intcap / sizeof(*optvalues)) || ((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues) > ((size_t)INT_MAX) )) ) /*lint !e571*/
1447 {
1448 SCIPdebugMsg(scip, "Too much memory (%lu) would be consumed.\n", (unsigned long) (((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues))); /*lint !e571*/
1449
1450 *success = FALSE;
1451 goto TERMINATE;
1452 }
1453
1454 /* allocate temporary memory and check for memory exceedance */
1455 retcode = SCIPallocBufferArray(scip, &optvalues, nmyitems * intcap);
1456 if( retcode == SCIP_NOMEMORY )
1457 {
1458 SCIPdebugMsg(scip, "Did not get enough memory.\n");
1459
1460 *success = FALSE;
1461 goto TERMINATE;
1462 }
1463 else
1464 {
1465 SCIP_CALL( retcode );
1466 }
1467
1468 SCIPdebugMsg(scip, "Start real exact algorithm.\n");
1469
1470 /* we memorize at each step the current minimal weight to later on know which value in our optvalues matrix is valid;
1471 * each value entries of the j-th row of optvalues is valid if the index is >= allcurrminweight[j], otherwise it is
1472 * invalid; a second possibility would be to clear the whole optvalues, which should be more expensive than storing
1473 * 'nmyitem' values
1474 */
1475 SCIP_CALL( SCIPallocBufferArray(scip, &allcurrminweight, nmyitems) );
1476 assert(myweights[0] - minweight < INT_MAX);
1477 currminweight = (int) (myweights[0] - minweight);
1478 allcurrminweight[0] = currminweight;
1479
1480 /* fills first row of dynamic programming table with optimal values */
1481 for( d = currminweight; d < intcap; ++d )
1482 optvalues[d] = myprofits[0];
1483
1484 /* fills dynamic programming table with optimal values */
1485 for( j = 1; j < nmyitems; ++j )
1486 {
1487 int intweight;
1488
1489 /* compute important part of weight, which will be represented in the table */
1490 intweight = (int)(myweights[j] - minweight);
1491 assert(0 <= intweight && intweight < intcap);
1492
1493 /* copy all nonzeros from row above */
1494 for( d = currminweight; d < intweight && d < intcap; ++d )
1495 optvalues[IDX(j,d)] = optvalues[IDX(j-1,d)];
1496
1497 /* update corresponding row */
1498 for( d = intweight; d < intcap; ++d )
1499 {
1500 /* if index d < current minweight then optvalues[IDX(j-1,d)] is not initialized, i.e. should be 0 */
1501 if( d < currminweight )
1502 optvalues[IDX(j,d)] = myprofits[j];
1503 else
1504 {
1505 SCIP_Real sumprofit;
1506
1507 if( d - myweights[j] < currminweight )
1508 sumprofit = myprofits[j];
1509 else
1510 sumprofit = optvalues[IDX(j-1,(int)(d-myweights[j]))] + myprofits[j];
1511
1512 optvalues[IDX(j,d)] = MAX(sumprofit, optvalues[IDX(j-1,d)]);
1513 }
1514 }
1515
1516 /* update currminweight */
1517 if( intweight < currminweight )
1518 currminweight = intweight;
1519
1520 allcurrminweight[j] = currminweight;
1521 }
1522
1523 /* update optimal solution by following the table */
1524 if( solitems != NULL )
1525 {
1526 assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1527 d = intcap - 1;
1528
1529 SCIPdebugMsg(scip, "Fill the solution vector after solving exactly.\n");
1530
1531 /* insert all items in (non-) solution vector */
1532 for( j = nmyitems - 1; j > 0; --j )
1533 {
1534 /* if the following condition holds this means all remaining items does not fit anymore */
1535 if( d < allcurrminweight[j] )
1536 {
1537 /* we cannot have exceeded our capacity */
1538 assert((SCIP_Longint) d >= -minweight);
1539 break;
1540 }
1541
1542 /* collect solution items; the first condition means that no further item can fit anymore, but this does */
1543 if( d < allcurrminweight[j-1] || optvalues[IDX(j,d)] > optvalues[IDX(j-1,d)] )
1544 {
1545 solitems[(*nsolitems)++] = myitems[j];
1546
1547 /* check that we do not have an underflow */
1548 assert(myweights[j] <= (INT_MAX + (SCIP_Longint) d));
1549 d = (int)(d - myweights[j]);
1550 }
1551 /* collect non-solution items */
1552 else
1553 nonsolitems[(*nnonsolitems)++] = myitems[j];
1554 }
1555
1556 /* insert remaining items */
1557 if( d >= allcurrminweight[j] )
1558 {
1559 assert(j == 0);
1560 solitems[(*nsolitems)++] = myitems[j];
1561 }
1562 else
1563 {
1564 assert(j >= 0);
1565 assert(d < allcurrminweight[j]);
1566
1567 for( ; j >= 0; --j )
1568 nonsolitems[(*nnonsolitems)++] = myitems[j];
1569 }
1570
1571 assert(*nsolitems + *nnonsolitems == nitems);
1572 }
1573
1574 /* update solution value */
1575 if( solval != NULL )
1576 *solval += optvalues[IDX(nmyitems-1,intcap-1)];
1577 SCIPfreeBufferArray(scip, &allcurrminweight);
1578
1579 /* free all temporary memory */
1580 SCIPfreeBufferArray(scip, &optvalues);
1581
1582 TERMINATE:
1583 SCIPfreeBufferArray(scip, &myitems);
1584 SCIPfreeBufferArray(scip, &myprofits);
1585 SCIPfreeBufferArray(scip, &myweights);
1586
1587 return SCIP_OKAY;
1588}
1589
1590/** solves knapsack problem in maximization form approximately by solving the LP-relaxation of the problem using Dantzig's
1591 * method and rounding down the solution; if needed, one can provide arrays to store all selected items and all not
1592 * selected items
1593 */
1595 SCIP* scip, /**< SCIP data structure */
1596 int nitems, /**< number of available items */
1597 SCIP_Longint* weights, /**< item weights */
1598 SCIP_Real* profits, /**< item profits */
1599 SCIP_Longint capacity, /**< capacity of knapsack */
1600 int* items, /**< item numbers */
1601 int* solitems, /**< array to store items in solution, or NULL */
1602 int* nonsolitems, /**< array to store items not in solution, or NULL */
1603 int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1604 int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1605 SCIP_Real* solval /**< pointer to store optimal solution value, or NULL */
1606 )
1607{
1608 SCIP_Real* tempsort;
1609 SCIP_Longint solitemsweight;
1610 SCIP_Real* realweights;
1611 int j;
1612 int criticalindex;
1613
1614 assert(weights != NULL);
1615 assert(profits != NULL);
1616 assert(capacity >= 0);
1617 assert(items != NULL);
1618 assert(nitems >= 0);
1619
1620 if( solitems != NULL )
1621 {
1622 *nsolitems = 0;
1623 *nnonsolitems = 0;
1624 }
1625 if( solval != NULL )
1626 *solval = 0.0;
1627
1628 /* initialize data for median search */
1629 SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nitems) );
1630 SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nitems) );
1631 for( j = nitems - 1; j >= 0; --j )
1632 {
1633 tempsort[j] = profits[j]/((SCIP_Real) weights[j]);
1634 realweights[j] = (SCIP_Real)weights[j];
1635 }
1636
1637 /* partially sort indices such that all elements that are larger than the break item appear first */
1638 SCIPselectWeightedDownRealLongRealInt(tempsort, weights, profits, items, realweights, (SCIP_Real)capacity, nitems, &criticalindex);
1639
1640 /* selects items as long as they fit into the knapsack */
1641 solitemsweight = 0;
1642 for( j = 0; j < nitems && solitemsweight + weights[j] <= capacity; ++j )
1643 {
1644 if( solitems != NULL )
1645 solitems[(*nsolitems)++] = items[j];
1646
1647 if( solval != NULL )
1648 (*solval) += profits[j];
1649 solitemsweight += weights[j];
1650 }
1651 if ( solitems != NULL )
1652 {
1653 for( ; j < nitems; j++ )
1654 nonsolitems[(*nnonsolitems)++] = items[j];
1655 }
1656
1657 SCIPfreeBufferArray(scip, &realweights);
1658 SCIPfreeBufferArray(scip, &tempsort);
1659
1660 return SCIP_OKAY;
1661}
1662
1663#ifdef SCIP_DEBUG
1664/** prints all nontrivial GUB constraints and their LP solution values */
1665static
1666void GUBsetPrint(
1667 SCIP* scip, /**< SCIP data structure */
1668 SCIP_GUBSET* gubset, /**< GUB set data structure */
1669 SCIP_VAR** vars, /**< variables in knapsack constraint */
1670 SCIP_Real* solvals /**< solution values of variables in knapsack constraint; or NULL */
1671 )
1672{
1673 int nnontrivialgubconss;
1674 int c;
1675
1676 nnontrivialgubconss = 0;
1677
1678 SCIPdebugMsg(scip, " Nontrivial GUBs of current GUB set:\n");
1679
1680 /* print out all nontrivial GUB constraints, i.e., with more than one variable */
1681 for( c = 0; c < gubset->ngubconss; c++ )
1682 {
1683 SCIP_Real gubsolval;
1684
1685 assert(gubset->gubconss[c]->ngubvars >= 0);
1686
1687 /* nontrivial GUB */
1688 if( gubset->gubconss[c]->ngubvars > 1 )
1689 {
1690 int v;
1691
1692 gubsolval = 0.0;
1693 SCIPdebugMsg(scip, " GUB<%d>:\n", c);
1694
1695 /* print GUB var */
1696 for( v = 0; v < gubset->gubconss[c]->ngubvars; v++ )
1697 {
1698 int currentvar;
1699
1700 currentvar = gubset->gubconss[c]->gubvars[v];
1701 if( solvals != NULL )
1702 {
1703 gubsolval += solvals[currentvar];
1704 SCIPdebugMsg(scip, " +<%s>(%4.2f)\n", SCIPvarGetName(vars[currentvar]), solvals[currentvar]);
1705 }
1706 else
1707 {
1708 SCIPdebugMsg(scip, " +<%s>\n", SCIPvarGetName(vars[currentvar]));
1709 }
1710 }
1711
1712 /* check whether LP solution satisfies the GUB constraint */
1713 if( solvals != NULL )
1714 {
1715 SCIPdebugMsg(scip, " =%4.2f <= 1 %s\n", gubsolval,
1716 SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1717 }
1718 else
1719 {
1720 SCIPdebugMsg(scip, " <= 1 %s\n", SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1721 }
1722 nnontrivialgubconss++;
1723 }
1724 }
1725
1726 SCIPdebugMsg(scip, " --> %d/%d nontrivial GUBs\n", nnontrivialgubconss, gubset->ngubconss);
1727}
1728#endif
1729
1730/** creates an empty GUB constraint */
1731static
1733 SCIP* scip, /**< SCIP data structure */
1734 SCIP_GUBCONS** gubcons /**< pointer to store GUB constraint data */
1735 )
1736{
1737 assert(scip != NULL);
1738 assert(gubcons != NULL);
1739
1740 /* allocate memory for GUB constraint data structures */
1741 SCIP_CALL( SCIPallocBuffer(scip, gubcons) );
1742 (*gubcons)->gubvarssize = GUBCONSGROWVALUE;
1743 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvars, (*gubcons)->gubvarssize) );
1744 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvarsstatus, (*gubcons)->gubvarssize) );
1745
1746 (*gubcons)->ngubvars = 0;
1747
1748 return SCIP_OKAY;
1749}
1750
1751/** frees GUB constraint */
1752static
1754 SCIP* scip, /**< SCIP data structure */
1755 SCIP_GUBCONS** gubcons /**< pointer to GUB constraint data structure */
1756 )
1757{
1758 assert(scip != NULL);
1759 assert(gubcons != NULL);
1760 assert((*gubcons)->gubvars != NULL);
1761 assert((*gubcons)->gubvarsstatus != NULL);
1762
1763 /* free allocated memory */
1764 SCIPfreeBufferArray(scip, &(*gubcons)->gubvarsstatus);
1765 SCIPfreeBufferArray(scip, &(*gubcons)->gubvars);
1766 SCIPfreeBuffer(scip, gubcons);
1767}
1768
1769/** adds variable to given GUB constraint */
1770static
1772 SCIP* scip, /**< SCIP data structure */
1773 SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1774 int var /**< index of given variable in knapsack constraint */
1775 )
1776{
1777 assert(scip != NULL);
1778 assert(gubcons != NULL);
1779 assert(gubcons->ngubvars >= 0 && gubcons->ngubvars < gubcons->gubvarssize);
1780 assert(gubcons->gubvars != NULL);
1781 assert(gubcons->gubvarsstatus != NULL);
1782 assert(var >= 0);
1783
1784 /* add variable to GUB constraint */
1785 gubcons->gubvars[gubcons->ngubvars] = var;
1786 gubcons->gubvarsstatus[gubcons->ngubvars] = GUBVARSTATUS_UNINITIAL;
1787 gubcons->ngubvars++;
1788
1789 /* increase space allocated to GUB constraint if the number of variables reaches the size */
1790 if( gubcons->ngubvars == gubcons->gubvarssize )
1791 {
1792 int newlen;
1793
1794 newlen = gubcons->gubvarssize + GUBCONSGROWVALUE;
1795 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1796 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1797
1798 gubcons->gubvarssize = newlen;
1799 }
1800
1801 return SCIP_OKAY;
1802}
1803
1804/** deletes variable from its current GUB constraint */
1805static
1807 SCIP* scip, /**< SCIP data structure */
1808 SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1809 int var, /**< index of given variable in knapsack constraint */
1810 int gubvarsidx /**< index of the variable in its current GUB constraint */
1811 )
1812{
1813 assert(scip != NULL);
1814 assert(gubcons != NULL);
1815 assert(var >= 0);
1816 assert(gubvarsidx >= 0 && gubvarsidx < gubcons->ngubvars);
1817 assert(gubcons->ngubvars >= gubvarsidx+1);
1818 assert(gubcons->gubvars[gubvarsidx] == var);
1819
1820 /* delete variable from GUB by swapping it replacing in by the last variable in the GUB constraint */
1821 gubcons->gubvars[gubvarsidx] = gubcons->gubvars[gubcons->ngubvars-1];
1822 gubcons->gubvarsstatus[gubvarsidx] = gubcons->gubvarsstatus[gubcons->ngubvars-1];
1823 gubcons->ngubvars--;
1824
1825 /* decrease space allocated for the GUB constraint, if the last GUBCONSGROWVALUE+1 array entries are now empty */
1826 if( gubcons->ngubvars < gubcons->gubvarssize - GUBCONSGROWVALUE && gubcons->ngubvars > 0 )
1827 {
1828 int newlen;
1829
1830 newlen = gubcons->gubvarssize - GUBCONSGROWVALUE;
1831
1832 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1833 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1834
1835 gubcons->gubvarssize = newlen;
1836 }
1837
1838 return SCIP_OKAY;
1839}
1840
1841/** moves variable from current GUB constraint to a different existing (nonempty) GUB constraint */
1842static
1844 SCIP* scip, /**< SCIP data structure */
1845 SCIP_GUBSET* gubset, /**< GUB set data structure */
1846 SCIP_VAR** vars, /**< variables in knapsack constraint */
1847 int var, /**< index of given variable in knapsack constraint */
1848 int oldgubcons, /**< index of old GUB constraint of given variable */
1849 int newgubcons /**< index of new GUB constraint of given variable */
1850 )
1851{
1852 int oldgubvaridx;
1853 int replacevar;
1854 int j;
1855
1856 assert(scip != NULL);
1857 assert(gubset != NULL);
1858 assert(var >= 0);
1859 assert(oldgubcons >= 0 && oldgubcons < gubset->ngubconss);
1860 assert(newgubcons >= 0 && newgubcons < gubset->ngubconss);
1861 assert(oldgubcons != newgubcons);
1862 assert(gubset->gubconssidx[var] == oldgubcons);
1863 assert(gubset->gubconss[oldgubcons]->ngubvars > 0);
1864 assert(gubset->gubconss[newgubcons]->ngubvars >= 0);
1865
1866 SCIPdebugMsg(scip, " moving variable<%s> from GUB<%d> to GUB<%d>\n", SCIPvarGetName(vars[var]), oldgubcons, newgubcons);
1867
1868 oldgubvaridx = gubset->gubvarsidx[var];
1869
1870 /* delete variable from old GUB constraint by replacing it by the last variable of the GUB constraint */
1871 SCIP_CALL( GUBconsDelVar(scip, gubset->gubconss[oldgubcons], var, oldgubvaridx) );
1872
1873 /* in GUB set, update stored index of variable in old GUB constraint for the variable used for replacement;
1874 * replacement variable is given by old position of the deleted variable
1875 */
1876 replacevar = gubset->gubconss[oldgubcons]->gubvars[oldgubvaridx];
1877 assert(gubset->gubvarsidx[replacevar] == gubset->gubconss[oldgubcons]->ngubvars);
1878 gubset->gubvarsidx[replacevar] = oldgubvaridx;
1879
1880 /* add variable to the end of new GUB constraint */
1881 SCIP_CALL( GUBconsAddVar(scip, gubset->gubconss[newgubcons], var) );
1882 assert(gubset->gubconss[newgubcons]->gubvars[gubset->gubconss[newgubcons]->ngubvars-1] == var);
1883
1884 /* in GUB set, update stored index of GUB of moved variable and stored index of variable in this GUB constraint */
1885 gubset->gubconssidx[var] = newgubcons;
1886 gubset->gubvarsidx[var] = gubset->gubconss[newgubcons]->ngubvars-1;
1887
1888 /* delete old GUB constraint if it became empty */
1889 if( gubset->gubconss[oldgubcons]->ngubvars == 0 )
1890 {
1891 SCIPdebugMsg(scip, "deleting empty GUB cons<%d> from current GUB set\n", oldgubcons);
1892#ifdef SCIP_DEBUG
1893 GUBsetPrint(scip, gubset, vars, NULL);
1894#endif
1895
1896 /* free old GUB constraint */
1897 GUBconsFree(scip, &gubset->gubconss[oldgubcons]);
1898
1899 /* if empty GUB was not the last one in GUB set data structure, replace it by last GUB constraint */
1900 if( oldgubcons != gubset->ngubconss-1 )
1901 {
1902 gubset->gubconss[oldgubcons] = gubset->gubconss[gubset->ngubconss-1];
1903 gubset->gubconsstatus[oldgubcons] = gubset->gubconsstatus[gubset->ngubconss-1];
1904
1905 /* in GUB set, update stored index of GUB constraint for all variable of the GUB constraint used for replacement;
1906 * replacement GUB is given by old position of the deleted GUB
1907 */
1908 for( j = 0; j < gubset->gubconss[oldgubcons]->ngubvars; j++ )
1909 {
1910 assert(gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] == gubset->ngubconss-1);
1911 gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] = oldgubcons;
1912 }
1913 }
1914
1915 /* update number of GUB constraints */
1916 gubset->ngubconss--;
1917
1918 /* variable should be at given new position, unless new GUB constraint replaced empty old GUB constraint
1919 * (because it was at the end of the GUB constraint array)
1920 */
1921 assert(gubset->gubconssidx[var] == newgubcons
1922 || (newgubcons == gubset->ngubconss && gubset->gubconssidx[var] == oldgubcons));
1923 }
1924#ifndef NDEBUG
1925 else
1926 assert(gubset->gubconssidx[var] == newgubcons);
1927#endif
1928
1929 return SCIP_OKAY;
1930}
1931
1932/** swaps two variables in the same GUB constraint */
1933static
1935 SCIP* scip, /**< SCIP data structure */
1936 SCIP_GUBSET* gubset, /**< GUB set data structure */
1937 int var1, /**< first variable to be swapped */
1938 int var2 /**< second variable to be swapped */
1939 )
1940{
1941 int gubcons;
1942 int var1idx;
1943 GUBVARSTATUS var1status;
1944 int var2idx;
1945 GUBVARSTATUS var2status;
1946
1947 assert(scip != NULL);
1948 assert(gubset != NULL);
1949
1950 gubcons = gubset->gubconssidx[var1];
1951 assert(gubcons == gubset->gubconssidx[var2]);
1952
1953 /* nothing to be done if both variables are the same */
1954 if( var1 == var2 )
1955 return;
1956
1957 /* swap index and status of variables in GUB constraint */
1958 var1idx = gubset->gubvarsidx[var1];
1959 var1status = gubset->gubconss[gubcons]->gubvarsstatus[var1idx];
1960 var2idx = gubset->gubvarsidx[var2];
1961 var2status = gubset->gubconss[gubcons]->gubvarsstatus[var2idx];
1962
1963 gubset->gubvarsidx[var1] = var2idx;
1964 gubset->gubconss[gubcons]->gubvars[var1idx] = var2;
1965 gubset->gubconss[gubcons]->gubvarsstatus[var1idx] = var2status;
1966
1967 gubset->gubvarsidx[var2] = var1idx;
1968 gubset->gubconss[gubcons]->gubvars[var2idx] = var1;
1969 gubset->gubconss[gubcons]->gubvarsstatus[var2idx] = var1status;
1970}
1971
1972/** initializes partition of knapsack variables into nonoverlapping trivial GUB constraints (GUB with one variable) */
1973static
1975 SCIP* scip, /**< SCIP data structure */
1976 SCIP_GUBSET** gubset, /**< pointer to store GUB set data structure */
1977 int nvars, /**< number of variables in the knapsack constraint */
1978 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
1979 SCIP_Longint capacity /**< capacity of knapsack */
1980 )
1981{
1982 int i;
1983
1984 assert(scip != NULL);
1985 assert(gubset != NULL);
1986 assert(nvars > 0);
1987 assert(weights != NULL);
1988 assert(capacity >= 0);
1989
1990 /* allocate memory for GUB set data structures */
1991 SCIP_CALL( SCIPallocBuffer(scip, gubset) );
1992 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconss, nvars) );
1993 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconsstatus, nvars) );
1994 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconssidx, nvars) );
1995 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubvarsidx, nvars) );
1996 (*gubset)->ngubconss = nvars;
1997 (*gubset)->nvars = nvars;
1998
1999 /* initialize the set of GUB constraints */
2000 for( i = 0; i < nvars; i++ )
2001 {
2002 /* assign each variable to a new (trivial) GUB constraint */
2003 SCIP_CALL( GUBconsCreate(scip, &(*gubset)->gubconss[i]) );
2004 SCIP_CALL( GUBconsAddVar(scip, (*gubset)->gubconss[i], i) );
2005
2006 /* set status of GUB constraint to initial */
2007 (*gubset)->gubconsstatus[i] = GUBCONSSTATUS_UNINITIAL;
2008
2009 (*gubset)->gubconssidx[i] = i;
2010 (*gubset)->gubvarsidx[i] = 0;
2011 assert((*gubset)->gubconss[i]->ngubvars == 1);
2012
2013 /* already updated status of variable in GUB constraint if it exceeds the capacity of the knapsack */
2014 if( weights[i] > capacity )
2015 (*gubset)->gubconss[(*gubset)->gubconssidx[i]]->gubvarsstatus[(*gubset)->gubvarsidx[i]] = GUBVARSTATUS_CAPACITYEXCEEDED;
2016 }
2017
2018 return SCIP_OKAY;
2019}
2020
2021/** frees GUB set data structure */
2022static
2024 SCIP* scip, /**< SCIP data structure */
2025 SCIP_GUBSET** gubset /**< pointer to GUB set data structure */
2026 )
2027{
2028 int i;
2029
2030 assert(scip != NULL);
2031 assert(gubset != NULL);
2032 assert((*gubset)->gubconss != NULL);
2033 assert((*gubset)->gubconsstatus != NULL);
2034 assert((*gubset)->gubconssidx != NULL);
2035 assert((*gubset)->gubvarsidx != NULL);
2036
2037 /* free all GUB constraints */
2038 for( i = (*gubset)->ngubconss-1; i >= 0; --i )
2039 {
2040 assert((*gubset)->gubconss[i] != NULL);
2041 GUBconsFree(scip, &(*gubset)->gubconss[i]);
2042 }
2043
2044 /* free allocated memory */
2045 SCIPfreeBufferArray( scip, &(*gubset)->gubvarsidx );
2046 SCIPfreeBufferArray( scip, &(*gubset)->gubconssidx );
2047 SCIPfreeBufferArray( scip, &(*gubset)->gubconsstatus );
2048 SCIPfreeBufferArray( scip, &(*gubset)->gubconss );
2049 SCIPfreeBuffer(scip, gubset);
2050}
2051
2052#ifndef NDEBUG
2053/** checks whether GUB set data structure is consistent */
2054static
2056 SCIP* scip, /**< SCIP data structure */
2057 SCIP_GUBSET* gubset, /**< GUB set data structure */
2058 SCIP_VAR** vars /**< variables in the knapsack constraint */
2059 )
2060{
2061 int i;
2062 int gubconsidx;
2063 int gubvaridx;
2064 SCIP_VAR* var1;
2065 SCIP_VAR* var2;
2066 SCIP_Bool var1negated;
2067 SCIP_Bool var2negated;
2068
2069 assert(scip != NULL);
2070 assert(gubset != NULL);
2071
2072 SCIPdebugMsg(scip, " GUB set consistency check:\n");
2073
2074 /* checks for all knapsack vars consistency of stored index of associated gubcons and corresponding index in gubvars */
2075 for( i = 0; i < gubset->nvars; i++ )
2076 {
2077 gubconsidx = gubset->gubconssidx[i];
2078 gubvaridx = gubset->gubvarsidx[i];
2079
2080 if( gubset->gubconss[gubconsidx]->gubvars[gubvaridx] != i )
2081 {
2082 SCIPdebugMsg(scip, " var<%d> should be in GUB<%d> at position<%d>, but stored is var<%d> instead\n", i,
2083 gubconsidx, gubvaridx, gubset->gubconss[gubconsidx]->gubvars[gubvaridx] );
2084 }
2085 assert(gubset->gubconss[gubconsidx]->gubvars[gubvaridx] == i);
2086 }
2087
2088 /* checks for each GUB whether all pairs of its variables have a common clique */
2089 for( i = 0; i < gubset->ngubconss; i++ )
2090 {
2091 int j;
2092
2093 for( j = 0; j < gubset->gubconss[i]->ngubvars; j++ )
2094 {
2095 int k;
2096
2097 /* get corresponding active problem variable */
2098 var1 = vars[gubset->gubconss[i]->gubvars[j]];
2099 var1negated = FALSE;
2100 SCIP_CALL( SCIPvarGetProbvarBinary(&var1, &var1negated) );
2101
2102 for( k = j+1; k < gubset->gubconss[i]->ngubvars; k++ )
2103 {
2104 /* get corresponding active problem variable */
2105 var2 = vars[gubset->gubconss[i]->gubvars[k]];
2106 var2negated = FALSE;
2107 SCIP_CALL( SCIPvarGetProbvarBinary(&var2, &var2negated) );
2108
2109 if( !SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE) )
2110 {
2111 SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2112 SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[j]]), k,
2113 SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[k]]));
2114 SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2115 SCIPvarGetName(var1), k,
2116 SCIPvarGetName(var2));
2117 }
2118
2119 /* @todo: in case we used also negated cliques for the GUB partition, this assert has to be changed */
2120 assert(SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE));
2121 }
2122 }
2123 }
2124 SCIPdebugMsg(scip, " --> successful\n");
2125
2126 return SCIP_OKAY;
2127}
2128#endif
2129
2130/** calculates a partition of the given set of binary variables into cliques;
2131 * afterwards the output array contains one value for each variable, such that two variables got the same value iff they
2132 * were assigned to the same clique;
2133 * the first variable is always assigned to clique 0, and a variable can only be assigned to clique i if at least one of
2134 * the preceding variables was assigned to clique i-1;
2135 * note: in contrast to SCIPcalcCliquePartition(), variables with LP value 1 are put into trivial cliques (with one
2136 * variable) and for the remaining variables, a partition with a small number of cliques is constructed
2137 */
2138
2139static
2141 SCIP*const scip, /**< SCIP data structure */
2142 SCIP_VAR**const vars, /**< binary variables in the clique from which at most one can be set to 1 */
2143 int const nvars, /**< number of variables in the clique */
2144 int*const cliquepartition, /**< array of length nvars to store the clique partition */
2145 int*const ncliques, /**< pointer to store number of cliques actually contained in the partition */
2146 SCIP_Real* solvals /**< solution values of all given binary variables */
2147 )
2148{
2149 SCIP_VAR** tmpvars;
2150 SCIP_VAR** cliquevars;
2151 SCIP_Bool* cliquevalues;
2152 SCIP_Bool* tmpvalues;
2153 int* varseq;
2154 int* sortkeys;
2155 int ncliquevars;
2156 int maxncliquevarscomp;
2157 int nignorevars;
2158 int nvarsused;
2159 int i;
2160
2161 assert(scip != NULL);
2162 assert(nvars == 0 || vars != NULL);
2163 assert(nvars == 0 || cliquepartition != NULL);
2164 assert(ncliques != NULL);
2165
2166 if( nvars == 0 )
2167 {
2168 *ncliques = 0;
2169 return SCIP_OKAY;
2170 }
2171
2172 /* allocate temporary memory for storing the variables of the current clique */
2173 SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
2174 SCIP_CALL( SCIPallocBufferArray(scip, &cliquevalues, nvars) );
2175 SCIP_CALL( SCIPallocBufferArray(scip, &tmpvalues, nvars) );
2176 SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpvars, vars, nvars) );
2178 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvars) );
2179
2180 /* initialize the cliquepartition array with -1 */
2181 /* initialize the tmpvalues array */
2182 for( i = nvars - 1; i >= 0; --i )
2183 {
2184 tmpvalues[i] = TRUE;
2185 cliquepartition[i] = -1;
2186 }
2187
2188 /* get corresponding active problem variables */
2189 SCIP_CALL( SCIPvarsGetProbvarBinary(&tmpvars, &tmpvalues, nvars) );
2190
2191 /* ignore variables with LP value 1 (will be assigned to trivial GUBs at the end) and sort remaining variables
2192 * by nondecreasing number of cliques the variables are in
2193 */
2194 nignorevars = 0;
2195 nvarsused = 0;
2196 for( i = 0; i < nvars; i++ )
2197 {
2198 if( SCIPisFeasEQ(scip, solvals[i], 1.0) )
2199 {
2200 /* variables with LP value 1 are put to the end of varseq array and will not be sorted */
2201 varseq[nvars-1-nignorevars] = i;
2202 nignorevars++;
2203 }
2204 else
2205 {
2206 /* remaining variables are put to the front of varseq array and will be sorted by their number of cliques */
2207 varseq[nvarsused] = i;
2208 sortkeys[nvarsused] = SCIPvarGetNCliques(tmpvars[i], tmpvalues[i]);
2209 nvarsused++;
2210 }
2211 }
2212 assert(nvarsused + nignorevars == nvars);
2213
2214 /* sort variables with LP value less than 1 by nondecreasing order of the number of cliques they are in */
2215 SCIPsortIntInt(sortkeys, varseq, nvarsused);
2216
2217 maxncliquevarscomp = MIN(nvars*nvars, MAXNCLIQUEVARSCOMP);
2218
2219 /* calculate the clique partition */
2220 *ncliques = 0;
2221 for( i = 0; i < nvars; ++i )
2222 {
2223 if( cliquepartition[varseq[i]] == -1 )
2224 {
2225 int j;
2226
2227 /* variable starts a new clique */
2228 cliquepartition[varseq[i]] = *ncliques;
2229 cliquevars[0] = tmpvars[varseq[i]];
2230 cliquevalues[0] = tmpvalues[varseq[i]];
2231 ncliquevars = 1;
2232
2233 /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique and
2234 * if the variable has LP value 1 we do not want it to be in nontrivial cliques
2235 */
2236 if( i < nvarsused && SCIPvarIsActive(tmpvars[varseq[i]]) )
2237 {
2238 /* greedily fill up the clique */
2239 for( j = i + 1; j < nvarsused; ++j )
2240 {
2241 /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique */
2242 if( cliquepartition[varseq[j]] == -1 && SCIPvarIsActive(tmpvars[varseq[j]]) )
2243 {
2244 int k;
2245
2246 /* check if every variable in the actual clique is in clique with the new variable */
2247 for( k = ncliquevars - 1; k >= 0; --k )
2248 {
2249 if( !SCIPvarsHaveCommonClique(tmpvars[varseq[j]], tmpvalues[varseq[j]], cliquevars[k],
2250 cliquevalues[k], TRUE) )
2251 break;
2252 }
2253
2254 if( k == -1 )
2255 {
2256 /* put the variable into the same clique */
2257 cliquepartition[varseq[j]] = cliquepartition[varseq[i]];
2258 cliquevars[ncliquevars] = tmpvars[varseq[j]];
2259 cliquevalues[ncliquevars] = tmpvalues[varseq[j]];
2260 ++ncliquevars;
2261 }
2262 }
2263 }
2264 }
2265
2266 /* this clique is finished */
2267 ++(*ncliques);
2268 }
2269 assert(cliquepartition[varseq[i]] >= 0 && cliquepartition[varseq[i]] < i + 1);
2270
2271 /* break if we reached the maximal number of comparisons */
2272 if( i * nvars > maxncliquevarscomp )
2273 break;
2274 }
2275 /* if we had too many variables fill up the cliquepartition and put each variable in a separate clique */
2276 for( ; i < nvars; ++i )
2277 {
2278 if( cliquepartition[varseq[i]] == -1 )
2279 {
2280 cliquepartition[varseq[i]] = *ncliques;
2281 ++(*ncliques);
2282 }
2283 }
2284
2285 /* free temporary memory */
2286 SCIPfreeBufferArray(scip, &sortkeys);
2287 SCIPfreeBufferArray(scip, &varseq);
2288 SCIPfreeBufferArray(scip, &tmpvars);
2289 SCIPfreeBufferArray(scip, &tmpvalues);
2290 SCIPfreeBufferArray(scip, &cliquevalues);
2291 SCIPfreeBufferArray(scip, &cliquevars);
2292
2293 return SCIP_OKAY;
2294}
2295
2296/** constructs sophisticated partition of knapsack variables into non-overlapping GUBs; current partition uses trivial GUBs */
2297static
2299 SCIP* scip, /**< SCIP data structure */
2300 SCIP_GUBSET* gubset, /**< GUB set data structure */
2301 SCIP_VAR** vars, /**< variables in the knapsack constraint */
2302 SCIP_Real* solvals /**< solution values of all knapsack variables */
2303 )
2304{
2305 int* cliquepartition;
2306 int* gubfirstvar;
2307 int ncliques;
2308 int currentgubconsidx;
2309 int newgubconsidx;
2310 int cliqueidx;
2311 int nvars;
2312 int i;
2313
2314 assert(scip != NULL);
2315 assert(gubset != NULL);
2316 assert(vars != NULL);
2317
2318 nvars = gubset->nvars;
2319 assert(nvars >= 0);
2320
2321 /* allocate temporary memory for clique partition */
2322 SCIP_CALL( SCIPallocBufferArray(scip, &cliquepartition, nvars) );
2323
2324 /* compute sophisticated clique partition */
2325 SCIP_CALL( GUBsetCalcCliquePartition(scip, vars, nvars, cliquepartition, &ncliques, solvals) );
2326
2327 /* allocate temporary memory for GUB set data structure */
2328 SCIP_CALL( SCIPallocBufferArray(scip, &gubfirstvar, ncliques) );
2329
2330 /* translate GUB partition into GUB set data structure */
2331 for( i = 0; i < ncliques; i++ )
2332 {
2333 /* initialize first variable for every GUB */
2334 gubfirstvar[i] = -1;
2335 }
2336 /* move every knapsack variable into GUB defined by clique partition */
2337 for( i = 0; i < nvars; i++ )
2338 {
2339 assert(cliquepartition[i] >= 0);
2340
2341 cliqueidx = cliquepartition[i];
2342 currentgubconsidx = gubset->gubconssidx[i];
2343 assert(gubset->gubconss[currentgubconsidx]->ngubvars == 1 );
2344
2345 /* variable is first element in GUB constraint defined by clique partition */
2346 if( gubfirstvar[cliqueidx] == -1 )
2347 {
2348 /* corresponding GUB constraint in GUB set data structure was already constructed (as initial trivial GUB);
2349 * note: no assert for gubconssidx, because it can changed due to deleting empty GUBs in GUBsetMoveVar()
2350 */
2351 assert(gubset->gubvarsidx[i] == 0);
2352 assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2353
2354 /* remember the first variable found for the current GUB */
2355 gubfirstvar[cliqueidx] = i;
2356 }
2357 /* variable is additional element of GUB constraint defined by clique partition */
2358 else
2359 {
2360 assert(gubfirstvar[cliqueidx] >= 0 && gubfirstvar[cliqueidx] < i);
2361
2362 /* move variable to GUB constraint defined by clique partition; index of this GUB constraint is given by the
2363 * first variable of this GUB constraint
2364 */
2365 newgubconsidx = gubset->gubconssidx[gubfirstvar[cliqueidx]];
2366 assert(newgubconsidx != currentgubconsidx); /* because initially every variable is in a different GUB */
2367 SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, i, currentgubconsidx, newgubconsidx) );
2368
2369 assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2370 }
2371 }
2372
2373#ifdef SCIP_DEBUG
2374 /* prints GUB set data structure */
2375 GUBsetPrint(scip, gubset, vars, solvals);
2376#endif
2377
2378#ifndef NDEBUG
2379 /* checks consistency of GUB set data structure */
2380 SCIP_CALL( GUBsetCheck(scip, gubset, vars) );
2381#endif
2382
2383 /* free temporary memory */
2384 SCIPfreeBufferArray(scip, &gubfirstvar);
2385 SCIPfreeBufferArray(scip, &cliquepartition);
2386
2387 return SCIP_OKAY;
2388}
2389
2390/** gets a most violated cover C (\f$\sum_{j \in C} a_j > a_0\f$) for a given knapsack constraint \f$\sum_{j \in N} a_j x_j \leq a_0\f$
2391 * taking into consideration the following fixing: \f$j \in C\f$, if \f$j \in N_1 = \{j \in N : x^*_j = 1\}\f$ and
2392 * \f$j \in N \setminus C\f$, if \f$j \in N_0 = \{j \in N : x^*_j = 0\}\f$, if one exists.
2393 */
2394static
2396 SCIP* scip, /**< SCIP data structure */
2397 SCIP_VAR** vars, /**< variables in knapsack constraint */
2398 int nvars, /**< number of variables in knapsack constraint */
2399 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2400 SCIP_Longint capacity, /**< capacity of knapsack */
2401 SCIP_Real* solvals, /**< solution values of all problem variables */
2402 int* covervars, /**< pointer to store cover variables */
2403 int* noncovervars, /**< pointer to store noncover variables */
2404 int* ncovervars, /**< pointer to store number of cover variables */
2405 int* nnoncovervars, /**< pointer to store number of noncover variables */
2406 SCIP_Longint* coverweight, /**< pointer to store weight of cover */
2407 SCIP_Bool* found, /**< pointer to store whether a cover was found */
2408 SCIP_Bool modtransused, /**< should modified transformed separation problem be used to find cover */
2409 int* ntightened, /**< pointer to store number of variables with tightened upper bound */
2410 SCIP_Bool* fractional /**< pointer to store whether the LP sol for knapsack vars is fractional */
2411 )
2412{
2413 SCIP_Longint* transweights;
2414 SCIP_Real* transprofits;
2415 SCIP_Longint transcapacity;
2416 SCIP_Longint fixedonesweight;
2417 SCIP_Longint itemsweight;
2418 SCIP_Bool infeasible;
2419 int* fixedones;
2420 int* fixedzeros;
2421 int* items;
2422 int nfixedones;
2423 int nfixedzeros;
2424 int nitems;
2425 int j;
2426
2427 assert(scip != NULL);
2428 assert(vars != NULL);
2429 assert(nvars > 0);
2430 assert(weights != NULL);
2431 assert(capacity >= 0);
2432 assert(solvals != NULL);
2433 assert(covervars != NULL);
2434 assert(noncovervars != NULL);
2435 assert(ncovervars != NULL);
2436 assert(nnoncovervars != NULL);
2437 assert(coverweight != NULL);
2438 assert(found != NULL);
2439 assert(ntightened != NULL);
2440 assert(fractional != NULL);
2441
2442 SCIPdebugMsg(scip, " get cover for knapsack constraint\n");
2443
2444 /* allocates temporary memory */
2445 SCIP_CALL( SCIPallocBufferArray(scip, &transweights, nvars) );
2446 SCIP_CALL( SCIPallocBufferArray(scip, &transprofits, nvars) );
2447 SCIP_CALL( SCIPallocBufferArray(scip, &fixedones, nvars) );
2448 SCIP_CALL( SCIPallocBufferArray(scip, &fixedzeros, nvars) );
2450
2451 *found = FALSE;
2452 *ncovervars = 0;
2453 *nnoncovervars = 0;
2454 *coverweight = 0;
2455 *fractional = TRUE;
2456
2457 /* gets the following sets
2458 * N_1 = {j in N : x*_j = 1} (fixedones),
2459 * N_0 = {j in N : x*_j = 0} (fixedzeros) and
2460 * N\‍(N_0 & N_1) (items),
2461 * where x*_j is the solution value of variable x_j
2462 */
2463 nfixedones = 0;
2464 nfixedzeros = 0;
2465 nitems = 0;
2466 fixedonesweight = 0;
2467 itemsweight = 0;
2468 *ntightened = 0;
2469 for( j = 0; j < nvars; j++ )
2470 {
2471 assert(SCIPvarIsBinary(vars[j]));
2472
2473 /* tightens upper bound of x_j if weight of x_j is greater than capacity of knapsack */
2474 if( weights[j] > capacity )
2475 {
2476 SCIP_CALL( SCIPtightenVarUb(scip, vars[j], 0.0, FALSE, &infeasible, NULL) );
2477 assert(!infeasible);
2478 (*ntightened)++;
2479 continue;
2480 }
2481
2482 /* variable x_j has solution value one */
2483 if( SCIPisFeasEQ(scip, solvals[j], 1.0) )
2484 {
2485 fixedones[nfixedones] = j;
2486 nfixedones++;
2487 fixedonesweight += weights[j];
2488 }
2489 /* variable x_j has solution value zero */
2490 else if( SCIPisFeasEQ(scip, solvals[j], 0.0) )
2491 {
2492 fixedzeros[nfixedzeros] = j;
2493 nfixedzeros++;
2494 }
2495 /* variable x_j has fractional solution value */
2496 else
2497 {
2498 assert( SCIPisFeasGT(scip, solvals[j], 0.0) && SCIPisFeasLT(scip, solvals[j], 1.0) );
2499 items[nitems] = j;
2500 nitems++;
2501 itemsweight += weights[j];
2502 }
2503 }
2504 assert(nfixedones + nfixedzeros + nitems == nvars - (*ntightened));
2505
2506 /* sets whether the LP solution x* for the knapsack variables is fractional; if it is not fractional we stop
2507 * the separation routine
2508 */
2509 assert(nitems >= 0);
2510 if( nitems == 0 )
2511 {
2512 *fractional = FALSE;
2513 goto TERMINATE;
2514 }
2515 assert(*fractional);
2516
2517 /* transforms the traditional separation problem (under consideration of the following fixing:
2518 * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2519 *
2520 * min sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) z_j
2521 * sum_{j in N\‍(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2522 * z_j in {0,1}, j in N\‍(N_0 & N_1)
2523 *
2524 * to a knapsack problem in maximization form by complementing the variables
2525 *
2526 * sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) -
2527 * max sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) z_j
2528 * sum_{j in N\‍(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2529 * z_j in {0,1}, j in N\‍(N_0 & N_1)
2530 */
2531
2532 /* gets weight and profit of variables in transformed knapsack problem */
2533 for( j = 0; j < nitems; j++ )
2534 {
2535 transweights[j] = weights[items[j]];
2536 transprofits[j] = 1.0 - solvals[items[j]];
2537 }
2538 /* gets capacity of transformed knapsack problem */
2539 transcapacity = fixedonesweight + itemsweight - capacity - 1;
2540
2541 /* if capacity of transformed knapsack problem is less than zero, there is no cover
2542 * (when variables fixed to zero are not used)
2543 */
2544 if( transcapacity < 0 )
2545 {
2546 assert(!(*found));
2547 goto TERMINATE;
2548 }
2549
2550 if( modtransused )
2551 {
2552 /* transforms the modified separation problem (under consideration of the following fixing:
2553 * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2554 *
2555 * min sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) a_j z_j
2556 * sum_{j in N\‍(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2557 * z_j in {0,1}, j in N\‍(N_0 & N_1)
2558 *
2559 * to a knapsack problem in maximization form by complementing the variables
2560 *
2561 * sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) a_j -
2562 * max sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) a_j z_j
2563 * sum_{j in N\‍(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2564 * z_j in {0,1}, j in N\‍(N_0 & N_1)
2565 */
2566
2567 /* gets weight and profit of variables in modified transformed knapsack problem */
2568 for( j = 0; j < nitems; j++ )
2569 {
2570 transprofits[j] *= weights[items[j]];
2571 assert(SCIPisFeasPositive(scip, transprofits[j]));
2572 }
2573 }
2574
2575 /* solves (modified) transformed knapsack problem approximately by solving the LP-relaxation of the (modified)
2576 * transformed knapsack problem using Dantzig's method and rounding down the solution.
2577 * let z* be the solution, then
2578 * j in C, if z*_j = 0 and
2579 * i in N\C, if z*_j = 1.
2580 */
2581 SCIP_CALL( SCIPsolveKnapsackApproximately(scip, nitems, transweights, transprofits, transcapacity, items,
2582 noncovervars, covervars, nnoncovervars, ncovervars, NULL) );
2583 /*assert(checkSolveKnapsack(scip, nitems, transweights, transprofits, items, weights, solvals, modtransused));*/
2584
2585 /* constructs cover C (sum_{j in C} a_j > a_0) */
2586 for( j = 0; j < *ncovervars; j++ )
2587 {
2588 (*coverweight) += weights[covervars[j]];
2589 }
2590
2591 /* adds all variables from N_1 to C */
2592 for( j = 0; j < nfixedones; j++ )
2593 {
2594 covervars[*ncovervars] = fixedones[j];
2595 (*ncovervars)++;
2596 (*coverweight) += weights[fixedones[j]];
2597 }
2598
2599 /* adds all variables from N_0 to N\C */
2600 for( j = 0; j < nfixedzeros; j++ )
2601 {
2602 noncovervars[*nnoncovervars] = fixedzeros[j];
2603 (*nnoncovervars)++;
2604 }
2605 assert((*ncovervars) + (*nnoncovervars) == nvars - (*ntightened));
2606 assert((*coverweight) > capacity);
2607 *found = TRUE;
2608
2609 TERMINATE:
2610 /* frees temporary memory */
2611 SCIPfreeBufferArray(scip, &items);
2612 SCIPfreeBufferArray(scip, &fixedzeros);
2613 SCIPfreeBufferArray(scip, &fixedones);
2614 SCIPfreeBufferArray(scip, &transprofits);
2615 SCIPfreeBufferArray(scip, &transweights);
2616
2617 SCIPdebugMsg(scip, " get cover for knapsack constraint -- end\n");
2618
2619 return SCIP_OKAY;
2620}
2621
2622#ifndef NDEBUG
2623/** checks if minweightidx is set correctly
2624 */
2625static
2627 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2628 SCIP_Longint capacity, /**< capacity of knapsack */
2629 int* covervars, /**< pointer to store cover variables */
2630 int ncovervars, /**< pointer to store number of cover variables */
2631 SCIP_Longint coverweight, /**< pointer to store weight of cover */
2632 int minweightidx, /**< index of variable in cover variables with minimum weight */
2633 int j /**< current index in cover variables */
2634 )
2635{
2636 SCIP_Longint minweight;
2637 int i;
2638
2639 assert(weights != NULL);
2640 assert(covervars != NULL);
2641 assert(ncovervars > 0);
2642
2643 minweight = weights[covervars[minweightidx]];
2644
2645 /* checks if all cover variables before index j have weight greater than minweight */
2646 for( i = 0; i < j; i++ )
2647 {
2648 assert(weights[covervars[i]] > minweight);
2649 if( weights[covervars[i]] <= minweight )
2650 return FALSE;
2651 }
2652
2653 /* checks if all variables before index j cannot be removed, i.e. i cannot be the next minweightidx */
2654 for( i = 0; i < j; i++ )
2655 {
2656 assert(coverweight - weights[covervars[i]] <= capacity);
2657 if( coverweight - weights[covervars[i]] > capacity )
2658 return FALSE;
2659 }
2660 return TRUE;
2661}
2662#endif
2663
2664
2665/** gets partition \f$(C_1,C_2)\f$ of minimal cover \f$C\f$, i.e. \f$C_1 \cup C_2 = C\f$ and \f$C_1 \cap C_2 = \emptyset\f$,
2666 * with \f$C_1\f$ not empty; chooses partition as follows \f$C_2 = \{ j \in C : x^*_j = 1 \}\f$ and \f$C_1 = C \setminus C_2\f$
2667 */
2668static
2670 SCIP* scip, /**< SCIP data structure */
2671 SCIP_Real* solvals, /**< solution values of all problem variables */
2672 int* covervars, /**< cover variables */
2673 int ncovervars, /**< number of cover variables */
2674 int* varsC1, /**< pointer to store variables in C1 */
2675 int* varsC2, /**< pointer to store variables in C2 */
2676 int* nvarsC1, /**< pointer to store number of variables in C1 */
2677 int* nvarsC2 /**< pointer to store number of variables in C2 */
2678 )
2679{
2680 int j;
2681
2682 assert(scip != NULL);
2683 assert(ncovervars >= 0);
2684 assert(solvals != NULL);
2685 assert(covervars != NULL);
2686 assert(varsC1 != NULL);
2687 assert(varsC2 != NULL);
2688 assert(nvarsC1 != NULL);
2689 assert(nvarsC2 != NULL);
2690
2691 *nvarsC1 = 0;
2692 *nvarsC2 = 0;
2693 for( j = 0; j < ncovervars; j++ )
2694 {
2695 assert(SCIPisFeasGT(scip, solvals[covervars[j]], 0.0));
2696
2697 /* variable has solution value one */
2698 if( SCIPisGE(scip, solvals[covervars[j]], 1.0) )
2699 {
2700 varsC2[*nvarsC2] = covervars[j];
2701 (*nvarsC2)++;
2702 }
2703 /* variable has solution value less than one */
2704 else
2705 {
2706 assert(SCIPisLT(scip, solvals[covervars[j]], 1.0));
2707 varsC1[*nvarsC1] = covervars[j];
2708 (*nvarsC1)++;
2709 }
2710 }
2711 assert((*nvarsC1) + (*nvarsC2) == ncovervars);
2712}
2713
2714/** changes given partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one and two (if possible) variables from
2715 * C2 to C1 if |C1| = 1 and |C1| = 0, respectively.
2716 */
2717static
2719 SCIP* scip, /**< SCIP data structure */
2720 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2721 int* varsC1, /**< pointer to store variables in C1 */
2722 int* varsC2, /**< pointer to store variables in C2 */
2723 int* nvarsC1, /**< pointer to store number of variables in C1 */
2724 int* nvarsC2 /**< pointer to store number of variables in C2 */
2725 )
2726{
2727 SCIP_Real* sortkeysC2;
2728 int j;
2729
2730 assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2731 assert(*nvarsC2 > 0);
2732
2733 /* allocates temporary memory */
2734 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2735
2736 /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2737 for( j = 0; j < *nvarsC2; j++ )
2738 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2739 SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2740
2741 /* adds one or two variable from C2 with smallest weight to C1 and removes them from C2 */
2742 assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2743 while( *nvarsC1 < 2 && *nvarsC2 > 0 )
2744 {
2745 varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2746 (*nvarsC1)++;
2747 (*nvarsC2)--;
2748 }
2749
2750 /* frees temporary memory */
2751 SCIPfreeBufferArray(scip, &sortkeysC2);
2752
2753 return SCIP_OKAY;
2754}
2755
2756/** changes given partition (C_1,C_2) of feasible set C, if |C1| = 1, by moving one variable from C2 to C1 */
2757static
2759 SCIP* scip, /**< SCIP data structure */
2760 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2761 int* varsC1, /**< pointer to store variables in C1 */
2762 int* varsC2, /**< pointer to store variables in C2 */
2763 int* nvarsC1, /**< pointer to store number of variables in C1 */
2764 int* nvarsC2 /**< pointer to store number of variables in C2 */
2765 )
2766{
2767 SCIP_Real* sortkeysC2;
2768 int j;
2769
2770 assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2771 assert(*nvarsC2 > 0);
2772
2773 /* allocates temporary memory */
2774 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2775
2776 /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2777 for( j = 0; j < *nvarsC2; j++ )
2778 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2779 SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2780
2781 /* adds variable from C2 with smallest weight to C1 and removes it from C2 */
2782 assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2783 varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2784 (*nvarsC1)++;
2785 (*nvarsC2)--;
2786
2787 /* frees temporary memory */
2788 SCIPfreeBufferArray(scip, &sortkeysC2);
2789
2790 return SCIP_OKAY;
2791}
2792
2793
2794/** gets partition \f$(F,R)\f$ of \f$N \setminus C\f$ where \f$C\f$ is a minimal cover, i.e. \f$F \cup R = N \setminus C\f$
2795 * and \f$F \cap R = \emptyset\f$; chooses partition as follows \f$R = \{ j \in N \setminus C : x^*_j = 0 \}\f$ and
2796 * \f$F = (N \setminus C) \setminus F\f$
2797 */
2798static
2800 SCIP* scip, /**< SCIP data structure */
2801 SCIP_Real* solvals, /**< solution values of all problem variables */
2802 int* noncovervars, /**< noncover variables */
2803 int nnoncovervars, /**< number of noncover variables */
2804 int* varsF, /**< pointer to store variables in F */
2805 int* varsR, /**< pointer to store variables in R */
2806 int* nvarsF, /**< pointer to store number of variables in F */
2807 int* nvarsR /**< pointer to store number of variables in R */
2808 )
2809{
2810 int j;
2811
2812 assert(scip != NULL);
2813 assert(nnoncovervars >= 0);
2814 assert(solvals != NULL);
2815 assert(noncovervars != NULL);
2816 assert(varsF != NULL);
2817 assert(varsR != NULL);
2818 assert(nvarsF != NULL);
2819 assert(nvarsR != NULL);
2820
2821 *nvarsF = 0;
2822 *nvarsR = 0;
2823
2824 for( j = 0; j < nnoncovervars; j++ )
2825 {
2826 /* variable has solution value zero */
2827 if( SCIPisFeasEQ(scip, solvals[noncovervars[j]], 0.0) )
2828 {
2829 varsR[*nvarsR] = noncovervars[j];
2830 (*nvarsR)++;
2831 }
2832 /* variable has solution value greater than zero */
2833 else
2834 {
2835 assert(SCIPisFeasGT(scip, solvals[noncovervars[j]], 0.0));
2836 varsF[*nvarsF] = noncovervars[j];
2837 (*nvarsF)++;
2838 }
2839 }
2840 assert((*nvarsF) + (*nvarsR) == nnoncovervars);
2841}
2842
2843/** sorts variables in F, C_2, and R according to the second level lifting sequence that will be used in the sequential
2844 * lifting procedure
2845 */
2846static
2848 SCIP* scip, /**< SCIP data structure */
2849 SCIP_Real* solvals, /**< solution values of all problem variables */
2850 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2851 int* varsF, /**< pointer to store variables in F */
2852 int* varsC2, /**< pointer to store variables in C2 */
2853 int* varsR, /**< pointer to store variables in R */
2854 int nvarsF, /**< number of variables in F */
2855 int nvarsC2, /**< number of variables in C2 */
2856 int nvarsR /**< number of variables in R */
2857 )
2858{
2859 SORTKEYPAIR** sortkeypairsF;
2860 SORTKEYPAIR* sortkeypairsFstore;
2861 SCIP_Real* sortkeysC2;
2862 SCIP_Real* sortkeysR;
2863 int j;
2864
2865 assert(scip != NULL);
2866 assert(solvals != NULL);
2867 assert(weights != NULL);
2868 assert(varsF != NULL);
2869 assert(varsC2 != NULL);
2870 assert(varsR != NULL);
2871 assert(nvarsF >= 0);
2872 assert(nvarsC2 >= 0);
2873 assert(nvarsR >= 0);
2874
2875 /* allocates temporary memory */
2876 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsF, nvarsF) );
2877 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsFstore, nvarsF) );
2878 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
2879 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
2880
2881 /* gets sorting key for variables in F corresponding to the following lifting sequence
2882 * sequence 1: non-increasing absolute difference between x*_j and the value the variable is fixed to, i.e.
2883 * x*_1 >= x*_2 >= ... >= x*_|F|
2884 * in case of equality uses
2885 * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2886 */
2887 for( j = 0; j < nvarsF; j++ )
2888 {
2889 sortkeypairsF[j] = &(sortkeypairsFstore[j]);
2890 sortkeypairsF[j]->key1 = solvals[varsF[j]];
2891 sortkeypairsF[j]->key2 = (SCIP_Real) weights[varsF[j]];
2892 }
2893
2894 /* gets sorting key for variables in C_2 corresponding to the following lifting sequence
2895 * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2896 */
2897 for( j = 0; j < nvarsC2; j++ )
2898 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2899
2900 /* gets sorting key for variables in R corresponding to the following lifting sequence
2901 * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|R|
2902 */
2903 for( j = 0; j < nvarsR; j++ )
2904 sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
2905
2906 /* sorts F, C2 and R */
2907 if( nvarsF > 0 )
2908 {
2909 SCIPsortDownPtrInt((void**)sortkeypairsF, varsF, compSortkeypairs, nvarsF);
2910 }
2911 if( nvarsC2 > 0 )
2912 {
2913 SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
2914 }
2915 if( nvarsR > 0)
2916 {
2917 SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
2918 }
2919
2920 /* frees temporary memory */
2921 SCIPfreeBufferArray(scip, &sortkeysR);
2922 SCIPfreeBufferArray(scip, &sortkeysC2);
2923 SCIPfreeBufferArray(scip, &sortkeypairsFstore);
2924 SCIPfreeBufferArray(scip, &sortkeypairsF);
2925
2926 return SCIP_OKAY;
2927}
2928
2929/** categorizes GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of the GUBs
2930 * for the sequential GUB wise lifting procedure
2931 */
2932static
2934 SCIP* scip, /**< SCIP data structure */
2935 SCIP_GUBSET* gubset, /**< GUB set data structure */
2936 SCIP_Real* solvals, /**< solution values of variables in knapsack constraint */
2937 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2938 int* varsC1, /**< variables in C1 */
2939 int* varsC2, /**< variables in C2 */
2940 int* varsF, /**< variables in F */
2941 int* varsR, /**< variables in R */
2942 int nvarsC1, /**< number of variables in C1 */
2943 int nvarsC2, /**< number of variables in C2 */
2944 int nvarsF, /**< number of variables in F */
2945 int nvarsR, /**< number of variables in R */
2946 int* gubconsGC1, /**< pointer to store GUBs in GC1(GNC1+GOC1) */
2947 int* gubconsGC2, /**< pointer to store GUBs in GC2 */
2948 int* gubconsGFC1, /**< pointer to store GUBs in GFC1(GNC1+GF) */
2949 int* gubconsGR, /**< pointer to store GUBs in GR */
2950 int* ngubconsGC1, /**< pointer to store number of GUBs in GC1(GNC1+GOC1) */
2951 int* ngubconsGC2, /**< pointer to store number of GUBs in GC2 */
2952 int* ngubconsGFC1, /**< pointer to store number of GUBs in GFC1(GNC1+GF) */
2953 int* ngubconsGR, /**< pointer to store number of GUBs in GR */
2954 int* ngubconscapexceed, /**< pointer to store number of GUBs with only capacity exceeding variables */
2955 int* maxgubvarssize /**< pointer to store the maximal size of GUB constraints */
2956 )
2957{
2958 SORTKEYPAIR** sortkeypairsGFC1;
2959 SORTKEYPAIR* sortkeypairsGFC1store;
2960 SCIP_Real* sortkeysC1;
2961 SCIP_Real* sortkeysC2;
2962 SCIP_Real* sortkeysR;
2963 int* nC1varsingubcons;
2964 int var;
2965 int gubconsidx;
2966 int varidx;
2967 int ngubconss;
2968 int ngubconsGOC1;
2969 int targetvar;
2970#ifndef NDEBUG
2971 int nvarsprocessed = 0;
2972#endif
2973 int i;
2974 int j;
2975
2976#if GUBSPLITGNC1GUBS
2977 SCIP_Bool gubconswithF;
2978 int origngubconss;
2979 origngubconss = gubset->ngubconss;
2980#endif
2981
2982 assert(scip != NULL);
2983 assert(gubset != NULL);
2984 assert(solvals != NULL);
2985 assert(weights != NULL);
2986 assert(varsC1 != NULL);
2987 assert(varsC2 != NULL);
2988 assert(varsF != NULL);
2989 assert(varsR != NULL);
2990 assert(nvarsC1 > 0);
2991 assert(nvarsC2 >= 0);
2992 assert(nvarsF >= 0);
2993 assert(nvarsR >= 0);
2994 assert(gubconsGC1 != NULL);
2995 assert(gubconsGC2 != NULL);
2996 assert(gubconsGFC1 != NULL);
2997 assert(gubconsGR != NULL);
2998 assert(ngubconsGC1 != NULL);
2999 assert(ngubconsGC2 != NULL);
3000 assert(ngubconsGFC1 != NULL);
3001 assert(ngubconsGR != NULL);
3002 assert(maxgubvarssize != NULL);
3003
3004 ngubconss = gubset->ngubconss;
3005 ngubconsGOC1 = 0;
3006
3007 /* GUBs are categorized into different types according to the variables in volved
3008 * - GOC1: involves variables in C1 only -- no C2, R, F
3009 * - GNC1: involves variables in C1 and F (and R) -- no C2
3010 * - GF: involves variables in F (and R) only -- no C1, C2
3011 * - GC2: involves variables in C2 only -- no C1, R, F
3012 * - GR: involves variables in R only -- no C1, C2, F
3013 * which requires splitting GUBs in case they include variable in F and R.
3014 *
3015 * afterwards all GUBs (except GOC1 GUBs, which we do not need to lift) are sorted by a two level lifting sequence.
3016 * - first ordering level is: GFC1 (GNC1+GF), GC2, and GR.
3017 * - second ordering level is
3018 * GFC1: non-increasing number of variables in F and non-increasing max{x*_k : k in GFC1_j} in case of equality
3019 * GC2: non-increasing max{ a_k : k in GC2_j}; note that |GFC2_j| = 1
3020 * GR: non-increasing max{ a_k : k in GR_j}
3021 *
3022 * in additon, another GUB union, which is helpful for the lifting procedure, is formed
3023 * - GC1: GUBs of category GOC1 and GNC1
3024 * with second ordering level non-decreasing min{ a_k : k in GC1_j };
3025 * note that min{ a_k : k in GC1_j } always comes from the first variable in the GUB
3026 */
3027
3028 /* allocates temporary memory */
3029 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC1, nvarsC1) );
3030 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
3031 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
3032
3033 /* to get the GUB lifting sequence, we first sort all variables in F, C2, and R
3034 * - F: non-increasing x*_j and non-increasing a_j in case of equality
3035 * - C2: non-increasing a_j
3036 * - R: non-increasing a_j
3037 * furthermore, sort C1 variables as needed for initializing the minweight table (non-increasing a_j).
3038 */
3039
3040 /* gets sorting key for variables in C1 corresponding to the following ordering
3041 * non-decreasing a_j, i.e. a_1 <= a_2 <= ... <= a_|C_1|
3042 */
3043 for( j = 0; j < nvarsC1; j++ )
3044 {
3045 /* gets sortkeys */
3046 sortkeysC1[j] = (SCIP_Real) weights[varsC1[j]];
3047
3048 /* update status of variable in its gub constraint */
3049 gubconsidx = gubset->gubconssidx[varsC1[j]];
3050 varidx = gubset->gubvarsidx[varsC1[j]];
3051 gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C1;
3052 }
3053
3054 /* gets sorting key for variables in F corresponding to the following ordering
3055 * non-increasing x*_j, i.e., x*_1 >= x*_2 >= ... >= x*_|F|, and
3056 * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|F| in case of equality
3057 * and updates status of each variable in F in GUB set data structure
3058 */
3059 for( j = 0; j < nvarsF; j++ )
3060 {
3061 /* update status of variable in its gub constraint */
3062 gubconsidx = gubset->gubconssidx[varsF[j]];
3063 varidx = gubset->gubvarsidx[varsF[j]];
3064 gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_F;
3065 }
3066
3067 /* gets sorting key for variables in C2 corresponding to the following ordering
3068 * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|C2|
3069 * and updates status of each variable in F in GUB set data structure
3070 */
3071 for( j = 0; j < nvarsC2; j++ )
3072 {
3073 /* gets sortkeys */
3074 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
3075
3076 /* update status of variable in its gub constraint */
3077 gubconsidx = gubset->gubconssidx[varsC2[j]];
3078 varidx = gubset->gubvarsidx[varsC2[j]];
3079 gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C2;
3080 }
3081
3082 /* gets sorting key for variables in R corresponding to the following ordering
3083 * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|R|
3084 * and updates status of each variable in F in GUB set data structure
3085 */
3086 for( j = 0; j < nvarsR; j++ )
3087 {
3088 /* gets sortkeys */
3089 sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
3090
3091 /* update status of variable in its gub constraint */
3092 gubconsidx = gubset->gubconssidx[varsR[j]];
3093 varidx = gubset->gubvarsidx[varsR[j]];
3094 gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_R;
3095 }
3096
3097 /* sorts C1, F, C2 and R */
3098 assert(nvarsC1 > 0);
3099 SCIPsortRealInt(sortkeysC1, varsC1, nvarsC1);
3100
3101 if( nvarsC2 > 0 )
3102 {
3103 SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
3104 }
3105 if( nvarsR > 0)
3106 {
3107 SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
3108 }
3109
3110 /* frees temporary memory */
3111 SCIPfreeBufferArray(scip, &sortkeysR);
3112 SCIPfreeBufferArray(scip, &sortkeysC2);
3113 SCIPfreeBufferArray(scip, &sortkeysC1);
3114
3115 /* allocate and initialize temporary memory for sorting GUB constraints */
3116 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1, ngubconss) );
3117 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1store, ngubconss) );
3118 SCIP_CALL( SCIPallocBufferArray(scip, &nC1varsingubcons, ngubconss) );
3119 BMSclearMemoryArray(nC1varsingubcons, ngubconss);
3120 for( i = 0; i < ngubconss; i++)
3121 {
3122 sortkeypairsGFC1[i] = &(sortkeypairsGFC1store[i]);
3123 sortkeypairsGFC1[i]->key1 = 0.0;
3124 sortkeypairsGFC1[i]->key2 = 0.0;
3125 }
3126 *ngubconsGC1 = 0;
3127 *ngubconsGC2 = 0;
3128 *ngubconsGFC1 = 0;
3129 *ngubconsGR = 0;
3130 *ngubconscapexceed = 0;
3131 *maxgubvarssize = 0;
3132
3133#ifndef NDEBUG
3134 for( i = 0; i < gubset->ngubconss; i++ )
3135 assert(gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL);
3136#endif
3137
3138 /* stores GUBs of group GC1 (GOC1+GNC1) and part of the GUBs of group GFC1 (GNC1 GUBs) and sorts variables in these GUBs
3139 * s.t. C1 variables come first (will automatically be sorted by non-decreasing weight).
3140 * gets sorting keys for GUBs of type GFC1 corresponding to the following ordering
3141 * non-increasing number of variables in F, and
3142 * non-increasing max{x*_k : k in GFC1_j} in case of equality
3143 */
3144 for( i = 0; i < nvarsC1; i++ )
3145 {
3146 int nvarsC1capexceed;
3147
3148 nvarsC1capexceed = 0;
3149
3150 var = varsC1[i];
3151 gubconsidx = gubset->gubconssidx[var];
3152 varidx = gubset->gubvarsidx[var];
3153
3154 assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3155 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C1);
3156
3157 /* current C1 variable is put to the front of its GUB where C1 part is stored by non-decreasing weigth;
3158 * note that variables in C1 are already sorted by non-decreasing weigth
3159 */
3160 targetvar = gubset->gubconss[gubconsidx]->gubvars[nC1varsingubcons[gubconsidx]];
3161 GUBsetSwapVars(scip, gubset, var, targetvar);
3162 nC1varsingubcons[gubconsidx]++;
3163
3164 /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3165 if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3166 {
3167 assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
3168 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3169 continue;
3170 }
3171
3172 /* determine the status of the current GUB constraint, GOC1 or GNC1; GUBs involving R variables are split into
3173 * GOC1/GNC1 and GF, if wanted. also update sorting key if GUB is of type GFC1 (GNC1)
3174 */
3175#if GUBSPLITGNC1GUBS
3176 gubconswithF = FALSE;
3177#endif
3178 for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3179 {
3180 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2);
3181
3182 /* C1-variable: update number of C1/capacity exceeding variables */
3183 if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_C1 )
3184 {
3185 nvarsC1capexceed++;
3186#ifndef NDEBUG
3187 nvarsprocessed++;
3188#endif
3189 }
3190 /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3191 else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3192 {
3193#if GUBSPLITGNC1GUBS
3194 gubconswithF = TRUE;
3195#endif
3196 sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3197
3198 if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3199 sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3200 }
3201 else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_CAPACITYEXCEEDED )
3202 {
3203 nvarsC1capexceed++;
3204 }
3205 else
3206 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_R);
3207 }
3208
3209 /* update set of GC1 GUBs */
3210 gubconsGC1[*ngubconsGC1] = gubconsidx;
3211 (*ngubconsGC1)++;
3212
3213 /* update maximum size of all GUB constraints */
3214 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3215 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3216
3217 /* set status of GC1-GUB (GOC1 or GNC1) and update set of GFC1 GUBs */
3218 if( nvarsC1capexceed == gubset->gubconss[gubconsidx]->ngubvars )
3219 {
3220 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3221 ngubconsGOC1++;
3222 }
3223 else
3224 {
3225#if GUBSPLITGNC1GUBS
3226 /* only variables in C1 and R -- no in F: GUB will be split into GR and GOC1 GUBs */
3227 if( !gubconswithF )
3228 {
3229 GUBVARSTATUS movevarstatus;
3230
3231 assert(gubset->ngubconss < gubset->nvars);
3232
3233 /* create a new GUB for GR part of splitting */
3234 SCIP_CALL( GUBconsCreate(scip, &gubset->gubconss[gubset->ngubconss]) );
3235 gubset->ngubconss++;
3236 ngubconss = gubset->ngubconss;
3237
3238 /* fill GR with R variables in current GUB */
3239 for( j = gubset->gubconss[gubconsidx]->ngubvars-1; j >= 0; j-- )
3240 {
3241 movevarstatus = gubset->gubconss[gubconsidx]->gubvarsstatus[j];
3242 if( movevarstatus != GUBVARSTATUS_BELONGSTOSET_C1 )
3243 {
3244 assert(movevarstatus == GUBVARSTATUS_BELONGSTOSET_R || movevarstatus == GUBVARSTATUS_CAPACITYEXCEEDED);
3245 SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, gubset->gubconss[gubconsidx]->gubvars[j],
3246 gubconsidx, ngubconss-1) );
3247 gubset->gubconss[ngubconss-1]->gubvarsstatus[gubset->gubconss[ngubconss-1]->ngubvars-1] =
3248 movevarstatus;
3249 }
3250 }
3251
3252 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3253 ngubconsGOC1++;
3254
3256 gubconsGR[*ngubconsGR] = ngubconss-1;
3257 (*ngubconsGR)++;
3258 }
3259 /* variables in C1, F, and maybe R: GNC1 GUB */
3260 else
3261 {
3262 assert(gubconswithF);
3263
3264 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3265 gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3266 (*ngubconsGFC1)++;
3267 }
3268#else
3269 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3270 gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3271 (*ngubconsGFC1)++;
3272#endif
3273 }
3274 }
3275
3276 /* stores GUBs of group GC2 (only trivial GUBs); sorting is not required because the C2 variables (which we loop over)
3277 * are already sorted correctly
3278 */
3279 for( i = 0; i < nvarsC2; i++ )
3280 {
3281 var = varsC2[i];
3282 gubconsidx = gubset->gubconssidx[var];
3283 varidx = gubset->gubvarsidx[var];
3284
3285 assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3286 assert(gubset->gubconss[gubconsidx]->ngubvars == 1);
3287 assert(varidx == 0);
3288 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C2);
3289 assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_UNINITIAL);
3290
3291 /* set status of GC2 GUB */
3292 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GC2;
3293
3294 /* update group of GC2 GUBs */
3295 gubconsGC2[*ngubconsGC2] = gubconsidx;
3296 (*ngubconsGC2)++;
3297
3298 /* update maximum size of all GUB constraints */
3299 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3300 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3301
3302#ifndef NDEBUG
3303 nvarsprocessed++;
3304#endif
3305 }
3306
3307 /* stores remaining part of the GUBs of group GFC1 (GF GUBs) and gets GUB sorting keys corresp. to following ordering
3308 * non-increasing number of variables in F, and
3309 * non-increasing max{x*_k : k in GFC1_j} in case of equality
3310 */
3311 for( i = 0; i < nvarsF; i++ )
3312 {
3313 var = varsF[i];
3314 gubconsidx = gubset->gubconssidx[var];
3315 varidx = gubset->gubvarsidx[var];
3316
3317 assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3318 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_F);
3319
3320#ifndef NDEBUG
3321 nvarsprocessed++;
3322#endif
3323
3324 /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3325 if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3326 {
3327 assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3328 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3329 continue;
3330 }
3331
3332 /* set status of GF GUB */
3333 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GF;
3334
3335 /* update sorting key of corresponding GFC1 GUB */
3336 for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3337 {
3338 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2
3339 && gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C1);
3340
3341 /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3342 if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3343 {
3344 sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3345
3346 if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3347 sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3348 }
3349 }
3350
3351 /* update set of GFC1 GUBs */
3352 gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3353 (*ngubconsGFC1)++;
3354
3355 /* update maximum size of all GUB constraints */
3356 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3357 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3358 }
3359
3360 /* stores GUBs of group GR; sorting is not required because the R variables (which we loop over) are already sorted
3361 * correctly
3362 */
3363 for( i = 0; i < nvarsR; i++ )
3364 {
3365 var = varsR[i];
3366 gubconsidx = gubset->gubconssidx[var];
3367 varidx = gubset->gubvarsidx[var];
3368
3369 assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3370 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_R);
3371
3372#ifndef NDEBUG
3373 nvarsprocessed++;
3374#endif
3375
3376 /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3377 if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3378 {
3379 assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR
3380 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3381 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3382 continue;
3383 }
3384
3385 /* set status of GR GUB */
3386 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GR;
3387
3388 /* update set of GR GUBs */
3389 gubconsGR[*ngubconsGR] = gubconsidx;
3390 (*ngubconsGR)++;
3391
3392 /* update maximum size of all GUB constraints */
3393 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3394 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3395 }
3396 assert(nvarsprocessed == nvarsC1 + nvarsC2 + nvarsF + nvarsR);
3397
3398 /* update number of GUBs with only capacity exceeding variables (will not be used for lifting) */
3399 (*ngubconscapexceed) = ngubconss - (ngubconsGOC1 + (*ngubconsGC2) + (*ngubconsGFC1) + (*ngubconsGR));
3400 assert(*ngubconscapexceed >= 0);
3401#ifndef NDEBUG
3402 {
3403 int check;
3404
3405 check = 0;
3406
3407 /* remaining not handled GUBs should only contain capacity exceeding variables */
3408 for( i = 0; i < ngubconss; i++ )
3409 {
3410 if( gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL )
3411 check++;
3412 }
3413 assert(check == *ngubconscapexceed);
3414 }
3415#endif
3416
3417 /* sort GFCI GUBs according to computed sorting keys */
3418 if( (*ngubconsGFC1) > 0 )
3419 {
3420 SCIPsortDownPtrInt((void**)sortkeypairsGFC1, gubconsGFC1, compSortkeypairs, (*ngubconsGFC1));
3421 }
3422
3423 /* free temporary memory */
3424#if GUBSPLITGNC1GUBS
3425 ngubconss = origngubconss;
3426#endif
3427 SCIPfreeBufferArray(scip, &nC1varsingubcons);
3428 SCIPfreeBufferArray(scip, &sortkeypairsGFC1store);
3429 SCIPfreeBufferArray(scip, &sortkeypairsGFC1);
3430
3431 return SCIP_OKAY;
3432}
3433
3434/** enlarges minweight table to at least the given length */
3435static
3437 SCIP* scip, /**< SCIP data structure */
3438 SCIP_Longint** minweightsptr, /**< pointer to minweights table */
3439 int* minweightslen, /**< pointer to store number of entries in minweights table (incl. z=0) */
3440 int* minweightssize, /**< pointer to current size of minweights table */
3441 int newlen /**< new length of minweights table */
3442 )
3443{
3444 int j;
3445
3446 assert(minweightsptr != NULL);
3447 assert(*minweightsptr != NULL);
3448 assert(minweightslen != NULL);
3449 assert(*minweightslen >= 0);
3450 assert(minweightssize != NULL);
3451 assert(*minweightssize >= 0);
3452
3453 if( newlen > *minweightssize )
3454 {
3455 int newsize;
3456
3457 /* reallocate table memory */
3458 newsize = SCIPcalcMemGrowSize(scip, newlen);
3459 SCIP_CALL( SCIPreallocBufferArray(scip, minweightsptr, newsize) );
3460 *minweightssize = newsize;
3461 }
3462 assert(newlen <= *minweightssize);
3463
3464 /* initialize new elements */
3465 for( j = *minweightslen; j < newlen; ++j )
3466 (*minweightsptr)[j] = SCIP_LONGINT_MAX;
3467 *minweightslen = newlen;
3468
3469 return SCIP_OKAY;
3470}
3471
3472/** lifts given inequality
3473 * sum_{j in M_1} x_j <= alpha_0
3474 * valid for
3475 * S^0 = { x in {0,1}^|M_1| : sum_{j in M_1} a_j x_j <= a_0 - sum_{j in M_2} a_j }
3476 * to a valid inequality
3477 * sum_{j in M_1} x_j + sum_{j in F} alpha_j x_j + sum_{j in M_2} alpha_j x_j + sum_{j in R} alpha_j x_j
3478 * <= alpha_0 + sum_{j in M_2} alpha_j
3479 * for
3480 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 };
3481 * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in M_2, and
3482 * sequential up-lifting for the variables in R; procedure can be used to strengthen minimal cover inequalities and
3483 * extended weight inequalities.
3484 */
3485static
3487 SCIP* scip, /**< SCIP data structure */
3488 SCIP_VAR** vars, /**< variables in knapsack constraint */
3489 int nvars, /**< number of variables in knapsack constraint */
3490 int ntightened, /**< number of variables with tightened upper bound */
3491 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3492 SCIP_Longint capacity, /**< capacity of knapsack */
3493 SCIP_Real* solvals, /**< solution values of all problem variables */
3494 int* varsM1, /**< variables in M_1 */
3495 int* varsM2, /**< variables in M_2 */
3496 int* varsF, /**< variables in F */
3497 int* varsR, /**< variables in R */
3498 int nvarsM1, /**< number of variables in M_1 */
3499 int nvarsM2, /**< number of variables in M_2 */
3500 int nvarsF, /**< number of variables in F */
3501 int nvarsR, /**< number of variables in R */
3502 int alpha0, /**< rights hand side of given valid inequality */
3503 int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3504 SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3505 int* liftrhs /**< pointer to store right hand side of the lifted valid inequality */
3506 )
3507{
3508 SCIP_Longint* minweights;
3509 SCIP_Real* sortkeys;
3510 SCIP_Longint fixedonesweight;
3511 int minweightssize;
3512 int minweightslen;
3513 int j;
3514 int w;
3515
3516 assert(scip != NULL);
3517 assert(vars != NULL);
3518 assert(nvars >= 0);
3519 assert(weights != NULL);
3520 assert(capacity >= 0);
3521 assert(solvals != NULL);
3522 assert(varsM1 != NULL);
3523 assert(varsM2 != NULL);
3524 assert(varsF != NULL);
3525 assert(varsR != NULL);
3526 assert(nvarsM1 >= 0 && nvarsM1 <= nvars - ntightened);
3527 assert(nvarsM2 >= 0 && nvarsM2 <= nvars - ntightened);
3528 assert(nvarsF >= 0 && nvarsF <= nvars - ntightened);
3529 assert(nvarsR >= 0 && nvarsR <= nvars - ntightened);
3530 assert(nvarsM1 + nvarsM2 + nvarsF + nvarsR == nvars - ntightened);
3531 assert(alpha0 >= 0);
3532 assert(liftcoefs != NULL);
3533 assert(cutact != NULL);
3534 assert(liftrhs != NULL);
3535
3536 /* allocates temporary memory */
3537 minweightssize = nvarsM1 + 1;
3538 SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
3539 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvarsM1) );
3540
3541 /* initializes data structures */
3542 BMSclearMemoryArray(liftcoefs, nvars);
3543 *cutact = 0.0;
3544
3545 /* sets lifting coefficient of variables in M1, sorts variables in M1 such that a_1 <= a_2 <= ... <= a_|M1|
3546 * and calculates activity of the current valid inequality
3547 */
3548 for( j = 0; j < nvarsM1; j++ )
3549 {
3550 assert(liftcoefs[varsM1[j]] == 0);
3551 liftcoefs[varsM1[j]] = 1;
3552 sortkeys[j] = (SCIP_Real) (weights[varsM1[j]]);
3553 (*cutact) += solvals[varsM1[j]];
3554 }
3555
3556 SCIPsortRealInt(sortkeys, varsM1, nvarsM1);
3557
3558 /* initializes (i = 1) the minweight table, defined as: minweights_i[w] =
3559 * min sum_{j in M_1} a_j x_j + sum_{k=1}^{i-1} a_{j_k} x_{j_k}
3560 * s.t. sum_{j in M_1} x_j + sum_{k=1}^{i-1} alpha_{j_k} x_{j_k} >= w
3561 * x_j in {0,1} for j in M_1 & {j_i,...,j_i-1},
3562 * for i = 1,...,t with t = |N\M1| and w = 0,...,|M1| + sum_{k=1}^{i-1} alpha_{j_k};
3563 */
3564 minweights[0] = 0;
3565 for( w = 1; w <= nvarsM1; w++ )
3566 minweights[w] = minweights[w-1] + weights[varsM1[w-1]];
3567 minweightslen = nvarsM1 + 1;
3568
3569 /* gets sum of weights of variables fixed to one, i.e. sum of weights of variables in M_2 */
3570 fixedonesweight = 0;
3571 for( j = 0; j < nvarsM2; j++ )
3572 fixedonesweight += weights[varsM2[j]];
3573 assert(fixedonesweight >= 0);
3574
3575 /* initializes right hand side of lifted valid inequality */
3576 *liftrhs = alpha0;
3577
3578 /* sequentially up-lifts all variables in F: */
3579 for( j = 0; j < nvarsF; j++ )
3580 {
3581 SCIP_Longint weight;
3582 int liftvar;
3583 int liftcoef;
3584 int z;
3585
3586 liftvar = varsF[j];
3587 weight = weights[liftvar];
3588 assert(liftvar >= 0 && liftvar < nvars);
3589 assert(SCIPisFeasGT(scip, solvals[liftvar], 0.0));
3590 assert(weight > 0);
3591
3592 /* knapsack problem is infeasible:
3593 * sets z = 0
3594 */
3595 if( capacity - fixedonesweight - weight < 0 )
3596 {
3597 z = 0;
3598 }
3599 /* knapsack problem is feasible:
3600 * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
3601 * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
3602 */
3603 else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
3604 {
3605 z = *liftrhs;
3606 }
3607 /* knapsack problem is feasible:
3608 * uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} }
3609 */
3610 else
3611 {
3612 int left;
3613 int right;
3614 int middle;
3615
3616 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
3617 left = 0;
3618 right = (*liftrhs) + 1;
3619 while( left < right - 1 )
3620 {
3621 middle = (left + right) / 2;
3622 assert(0 <= middle && middle < minweightslen);
3623 if( minweights[middle] <= capacity - fixedonesweight - weight )
3624 left = middle;
3625 else
3626 right = middle;
3627 }
3628 assert(left == right - 1);
3629 assert(0 <= left && left < minweightslen);
3630 assert(minweights[left] <= capacity - fixedonesweight - weight );
3631 assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
3632
3633 /* now z = left */
3634 z = left;
3635 assert(z <= *liftrhs);
3636 }
3637
3638 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3639 liftcoef = (*liftrhs) - z;
3640 liftcoefs[liftvar] = liftcoef;
3641 assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
3642
3643 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3644 if( liftcoef == 0 )
3645 continue;
3646
3647 /* updates activity of current valid inequality */
3648 (*cutact) += liftcoef * solvals[liftvar];
3649
3650 /* enlarges current minweight table:
3651 * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3652 * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3653 * and sets minweights_i[w] = infinity for
3654 * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3655 */
3656 SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3657
3658 /* updates minweight table: minweight_i+1[w] =
3659 * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3660 * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3661 */
3662 for( w = minweightslen - 1; w >= 0; w-- )
3663 {
3665 if( w < liftcoef )
3666 {
3667 min = MIN(minweights[w], weight);
3668 minweights[w] = min;
3669 }
3670 else
3671 {
3672 assert(w >= liftcoef);
3673 min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3674 minweights[w] = min;
3675 }
3676 }
3677 }
3678 assert(minweights[0] == 0);
3679
3680 /* sequentially down-lifts all variables in M_2: */
3681 for( j = 0; j < nvarsM2; j++ )
3682 {
3683 SCIP_Longint weight;
3684 int liftvar;
3685 int liftcoef;
3686 int left;
3687 int right;
3688 int middle;
3689 int z;
3690
3691 liftvar = varsM2[j];
3692 weight = weights[liftvar];
3693 assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
3694 assert(liftvar >= 0 && liftvar < nvars);
3695 assert(weight > 0);
3696
3697 /* uses binary search to find
3698 * z = max { w : 0 <= w <= |M_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
3699 */
3700 left = 0;
3701 right = minweightslen;
3702 while( left < right - 1 )
3703 {
3704 middle = (left + right) / 2;
3705 assert(0 <= middle && middle < minweightslen);
3706 if( minweights[middle] <= capacity - fixedonesweight + weight )
3707 left = middle;
3708 else
3709 right = middle;
3710 }
3711 assert(left == right - 1);
3712 assert(0 <= left && left < minweightslen);
3713 assert(minweights[left] <= capacity - fixedonesweight + weight );
3714 assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight + weight);
3715
3716 /* now z = left */
3717 z = left;
3718 assert(z >= *liftrhs);
3719
3720 /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
3721 liftcoef = z - (*liftrhs);
3722 liftcoefs[liftvar] = liftcoef;
3723 assert(liftcoef >= 0);
3724
3725 /* updates sum of weights of variables fixed to one */
3726 fixedonesweight -= weight;
3727
3728 /* updates right-hand side of current valid inequality */
3729 (*liftrhs) += liftcoef;
3730 assert(*liftrhs >= alpha0);
3731
3732 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3733 if( liftcoef == 0 )
3734 continue;
3735
3736 /* updates activity of current valid inequality */
3737 (*cutact) += liftcoef * solvals[liftvar];
3738
3739 /* enlarges current minweight table:
3740 * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3741 * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3742 * and sets minweights_i[w] = infinity for
3743 * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3744 */
3745 SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3746
3747 /* updates minweight table: minweight_i+1[w] =
3748 * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3749 * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3750 */
3751 for( w = minweightslen - 1; w >= 0; w-- )
3752 {
3754 if( w < liftcoef )
3755 {
3756 min = MIN(minweights[w], weight);
3757 minweights[w] = min;
3758 }
3759 else
3760 {
3761 assert(w >= liftcoef);
3762 min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3763 minweights[w] = min;
3764 }
3765 }
3766 }
3767 assert(fixedonesweight == 0);
3768 assert(*liftrhs >= alpha0);
3769
3770 /* sequentially up-lifts all variables in R: */
3771 for( j = 0; j < nvarsR; j++ )
3772 {
3773 SCIP_Longint weight;
3774 int liftvar;
3775 int liftcoef;
3776 int z;
3777
3778 liftvar = varsR[j];
3779 weight = weights[liftvar];
3780 assert(liftvar >= 0 && liftvar < nvars);
3781 assert(SCIPisFeasEQ(scip, solvals[liftvar], 0.0));
3782 assert(weight > 0);
3783 assert(capacity - weight >= 0);
3784 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
3785
3786 /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
3787 * if minweights_i[liftrhs] <= a_0 - a_{j_i}
3788 */
3789 if( minweights[*liftrhs] <= capacity - weight )
3790 {
3791 z = *liftrhs;
3792 }
3793 /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
3794 */
3795 else
3796 {
3797 int left;
3798 int right;
3799 int middle;
3800
3801 left = 0;
3802 right = (*liftrhs) + 1;
3803 while( left < right - 1)
3804 {
3805 middle = (left + right) / 2;
3806 assert(0 <= middle && middle < minweightslen);
3807 if( minweights[middle] <= capacity - weight )
3808 left = middle;
3809 else
3810 right = middle;
3811 }
3812 assert(left == right - 1);
3813 assert(0 <= left && left < minweightslen);
3814 assert(minweights[left] <= capacity - weight );
3815 assert(left == minweightslen - 1 || minweights[left+1] > capacity - weight);
3816
3817 /* now z = left */
3818 z = left;
3819 assert(z <= *liftrhs);
3820 }
3821
3822 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3823 liftcoef = (*liftrhs) - z;
3824 liftcoefs[liftvar] = liftcoef;
3825 assert(liftcoef >= 0 && liftcoef <= *liftrhs);
3826
3827 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3828 if( liftcoef == 0 )
3829 continue;
3830
3831 /* updates activity of current valid inequality */
3832 (*cutact) += liftcoef * solvals[liftvar];
3833
3834 /* updates minweight table: minweight_i+1[w] =
3835 * min{ minweight_i[w], a_{j_i}}, if w < alpha_j_i
3836 * min{ minweight_i[w], minweight_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3837 */
3838 for( w = *liftrhs; w >= 0; w-- )
3839 {
3841 if( w < liftcoef )
3842 {
3843 min = MIN(minweights[w], weight);
3844 minweights[w] = min;
3845 }
3846 else
3847 {
3848 assert(w >= liftcoef);
3849 min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3850 minweights[w] = min;
3851 }
3852 }
3853 }
3854
3855 /* frees temporary memory */
3856 SCIPfreeBufferArray(scip, &sortkeys);
3857 SCIPfreeBufferArray(scip, &minweights);
3858
3859 return SCIP_OKAY;
3860}
3861
3862/** adds two minweight values in a safe way, i.e,, ensures no overflow */
3863static
3865 SCIP_Longint val1, /**< first value to add */
3866 SCIP_Longint val2 /**< second value to add */
3867 )
3868{
3869 assert(val1 >= 0);
3870 assert(val2 >= 0);
3871
3872 if( val1 >= SCIP_LONGINT_MAX || val2 >= SCIP_LONGINT_MAX )
3873 return SCIP_LONGINT_MAX;
3874 else
3875 {
3876 assert(val1 <= SCIP_LONGINT_MAX - val2);
3877 return (val1 + val2);
3878 }
3879}
3880
3881/** computes minweights table for lifting with GUBs by combining unfished and fished tables */
3882static
3884 SCIP_Longint* minweights, /**< minweight table to compute */
3885 SCIP_Longint* finished, /**< given finished table */
3886 SCIP_Longint* unfinished, /**< given unfinished table */
3887 int minweightslen /**< length of minweight, finished, and unfinished tables */
3888 )
3889{
3890 int w1;
3891 int w2;
3892
3893 /* minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
3894 * note that finished and unfished arrays sorted by non-decreasing weight
3895 */
3896
3897 /* initialize minweight with w2 = 0 */
3898 w2 = 0;
3899 assert(unfinished[w2] == 0);
3900 for( w1 = 0; w1 < minweightslen; w1++ )
3901 minweights[w1] = finished[w1];
3902
3903 /* consider w2 = 1, ..., minweightslen-1 */
3904 for( w2 = 1; w2 < minweightslen; w2++ )
3905 {
3906 if( unfinished[w2] >= SCIP_LONGINT_MAX )
3907 break;
3908
3909 for( w1 = 0; w1 < minweightslen - w2; w1++ )
3910 {
3911 SCIP_Longint temp;
3912
3913 temp = safeAddMinweightsGUB(finished[w1], unfinished[w2]);
3914 if( temp <= minweights[w1+w2] )
3915 minweights[w1+w2] = temp;
3916 }
3917 }
3918}
3919
3920/** lifts given inequality
3921 * sum_{j in C_1} x_j <= alpha_0
3922 * valid for
3923 * S^0 = { x in {0,1}^|C_1| : sum_{j in C_1} a_j x_j <= a_0 - sum_{j in C_2} a_j;
3924 * sum_{j in Q_i} x_j <= 1, forall i in I }
3925 * to a valid inequality
3926 * sum_{j in C_1} x_j + sum_{j in F} alpha_j x_j + sum_{j in C_2} alpha_j x_j + sum_{j in R} alpha_j x_j
3927 * <= alpha_0 + sum_{j in C_2} alpha_j
3928 * for
3929 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0; sum_{j in Q_i} x_j <= 1, forall i in I };
3930 * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
3931 * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
3932 * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
3933 */
3934static
3936 SCIP* scip, /**< SCIP data structure */
3937 SCIP_GUBSET* gubset, /**< GUB set data structure */
3938 SCIP_VAR** vars, /**< variables in knapsack constraint */
3939 int ngubconscapexceed, /**< number of GUBs with only capacity exceeding variables */
3940 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3941 SCIP_Longint capacity, /**< capacity of knapsack */
3942 SCIP_Real* solvals, /**< solution values of all knapsack variables */
3943 int* gubconsGC1, /**< GUBs in GC1(GNC1+GOC1) */
3944 int* gubconsGC2, /**< GUBs in GC2 */
3945 int* gubconsGFC1, /**< GUBs in GFC1(GNC1+GF) */
3946 int* gubconsGR, /**< GUBs in GR */
3947 int ngubconsGC1, /**< number of GUBs in GC1(GNC1+GOC1) */
3948 int ngubconsGC2, /**< number of GUBs in GC2 */
3949 int ngubconsGFC1, /**< number of GUBs in GFC1(GNC1+GF) */
3950 int ngubconsGR, /**< number of GUBs in GR */
3951 int alpha0, /**< rights hand side of given valid inequality */
3952 int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3953 SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3954 int* liftrhs, /**< pointer to store right hand side of the lifted valid inequality */
3955 int maxgubvarssize /**< maximal size of GUB constraints */
3956 )
3957{
3958 SCIP_Longint* minweights;
3959 SCIP_Longint* finished;
3960 SCIP_Longint* unfinished;
3961 int* gubconsGOC1;
3962 int* gubconsGNC1;
3963 int* liftgubvars;
3964 SCIP_Longint fixedonesweight;
3965 SCIP_Longint weight;
3966 SCIP_Longint weightdiff1;
3967 SCIP_Longint weightdiff2;
3969 int minweightssize;
3970 int minweightslen;
3971 int nvars;
3972 int varidx;
3973 int liftgubconsidx;
3974 int liftvar;
3975 int sumliftcoef;
3976 int liftcoef;
3977 int ngubconsGOC1;
3978 int ngubconsGNC1;
3979 int left;
3980 int right;
3981 int middle;
3982 int nliftgubvars;
3983 int tmplen;
3984 int tmpsize;
3985 int j;
3986 int k;
3987 int w;
3988 int z;
3989#ifndef NDEBUG
3990 int ngubconss;
3991 int nliftgubC1;
3992
3993 assert(gubset != NULL);
3994 ngubconss = gubset->ngubconss;
3995#else
3996 assert(gubset != NULL);
3997#endif
3998
3999 nvars = gubset->nvars;
4000
4001 assert(scip != NULL);
4002 assert(vars != NULL);
4003 assert(nvars >= 0);
4004 assert(weights != NULL);
4005 assert(capacity >= 0);
4006 assert(solvals != NULL);
4007 assert(gubconsGC1 != NULL);
4008 assert(gubconsGC2 != NULL);
4009 assert(gubconsGFC1 != NULL);
4010 assert(gubconsGR != NULL);
4011 assert(ngubconsGC1 >= 0 && ngubconsGC1 <= ngubconss - ngubconscapexceed);
4012 assert(ngubconsGC2 >= 0 && ngubconsGC2 <= ngubconss - ngubconscapexceed);
4013 assert(ngubconsGFC1 >= 0 && ngubconsGFC1 <= ngubconss - ngubconscapexceed);
4014 assert(ngubconsGR >= 0 && ngubconsGR <= ngubconss - ngubconscapexceed);
4015 assert(alpha0 >= 0);
4016 assert(liftcoefs != NULL);
4017 assert(cutact != NULL);
4018 assert(liftrhs != NULL);
4019
4020 minweightssize = ngubconsGC1+1;
4021
4022 /* allocates temporary memory */
4023 SCIP_CALL( SCIPallocBufferArray(scip, &liftgubvars, maxgubvarssize) );
4024 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGOC1, ngubconsGC1) );
4025 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGNC1, ngubconsGC1) );
4026 SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
4027 SCIP_CALL( SCIPallocBufferArray(scip, &finished, minweightssize) );
4028 SCIP_CALL( SCIPallocBufferArray(scip, &unfinished, minweightssize) );
4029
4030 /* initializes data structures */
4031 BMSclearMemoryArray(liftcoefs, nvars);
4032 *cutact = 0.0;
4033
4034 /* gets GOC1 and GNC1 GUBs, sets lifting coefficient of variables in C1 and calculates activity of the current
4035 * valid inequality
4036 */
4037 ngubconsGOC1 = 0;
4038 ngubconsGNC1 = 0;
4039 for( j = 0; j < ngubconsGC1; j++ )
4040 {
4041 if( gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GOC1 )
4042 {
4043 gubconsGOC1[ngubconsGOC1] = gubconsGC1[j];
4044 ngubconsGOC1++;
4045 }
4046 else
4047 {
4048 assert(gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4049 gubconsGNC1[ngubconsGNC1] = gubconsGC1[j];
4050 ngubconsGNC1++;
4051 }
4052 for( k = 0; k < gubset->gubconss[gubconsGC1[j]]->ngubvars
4053 && gubset->gubconss[gubconsGC1[j]]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4054 {
4055 varidx = gubset->gubconss[gubconsGC1[j]]->gubvars[k];
4056 assert(varidx >= 0 && varidx < nvars);
4057 assert(liftcoefs[varidx] == 0);
4058
4059 liftcoefs[varidx] = 1;
4060 (*cutact) += solvals[varidx];
4061 }
4062 assert(k >= 1);
4063 }
4064 assert(ngubconsGOC1 + ngubconsGFC1 + ngubconsGC2 + ngubconsGR == ngubconss - ngubconscapexceed);
4065 assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4066
4067 /* initialize the minweight tables, defined as: for i = 1,...,m with m = |I| and w = 0,...,|gubconsGC1|;
4068 * - finished_i[w] =
4069 * min sum_{k = 1,2,...,i-1} sum_{j in Q_k} a_j x_j
4070 * s.t. sum_{k = 1,2,...,i-1} sum_{j in Q_k} alpha_j x_j >= w
4071 * sum_{j in Q_k} x_j <= 1
4072 * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4073 * - unfinished_i[w] =
4074 * min sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} a_j x_j
4075 * s.t. sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} x_j >= w
4076 * sum_{j in Q_k} x_j <= 1
4077 * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4078 * - minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
4079 */
4080
4081 /* initialize finished table; note that variables in GOC1 GUBs (includes C1 and capacity exceeding variables)
4082 * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4083 * GUBs in the group GCI are sorted by non-decreasing min{ a_k : k in GC1_j } where min{ a_k : k in GC1_j } always
4084 * comes from the first variable in the GUB
4085 */
4086 assert(ngubconsGOC1 <= ngubconsGC1);
4087 finished[0] = 0;
4088 for( w = 1; w <= ngubconsGOC1; w++ )
4089 {
4090 liftgubconsidx = gubconsGOC1[w-1];
4091
4092 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1);
4093 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4094
4095 varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4096
4097 assert(varidx >= 0 && varidx < nvars);
4098 assert(liftcoefs[varidx] == 1);
4099
4100 min = weights[varidx];
4101 finished[w] = finished[w-1] + min;
4102
4103#ifndef NDEBUG
4104 for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4105 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4106 {
4107 varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4108 assert(varidx >= 0 && varidx < nvars);
4109 assert(liftcoefs[varidx] == 1);
4110 assert(weights[varidx] >= min);
4111 }
4112#endif
4113 }
4114 for( w = ngubconsGOC1+1; w <= ngubconsGC1; w++ )
4115 finished[w] = SCIP_LONGINT_MAX;
4116
4117 /* initialize unfinished table; note that variables in GNC1 GUBs
4118 * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4119 * GUBs in the group GCI are sorted by non-decreasing min{ a_k : k in GC1_j } where min{ a_k : k in GC1_j } always
4120 * comes from the first variable in the GUB
4121 */
4122 assert(ngubconsGNC1 <= ngubconsGC1);
4123 unfinished[0] = 0;
4124 for( w = 1; w <= ngubconsGNC1; w++ )
4125 {
4126 liftgubconsidx = gubconsGNC1[w-1];
4127
4128 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4129 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4130
4131 varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4132
4133 assert(varidx >= 0 && varidx < nvars);
4134 assert(liftcoefs[varidx] == 1);
4135
4136 min = weights[varidx];
4137 unfinished[w] = unfinished[w-1] + min;
4138
4139#ifndef NDEBUG
4140 for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4141 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4142 {
4143 varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4144 assert(varidx >= 0 && varidx < nvars);
4145 assert(liftcoefs[varidx] == 1);
4146 assert(weights[varidx] >= min );
4147 }
4148#endif
4149 }
4150 for( w = ngubconsGNC1 + 1; w <= ngubconsGC1; w++ )
4151 unfinished[w] = SCIP_LONGINT_MAX;
4152
4153 /* initialize minweights table; note that variables in GC1 GUBs
4154 * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4155 * we can directly initialize minweights instead of computing it from finished and unfinished (which would be more time
4156 * consuming) because is it has to be build using weights from C1 only.
4157 */
4158 assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4159 minweights[0] = 0;
4160 for( w = 1; w <= ngubconsGC1; w++ )
4161 {
4162 liftgubconsidx = gubconsGC1[w-1];
4163
4164 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
4165 || gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4166 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4167
4168 varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4169
4170 assert(varidx >= 0 && varidx < nvars);
4171 assert(liftcoefs[varidx] == 1);
4172
4173 min = weights[varidx];
4174 minweights[w] = minweights[w-1] + min;
4175
4176#ifndef NDEBUG
4177 for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4178 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4179 {
4180 varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4181 assert(varidx >= 0 && varidx < nvars);
4182 assert(liftcoefs[varidx] == 1);
4183 assert(weights[varidx] >= min);
4184 }
4185#endif
4186 }
4187 minweightslen = ngubconsGC1 + 1;
4188
4189 /* gets sum of weights of variables fixed to one, i.e. sum of weights of C2 variables GC2 GUBs */
4190 fixedonesweight = 0;
4191 for( j = 0; j < ngubconsGC2; j++ )
4192 {
4193 varidx = gubset->gubconss[gubconsGC2[j]]->gubvars[0];
4194
4195 assert(gubset->gubconss[gubconsGC2[j]]->ngubvars == 1);
4196 assert(varidx >= 0 && varidx < nvars);
4197 assert(gubset->gubconss[gubconsGC2[j]]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4198
4199 fixedonesweight += weights[varidx];
4200 }
4201 assert(fixedonesweight >= 0);
4202
4203 /* initializes right hand side of lifted valid inequality */
4204 *liftrhs = alpha0;
4205
4206 /* sequentially up-lifts all variables in GFC1 GUBs */
4207 for( j = 0; j < ngubconsGFC1; j++ )
4208 {
4209 liftgubconsidx = gubconsGFC1[j];
4210 assert(liftgubconsidx >= 0 && liftgubconsidx < ngubconss);
4211
4212 /* GNC1 GUB: update unfinished table (remove current GUB, i.e., remove min weight of C1 vars in GUB) and
4213 * compute minweight table via updated unfinished table and aleady upto date finished table;
4214 */
4215 k = 0;
4216 if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4217 {
4218 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4219 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4220 assert(ngubconsGNC1 > 0);
4221
4222 /* get number of C1 variables of current GNC1 GUB and put them into array of variables in GUB that
4223 * are considered for the lifting, i.e., not capacity exceeding
4224 */
4225 for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars
4226 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4227 liftgubvars[k] = gubset->gubconss[liftgubconsidx]->gubvars[k];
4228 assert(k >= 1);
4229
4230 /* update unfinished table by removing current GNC1 GUB, i.e, remove C1 variable with minimal weight
4231 * unfinished[w] = MAX{unfinished[w], unfinished[w+1] - weight}, "weight" is the minimal weight of current GUB
4232 */
4233 weight = weights[liftgubvars[0]];
4234
4235 weightdiff2 = unfinished[ngubconsGNC1] - weight;
4236 unfinished[ngubconsGNC1] = SCIP_LONGINT_MAX;
4237 for( w = ngubconsGNC1-1; w >= 1; w-- )
4238 {
4239 weightdiff1 = weightdiff2;
4240 weightdiff2 = unfinished[w] - weight;
4241
4242 if( unfinished[w] < weightdiff1 )
4243 unfinished[w] = weightdiff1;
4244 else
4245 break;
4246 }
4247 ngubconsGNC1--;
4248
4249 /* computes minweights table by combining unfished and fished tables */
4250 computeMinweightsGUB(minweights, finished, unfinished, minweightslen);
4251 assert(minweights[0] == 0);
4252 }
4253 /* GF GUB: no update of unfinished table (and minweight table) required because GF GUBs have no C1 variables and
4254 * are therefore not in the unfinished table
4255 */
4256 else
4257 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4258
4259#ifndef NDEBUG
4260 nliftgubC1 = k;
4261#endif
4262 nliftgubvars = k;
4263 sumliftcoef = 0;
4264
4265 /* compute lifting coefficient of F and R variables in GNC1 and GF GUBs (C1 vars have already liftcoef 1) */
4266 for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4267 {
4268 if( gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_F
4269 || gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4270 {
4271 liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4272 weight = weights[liftvar];
4273 assert(weight > 0);
4274 assert(liftvar >= 0 && liftvar < nvars);
4275 assert(capacity - weight >= 0);
4276
4277 /* put variable into array of variables in GUB that are considered for the lifting,
4278 * i.e., not capacity exceeding
4279 */
4280 liftgubvars[nliftgubvars] = liftvar;
4281 nliftgubvars++;
4282
4283 /* knapsack problem is infeasible:
4284 * sets z = 0
4285 */
4286 if( capacity - fixedonesweight - weight < 0 )
4287 {
4288 z = 0;
4289 }
4290 /* knapsack problem is feasible:
4291 * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
4292 * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
4293 */
4294 else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
4295 {
4296 z = *liftrhs;
4297 }
4298 /* knapsack problem is feasible:
4299 * binary search to find z = max {w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i}}
4300 */
4301 else
4302 {
4303 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
4304 left = 0;
4305 right = (*liftrhs) + 1;
4306 while( left < right - 1 )
4307 {
4308 middle = (left + right) / 2;
4309 assert(0 <= middle && middle < minweightslen);
4310 if( minweights[middle] <= capacity - fixedonesweight - weight )
4311 left = middle;
4312 else
4313 right = middle;
4314 }
4315 assert(left == right - 1);
4316 assert(0 <= left && left < minweightslen);
4317 assert(minweights[left] <= capacity - fixedonesweight - weight);
4318 assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
4319
4320 /* now z = left */
4321 z = left;
4322 assert(z <= *liftrhs);
4323 }
4324
4325 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4326 liftcoef = (*liftrhs) - z;
4327 liftcoefs[liftvar] = liftcoef;
4328 assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4329
4330 /* updates activity of current valid inequality */
4331 (*cutact) += liftcoef * solvals[liftvar];
4332
4333 /* updates sum of all lifting coefficients in GUB */
4334 sumliftcoef += liftcoefs[liftvar];
4335 }
4336 else
4337 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4338 }
4339 /* at least one variable is in F or R (j = number of C1 variables in current GUB) */
4340 assert(nliftgubvars > nliftgubC1);
4341
4342 /* activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0
4343 * and finished and minweight table can be updated easily as only C1 variables need to be considered;
4344 * not needed for GF GUBs
4345 */
4346 if( sumliftcoef == 0 )
4347 {
4348 if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4349 {
4350 weight = weights[liftgubvars[0]];
4351 /* update finished table and minweights table by applying special case of
4352 * finished[w] = MIN{finished[w], finished[w-1] + weight}, "weight" is the minimal weight of current GUB
4353 * minweights[w] = MIN{minweights[w], minweights[w-1] + weight}, "weight" is the minimal weight of current GUB
4354 */
4355 for( w = minweightslen-1; w >= 1; w-- )
4356 {
4357 SCIP_Longint tmpval;
4358
4359 tmpval = safeAddMinweightsGUB(finished[w-1], weight);
4360 finished[w] = MIN(finished[w], tmpval);
4361
4362 tmpval = safeAddMinweightsGUB(minweights[w-1], weight);
4363 minweights[w] = MIN(minweights[w], tmpval);
4364 }
4365 }
4366 else
4367 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4368
4369 continue;
4370 }
4371
4372 /* enlarges current minweights tables(finished, unfinished, minweights):
4373 * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4374 * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4375 * and sets minweights_i[w] = infinity for
4376 * w = |gubconsGC1| + sum_{k=1,2,..,i-1}sum_{j in Q_k} alpha_j+1,..,|C1| + sum_{k=1,2,..,i}sum_{j in Q_k} alpha_j
4377 */
4378 tmplen = minweightslen; /* will be updated in enlargeMinweights() */
4379 tmpsize = minweightssize;
4380 SCIP_CALL( enlargeMinweights(scip, &unfinished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4381 tmplen = minweightslen;
4382 tmpsize = minweightssize;
4383 SCIP_CALL( enlargeMinweights(scip, &finished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4384 SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + sumliftcoef) );
4385
4386 /* update finished table and minweight table;
4387 * note that instead of computing minweight table from updated finished and updated unfinished table again
4388 * (for the lifting coefficient, we had to update unfinished table and compute minweight table), we here
4389 * only need to update the minweight table and the updated finished in the same way (i.e., computing for minweight
4390 * not needed because only finished table changed at this point and the change was "adding" one weight)
4391 *
4392 * update formular for minweight table is: minweight_i+1[w] =
4393 * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4394 * formular for finished table has the same pattern.
4395 */
4396 for( w = minweightslen-1; w >= 0; w-- )
4397 {
4398 SCIP_Longint minminweight;
4399 SCIP_Longint minfinished;
4400
4401 for( k = 0; k < nliftgubvars; k++ )
4402 {
4403 liftcoef = liftcoefs[liftgubvars[k]];
4404 weight = weights[liftgubvars[k]];
4405
4406 if( w < liftcoef )
4407 {
4408 minfinished = MIN(finished[w], weight);
4409 minminweight = MIN(minweights[w], weight);
4410
4411 finished[w] = minfinished;
4412 minweights[w] = minminweight;
4413 }
4414 else
4415 {
4416 SCIP_Longint tmpval;
4417
4418 assert(w >= liftcoef);
4419
4420 tmpval = safeAddMinweightsGUB(finished[w-liftcoef], weight);
4421 minfinished = MIN(finished[w], tmpval);
4422
4423 tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4424 minminweight = MIN(minweights[w], tmpval);
4425
4426 finished[w] = minfinished;
4427 minweights[w] = minminweight;
4428 }
4429 }
4430 }
4431 assert(minweights[0] == 0);
4432 }
4433 assert(ngubconsGNC1 == 0);
4434
4435 /* note: now the unfinished table no longer exists, i.e., it is "0, MAX, MAX, ..." and minweight equals to finished;
4436 * therefore, only work with minweight table from here on
4437 */
4438
4439 /* sequentially down-lifts C2 variables contained in trivial GC2 GUBs */
4440 for( j = 0; j < ngubconsGC2; j++ )
4441 {
4442 liftgubconsidx = gubconsGC2[j];
4443
4444 assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4445 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GC2);
4446 assert(gubset->gubconss[liftgubconsidx]->ngubvars == 1);
4447 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4448
4449 liftvar = gubset->gubconss[liftgubconsidx]->gubvars[0]; /* C2 GUBs contain only one variable */
4450 weight = weights[liftvar];
4451
4452 assert(liftvar >= 0 && liftvar < nvars);
4453 assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
4454 assert(weight > 0);
4455
4456 /* uses binary search to find
4457 * z = max { w : 0 <= w <= |C_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
4458 */
4459 left = 0;
4460 right = minweightslen;
4461 while( left < right - 1 )
4462 {
4463 middle = (left + right) / 2;
4464 assert(0 <= middle && middle < minweightslen);
4465 if( minweights[middle] <= capacity - fixedonesweight + weight )
4466 left = middle;
4467 else
4468 right = middle;
4469 }
4470 assert(left == right - 1);
4471 assert(0 <= left && left < minweightslen);
4472 assert(minweights[left] <= capacity - fixedonesweight + weight);
4473 assert(left == minweightslen - 1 || minweights[left + 1] > capacity - fixedonesweight + weight);
4474
4475 /* now z = left */
4476 z = left;
4477 assert(z >= *liftrhs);
4478
4479 /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
4480 liftcoef = z - (*liftrhs);
4481 liftcoefs[liftvar] = liftcoef;
4482 assert(liftcoef >= 0);
4483
4484 /* updates sum of weights of variables fixed to one */
4485 fixedonesweight -= weight;
4486
4487 /* updates right-hand side of current valid inequality */
4488 (*liftrhs) += liftcoef;
4489 assert(*liftrhs >= alpha0);
4490
4491 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
4492 if( liftcoef == 0 )
4493 continue;
4494
4495 /* updates activity of current valid inequality */
4496 (*cutact) += liftcoef * solvals[liftvar];
4497
4498 /* enlarges current minweight table:
4499 * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4500 * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4501 * and sets minweights_i[w] = infinity for
4502 * w = |C1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 , ... , |C1| + sum_{k=1,2,...,i}sum_{j in Q_k} alpha_j
4503 */
4504 SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
4505
4506 /* updates minweight table: minweight_i+1[w] =
4507 * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
4508 * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
4509 */
4510 for( w = minweightslen - 1; w >= 0; w-- )
4511 {
4512 if( w < liftcoef )
4513 {
4514 min = MIN(minweights[w], weight);
4515 minweights[w] = min;
4516 }
4517 else
4518 {
4519 SCIP_Longint tmpval;
4520
4521 assert(w >= liftcoef);
4522
4523 tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4524 min = MIN(minweights[w], tmpval);
4525 minweights[w] = min;
4526 }
4527 }
4528 }
4529 assert(fixedonesweight == 0);
4530 assert(*liftrhs >= alpha0);
4531
4532 /* sequentially up-lifts variables in GUB constraints in GR GUBs */
4533 for( j = 0; j < ngubconsGR; j++ )
4534 {
4535 liftgubconsidx = gubconsGR[j];
4536
4537 assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4538 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR);
4539
4540 sumliftcoef = 0;
4541 nliftgubvars = 0;
4542 for( k = 0; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4543 {
4544 if(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4545 {
4546 liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4547 weight = weights[liftvar];
4548 assert(weight > 0);
4549 assert(liftvar >= 0 && liftvar < nvars);
4550 assert(capacity - weight >= 0);
4551 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
4552
4553 /* put variable into array of variables in GUB that are considered for the lifting,
4554 * i.e., not capacity exceeding
4555 */
4556 liftgubvars[nliftgubvars] = liftvar;
4557 nliftgubvars++;
4558
4559 /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
4560 * if minweights_i[liftrhs] <= a_0 - a_{j_i}
4561 */
4562 if( minweights[*liftrhs] <= capacity - weight )
4563 {
4564 z = *liftrhs;
4565 }
4566 /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
4567 */
4568 else
4569 {
4570 left = 0;
4571 right = (*liftrhs) + 1;
4572 while( left < right - 1 )
4573 {
4574 middle = (left + right) / 2;
4575 assert(0 <= middle && middle < minweightslen);
4576 if( minweights[middle] <= capacity - weight )
4577 left = middle;
4578 else
4579 right = middle;
4580 }
4581 assert(left == right - 1);
4582 assert(0 <= left && left < minweightslen);
4583 assert(minweights[left] <= capacity - weight);
4584 assert(left == minweightslen - 1 || minweights[left + 1] > capacity - weight);
4585
4586 /* now z = left */
4587 z = left;
4588 assert(z <= *liftrhs);
4589 }
4590 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4591 liftcoef = (*liftrhs) - z;
4592 liftcoefs[liftvar] = liftcoef;
4593 assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4594
4595 /* updates activity of current valid inequality */
4596 (*cutact) += liftcoef * solvals[liftvar];
4597
4598 /* updates sum of all lifting coefficients in GUB */
4599 sumliftcoef += liftcoefs[liftvar];
4600 }
4601 else
4602 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4603 }
4604 assert(nliftgubvars >= 1); /* at least one variable is in R */
4605
4606 /* minweight table and activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0 */
4607 if( sumliftcoef == 0 )
4608 continue;
4609
4610 /* updates minweight table: minweight_i+1[w] =
4611 * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4612 */
4613 for( w = *liftrhs; w >= 0; w-- )
4614 {
4615 for( k = 0; k < nliftgubvars; k++ )
4616 {
4617 liftcoef = liftcoefs[liftgubvars[k]];
4618 weight = weights[liftgubvars[k]];
4619
4620 if( w < liftcoef )
4621 {
4622 min = MIN(minweights[w], weight);
4623 minweights[w] = min;
4624 }
4625 else
4626 {
4627 SCIP_Longint tmpval;
4628
4629 assert(w >= liftcoef);
4630
4631 tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4632 min = MIN(minweights[w], tmpval);
4633 minweights[w] = min;
4634 }
4635 }
4636 }
4637 assert(minweights[0] == 0);
4638 }
4639
4640 /* frees temporary memory */
4641 SCIPfreeBufferArray(scip, &minweights);
4642 SCIPfreeBufferArray(scip, &finished);
4643 SCIPfreeBufferArray(scip, &unfinished);
4644 SCIPfreeBufferArray(scip, &liftgubvars);
4645 SCIPfreeBufferArray(scip, &gubconsGOC1 );
4646 SCIPfreeBufferArray(scip, &gubconsGNC1);
4647
4648 return SCIP_OKAY;
4649}
4650
4651/** lifts given minimal cover inequality
4652 * \f[
4653 * \sum_{j \in C} x_j \leq |C| - 1
4654 * \f]
4655 * valid for
4656 * \f[
4657 * S^0 = \{ x \in {0,1}^{|C|} : \sum_{j \in C} a_j x_j \leq a_0 \}
4658 * \f]
4659 * to a valid inequality
4660 * \f[
4661 * \sum_{j \in C} x_j + \sum_{j \in N \setminus C} \alpha_j x_j \leq |C| - 1
4662 * \f]
4663 * for
4664 * \f[
4665 * S = \{ x \in {0,1}^{|N|} : \sum_{j \in N} a_j x_j \leq a_0 \};
4666 * \f]
4667 * uses superadditive up-lifting for the variables in \f$N \setminus C\f$.
4668 */
4669static
4671 SCIP* scip, /**< SCIP data structure */
4672 SCIP_VAR** vars, /**< variables in knapsack constraint */
4673 int nvars, /**< number of variables in knapsack constraint */
4674 int ntightened, /**< number of variables with tightened upper bound */
4675 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4676 SCIP_Longint capacity, /**< capacity of knapsack */
4677 SCIP_Real* solvals, /**< solution values of all problem variables */
4678 int* covervars, /**< cover variables */
4679 int* noncovervars, /**< noncover variables */
4680 int ncovervars, /**< number of cover variables */
4681 int nnoncovervars, /**< number of noncover variables */
4682 SCIP_Longint coverweight, /**< weight of cover */
4683 SCIP_Real* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
4684 SCIP_Real* cutact /**< pointer to store activity of lifted valid inequality */
4685 )
4686{
4687 SCIP_Longint* maxweightsums;
4688 SCIP_Longint* intervalends;
4689 SCIP_Longint* rhos;
4690 SCIP_Real* sortkeys;
4691 SCIP_Longint lambda;
4692 int j;
4693 int h;
4694
4695 assert(scip != NULL);
4696 assert(vars != NULL);
4697 assert(nvars >= 0);
4698 assert(weights != NULL);
4699 assert(capacity >= 0);
4700 assert(solvals != NULL);
4701 assert(covervars != NULL);
4702 assert(noncovervars != NULL);
4703 assert(ncovervars > 0 && ncovervars <= nvars);
4704 assert(nnoncovervars >= 0 && nnoncovervars <= nvars - ntightened);
4705 assert(ncovervars + nnoncovervars == nvars - ntightened);
4706 assert(liftcoefs != NULL);
4707 assert(cutact != NULL);
4708
4709 /* allocates temporary memory */
4710 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, ncovervars) );
4711 SCIP_CALL( SCIPallocBufferArray(scip, &maxweightsums, ncovervars + 1) );
4712 SCIP_CALL( SCIPallocBufferArray(scip, &intervalends, ncovervars) );
4713 SCIP_CALL( SCIPallocBufferArray(scip, &rhos, ncovervars) );
4714
4715 /* initializes data structures */
4716 BMSclearMemoryArray(liftcoefs, nvars);
4717 *cutact = 0.0;
4718
4719 /* sets lifting coefficient of variables in C, sorts variables in C such that a_1 >= a_2 >= ... >= a_|C|
4720 * and calculates activity of current valid inequality
4721 */
4722 for( j = 0; j < ncovervars; j++ )
4723 {
4724 assert(liftcoefs[covervars[j]] == 0.0);
4725 liftcoefs[covervars[j]] = 1.0;
4726 sortkeys[j] = (SCIP_Real) weights[covervars[j]];
4727 (*cutact) += solvals[covervars[j]];
4728 }
4729 SCIPsortDownRealInt(sortkeys, covervars, ncovervars);
4730
4731 /* calculates weight excess of cover C */
4732 lambda = coverweight - capacity;
4733 assert(lambda > 0);
4734
4735 /* calculates A_h for h = 0,...,|C|, I_h for h = 1,...,|C| and rho_h for h = 1,...,|C| */
4736 maxweightsums[0] = 0;
4737 for( h = 1; h <= ncovervars; h++ )
4738 {
4739 maxweightsums[h] = maxweightsums[h-1] + weights[covervars[h-1]];
4740 intervalends[h-1] = maxweightsums[h] - lambda;
4741 rhos[h-1] = MAX(0, weights[covervars[h-1]] - weights[covervars[0]] + lambda);
4742 }
4743
4744 /* sorts variables in N\C such that a_{j_1} <= a_{j_2} <= ... <= a_{j_t} */
4745 for( j = 0; j < nnoncovervars; j++ )
4746 sortkeys[j] = (SCIP_Real) (weights[noncovervars[j]]);
4747 SCIPsortRealInt(sortkeys, noncovervars, nnoncovervars);
4748
4749 /* calculates lifting coefficient for all variables in N\C */
4750 h = 0;
4751 for( j = 0; j < nnoncovervars; j++ )
4752 {
4753 int liftvar;
4754 SCIP_Longint weight;
4755 SCIP_Real liftcoef;
4756
4757 liftvar = noncovervars[j];
4758 weight = weights[liftvar];
4759
4760 while( intervalends[h] < weight )
4761 h++;
4762
4763 if( h == 0 )
4764 liftcoef = h;
4765 else
4766 {
4767 if( weight <= intervalends[h-1] + rhos[h] )
4768 {
4769 SCIP_Real tmp1;
4770 SCIP_Real tmp2;
4771 tmp1 = (SCIP_Real) (intervalends[h-1] + rhos[h] - weight);
4772 tmp2 = (SCIP_Real) rhos[1];
4773 liftcoef = h - ( tmp1 / tmp2 );
4774 }
4775 else
4776 liftcoef = h;
4777 }
4778
4779 /* sets lifting coefficient */
4780 assert(liftcoefs[liftvar] == 0.0);
4781 liftcoefs[liftvar] = liftcoef;
4782
4783 /* updates activity of current valid inequality */
4784 (*cutact) += liftcoef * solvals[liftvar];
4785 }
4786
4787 /* frees temporary memory */
4788 SCIPfreeBufferArray(scip, &rhos);
4789 SCIPfreeBufferArray(scip, &intervalends);
4790 SCIPfreeBufferArray(scip, &maxweightsums);
4791 SCIPfreeBufferArray(scip, &sortkeys);
4792
4793 return SCIP_OKAY;
4794}
4795
4796
4797/** separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information, if wanted, for
4798 * given knapsack problem
4799*/
4800static
4802 SCIP* scip, /**< SCIP data structure */
4803 SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
4804 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
4805 SCIP_VAR** vars, /**< variables in knapsack constraint */
4806 int nvars, /**< number of variables in knapsack constraint */
4807 int ntightened, /**< number of variables with tightened upper bound */
4808 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4809 SCIP_Longint capacity, /**< capacity of knapsack */
4810 SCIP_Real* solvals, /**< solution values of all problem variables */
4811 int* mincovervars, /**< mincover variables */
4812 int* nonmincovervars, /**< nonmincover variables */
4813 int nmincovervars, /**< number of mincover variables */
4814 int nnonmincovervars, /**< number of nonmincover variables */
4815 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
4816 SCIP_GUBSET* gubset, /**< GUB set data structure, NULL if no GUB information should be used */
4817 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
4818 int* ncuts /**< pointer to add up the number of found cuts */
4819 )
4820{
4821 int* varsC1;
4822 int* varsC2;
4823 int* varsF;
4824 int* varsR;
4825 int nvarsC1;
4826 int nvarsC2;
4827 int nvarsF;
4828 int nvarsR;
4829 SCIP_Real cutact;
4830 int* liftcoefs;
4831 int liftrhs;
4832
4833 assert( cutoff != NULL );
4834 *cutoff = FALSE;
4835
4836 /* allocates temporary memory */
4841 SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
4842
4843 /* gets partition (C_1,C_2) of C, i.e. C_1 & C_2 = C and C_1 cap C_2 = emptyset, with C_1 not empty; chooses partition
4844 * as follows
4845 * C_2 = { j in C : x*_j = 1 } and
4846 * C_1 = C\C_2
4847 */
4848 getPartitionCovervars(scip, solvals, mincovervars, nmincovervars, varsC1, varsC2, &nvarsC1, &nvarsC2);
4849 assert(nvarsC1 + nvarsC2 == nmincovervars);
4850 assert(nmincovervars > 0);
4851 assert(nvarsC1 >= 0); /* nvarsC1 > 0 does not always hold, because relaxed knapsack conss may already be violated */
4852
4853 /* changes partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one variable from C2 to C1 */
4854 if( nvarsC1 < 2 && nvarsC2 > 0)
4855 {
4856 SCIP_CALL( changePartitionCovervars(scip, weights, varsC1, varsC2, &nvarsC1, &nvarsC2) );
4857 assert(nvarsC1 >= 1);
4858 }
4859 assert(nvarsC2 == 0 || nvarsC1 >= 1);
4860
4861 /* gets partition (F,R) of N\C, i.e. F & R = N\C and F cap R = emptyset; chooses partition as follows
4862 * R = { j in N\C : x*_j = 0 } and
4863 * F = (N\C)\F
4864 */
4865 getPartitionNoncovervars(scip, solvals, nonmincovervars, nnonmincovervars, varsF, varsR, &nvarsF, &nvarsR);
4866 assert(nvarsF + nvarsR == nnonmincovervars);
4867 assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4868
4869 /* lift cuts without GUB information */
4870 if( gubset == NULL )
4871 {
4872 /* sorts variables in F, C_2, R according to the second level lifting sequence that will be used in the sequential
4873 * lifting procedure
4874 */
4875 SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsC2, varsR, nvarsF, nvarsC2, nvarsR) );
4876
4877 /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4878 *
4879 * S^0 = { x in {0,1}^|C_1| : sum_{j in C_1} a_j x_j <= a_0 - sum_{j in C_2} a_j }
4880 *
4881 * to a valid inequality sum_{j in C_1} x_j + sum_{j in N\C_1} alpha_j x_j <= |C_1| - 1 + sum_{j in C_2} alpha_j for
4882 *
4883 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
4884 *
4885 * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in C_2 and sequential
4886 * up-lifting for the variables in R according to the second level lifting sequence
4887 */
4888 SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsC1, varsC2,
4889 varsF, varsR, nvarsC1, nvarsC2, nvarsF, nvarsR, nvarsC1 - 1, liftcoefs, &cutact, &liftrhs) );
4890 }
4891 /* lift cuts with GUB information */
4892 else
4893 {
4894 int* gubconsGC1;
4895 int* gubconsGC2;
4896 int* gubconsGFC1;
4897 int* gubconsGR;
4898 int ngubconsGC1;
4899 int ngubconsGC2;
4900 int ngubconsGFC1;
4901 int ngubconsGR;
4902 int ngubconss;
4903 int nconstightened;
4904 int maxgubvarssize;
4905
4906 assert(nvars == gubset->nvars);
4907
4908 ngubconsGC1 = 0;
4909 ngubconsGC2 = 0;
4910 ngubconsGFC1 = 0;
4911 ngubconsGR = 0;
4912 ngubconss = gubset->ngubconss;
4913 nconstightened = 0;
4914 maxgubvarssize = 0;
4915
4916 /* allocates temporary memory */
4917 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC1, ngubconss) );
4918 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC2, ngubconss) );
4919 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGFC1, ngubconss) );
4921
4922 /* categorizies GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of
4923 * the GUBs for the sequential GUB wise lifting procedure
4924 */
4925 SCIP_CALL( getLiftingSequenceGUB(scip, gubset, solvals, weights, varsC1, varsC2, varsF, varsR, nvarsC1,
4926 nvarsC2, nvarsF, nvarsR, gubconsGC1, gubconsGC2, gubconsGFC1, gubconsGR, &ngubconsGC1, &ngubconsGC2,
4927 &ngubconsGFC1, &ngubconsGR, &nconstightened, &maxgubvarssize) );
4928
4929 /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4930 *
4931 * S^0 = { x in {0,1}^|C_1| : sum_{j in C_1} a_j x_j <= a_0 - sum_{j in C_2} a_j,
4932 * sum_{j in Q_i} x_j <= 1, forall i in I }
4933 *
4934 * to a valid inequality sum_{j in C_1} x_j + sum_{j in N\C_1} alpha_j x_j <= |C_1| - 1 + sum_{j in C_2} alpha_j for
4935 *
4936 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0, sum_{j in Q_i} x_j <= 1, forall i in I },
4937 *
4938 * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
4939 * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
4940 * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
4941 */
4942 SCIP_CALL( sequentialUpAndDownLiftingGUB(scip, gubset, vars, nconstightened, weights, capacity, solvals, gubconsGC1,
4943 gubconsGC2, gubconsGFC1, gubconsGR, ngubconsGC1, ngubconsGC2, ngubconsGFC1, ngubconsGR,
4944 MIN(nvarsC1 - 1, ngubconsGC1), liftcoefs, &cutact, &liftrhs, maxgubvarssize) );
4945
4946 /* frees temporary memory */
4947 SCIPfreeBufferArray(scip, &gubconsGR);
4948 SCIPfreeBufferArray(scip, &gubconsGFC1);
4949 SCIPfreeBufferArray(scip, &gubconsGC2);
4950 SCIPfreeBufferArray(scip, &gubconsGC1);
4951 }
4952
4953 /* checks if lifting yielded a violated cut */
4954 if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
4955 {
4956 SCIP_ROW* row;
4957 char name[SCIP_MAXSTRLEN];
4958 int j;
4959
4960 /* creates LP row */
4961 assert( cons == NULL || sepa == NULL );
4962 if ( cons != NULL )
4963 {
4965 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
4966 cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
4967 cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
4968 }
4969 else if ( sepa != NULL )
4970 {
4971 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
4972 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4973 }
4974 else
4975 {
4976 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcseq_%d", *ncuts);
4978 }
4979
4980 /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
4982 assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4983 for( j = 0; j < nvarsC1; j++ )
4984 {
4985 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC1[j]], 1.0) );
4986 }
4987 for( j = 0; j < nvarsC2; j++ )
4988 {
4989 if( liftcoefs[varsC2[j]] > 0 )
4990 {
4991 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC2[j]], (SCIP_Real)liftcoefs[varsC2[j]]) );
4992 }
4993 }
4994 for( j = 0; j < nvarsF; j++ )
4995 {
4996 if( liftcoefs[varsF[j]] > 0 )
4997 {
4998 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
4999 }
5000 }
5001 for( j = 0; j < nvarsR; j++ )
5002 {
5003 if( liftcoefs[varsR[j]] > 0 )
5004 {
5005 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
5006 }
5007 }
5009
5010 /* checks if cut is violated enough */
5011 if( SCIPisCutEfficacious(scip, sol, row) )
5012 {
5013 if( cons != NULL )
5014 {
5016 }
5017 SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5018 (*ncuts)++;
5019 }
5020 SCIP_CALL( SCIPreleaseRow(scip, &row) );
5021 }
5022
5023 /* frees temporary memory */
5024 SCIPfreeBufferArray(scip, &liftcoefs);
5025 SCIPfreeBufferArray(scip, &varsR);
5026 SCIPfreeBufferArray(scip, &varsF);
5027 SCIPfreeBufferArray(scip, &varsC2);
5028 SCIPfreeBufferArray(scip, &varsC1);
5029
5030 return SCIP_OKAY;
5031}
5032
5033/** separates lifted extended weight inequalities using sequential up- and down-lifting for given knapsack problem */
5034static
5036 SCIP* scip, /**< SCIP data structure */
5037 SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5038 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5039 SCIP_VAR** vars, /**< variables in knapsack constraint */
5040 int nvars, /**< number of variables in knapsack constraint */
5041 int ntightened, /**< number of variables with tightened upper bound */
5042 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5043 SCIP_Longint capacity, /**< capacity of knapsack */
5044 SCIP_Real* solvals, /**< solution values of all problem variables */
5045 int* feassetvars, /**< variables in feasible set */
5046 int* nonfeassetvars, /**< variables not in feasible set */
5047 int nfeassetvars, /**< number of variables in feasible set */
5048 int nnonfeassetvars, /**< number of variables not in feasible set */
5049 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5050 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5051 int* ncuts /**< pointer to add up the number of found cuts */
5052 )
5053{
5054 int* varsT1;
5055 int* varsT2;
5056 int* varsF;
5057 int* varsR;
5058 int* liftcoefs;
5059 SCIP_Real cutact;
5060 int nvarsT1;
5061 int nvarsT2;
5062 int nvarsF;
5063 int nvarsR;
5064 int liftrhs;
5065 int j;
5066
5067 assert( cutoff != NULL );
5068 *cutoff = FALSE;
5069
5070 /* allocates temporary memory */
5075 SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
5076
5077 /* gets partition (T_1,T_2) of T, i.e. T_1 & T_2 = T and T_1 cap T_2 = emptyset, with T_1 not empty; chooses partition
5078 * as follows
5079 * T_2 = { j in T : x*_j = 1 } and
5080 * T_1 = T\T_2
5081 */
5082 getPartitionCovervars(scip, solvals, feassetvars, nfeassetvars, varsT1, varsT2, &nvarsT1, &nvarsT2);
5083 assert(nvarsT1 + nvarsT2 == nfeassetvars);
5084
5085 /* changes partition (T_1,T_2) of feasible set T, if |T1| = 0, by moving one variable from T2 to T1 */
5086 if( nvarsT1 == 0 && nvarsT2 > 0)
5087 {
5088 SCIP_CALL( changePartitionFeasiblesetvars(scip, weights, varsT1, varsT2, &nvarsT1, &nvarsT2) );
5089 assert(nvarsT1 == 1);
5090 }
5091 assert(nvarsT2 == 0 || nvarsT1 > 0);
5092
5093 /* gets partition (F,R) of N\T, i.e. F & R = N\T and F cap R = emptyset; chooses partition as follows
5094 * R = { j in N\T : x*_j = 0 } and
5095 * F = (N\T)\F
5096 */
5097 getPartitionNoncovervars(scip, solvals, nonfeassetvars, nnonfeassetvars, varsF, varsR, &nvarsF, &nvarsR);
5098 assert(nvarsF + nvarsR == nnonfeassetvars);
5099 assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5100
5101 /* sorts variables in F, T_2, and R according to the second level lifting sequence that will be used in the sequential
5102 * lifting procedure (the variable removed last from the initial cover does not have to be lifted first, therefore it
5103 * is included in the sorting routine)
5104 */
5105 SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsT2, varsR, nvarsF, nvarsT2, nvarsR) );
5106
5107 /* lifts extended weight inequality sum_{j in T_1} x_j <= |T_1| valid for
5108 *
5109 * S^0 = { x in {0,1}^|T_1| : sum_{j in T_1} a_j x_j <= a_0 - sum_{j in T_2} a_j }
5110 *
5111 * to a valid inequality sum_{j in T_1} x_j + sum_{j in N\T_1} alpha_j x_j <= |T_1| + sum_{j in T_2} alpha_j for
5112 *
5113 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5114 *
5115 * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in T_2 and sequential
5116 * up-lifting for the variabels in R according to the second level lifting sequence
5117 */
5118 SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsT1, varsT2, varsF, varsR,
5119 nvarsT1, nvarsT2, nvarsF, nvarsR, nvarsT1, liftcoefs, &cutact, &liftrhs) );
5120
5121 /* checks if lifting yielded a violated cut */
5122 if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5123 {
5124 SCIP_ROW* row;
5125 char name[SCIP_MAXSTRLEN];
5126
5127 /* creates LP row */
5128 assert( cons == NULL || sepa == NULL );
5129 if( cons != NULL )
5130 {
5133 cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5134 cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5135 }
5136 else if ( sepa != NULL )
5137 {
5138 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5139 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5140 }
5141 else
5142 {
5143 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_ewseq_%d", *ncuts);
5145 }
5146
5147 /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5149 assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5150 for( j = 0; j < nvarsT1; j++ )
5151 {
5152 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT1[j]], 1.0) );
5153 }
5154 for( j = 0; j < nvarsT2; j++ )
5155 {
5156 if( liftcoefs[varsT2[j]] > 0 )
5157 {
5158 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT2[j]], (SCIP_Real)liftcoefs[varsT2[j]]) );
5159 }
5160 }
5161 for( j = 0; j < nvarsF; j++ )
5162 {
5163 if( liftcoefs[varsF[j]] > 0 )
5164 {
5165 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
5166 }
5167 }
5168 for( j = 0; j < nvarsR; j++ )
5169 {
5170 if( liftcoefs[varsR[j]] > 0 )
5171 {
5172 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
5173 }
5174 }
5176
5177 /* checks if cut is violated enough */
5178 if( SCIPisCutEfficacious(scip, sol, row) )
5179 {
5180 if( cons != NULL )
5181 {
5183 }
5184 SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5185 (*ncuts)++;
5186 }
5187 SCIP_CALL( SCIPreleaseRow(scip, &row) );
5188 }
5189
5190 /* frees temporary memory */
5191 SCIPfreeBufferArray(scip, &liftcoefs);
5192 SCIPfreeBufferArray(scip, &varsR);
5193 SCIPfreeBufferArray(scip, &varsF);
5194 SCIPfreeBufferArray(scip, &varsT2);
5195 SCIPfreeBufferArray(scip, &varsT1);
5196
5197 return SCIP_OKAY;
5198}
5199
5200/** separates lifted minimal cover inequalities using superadditive up-lifting for given knapsack problem */
5201static
5203 SCIP* scip, /**< SCIP data structure */
5204 SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5205 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5206 SCIP_VAR** vars, /**< variables in knapsack constraint */
5207 int nvars, /**< number of variables in knapsack constraint */
5208 int ntightened, /**< number of variables with tightened upper bound */
5209 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5210 SCIP_Longint capacity, /**< capacity of knapsack */
5211 SCIP_Real* solvals, /**< solution values of all problem variables */
5212 int* mincovervars, /**< mincover variables */
5213 int* nonmincovervars, /**< nonmincover variables */
5214 int nmincovervars, /**< number of mincover variables */
5215 int nnonmincovervars, /**< number of nonmincover variables */
5216 SCIP_Longint mincoverweight, /**< weight of minimal cover */
5217 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5218 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5219 int* ncuts /**< pointer to add up the number of found cuts */
5220 )
5221{
5222 SCIP_Real* realliftcoefs;
5223 SCIP_Real cutact;
5224 int liftrhs;
5225
5226 assert( cutoff != NULL );
5227 *cutoff = FALSE;
5228 cutact = 0.0;
5229
5230 /* allocates temporary memory */
5231 SCIP_CALL( SCIPallocBufferArray(scip, &realliftcoefs, nvars) );
5232
5233 /* lifts minimal cover inequality sum_{j in C} x_j <= |C| - 1 valid for
5234 *
5235 * S^0 = { x in {0,1}^|C| : sum_{j in C} a_j x_j <= a_0 }
5236 *
5237 * to a valid inequality sum_{j in C} x_j + sum_{j in N\C} alpha_j x_j <= |C| - 1 for
5238 *
5239 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5240 *
5241 * uses superadditive up-lifting for the variables in N\C.
5242 */
5243 SCIP_CALL( superadditiveUpLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, mincovervars,
5244 nonmincovervars, nmincovervars, nnonmincovervars, mincoverweight, realliftcoefs, &cutact) );
5245 liftrhs = nmincovervars - 1;
5246
5247 /* checks if lifting yielded a violated cut */
5248 if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5249 {
5250 SCIP_ROW* row;
5251 char name[SCIP_MAXSTRLEN];
5252 int j;
5253
5254 /* creates LP row */
5255 assert( cons == NULL || sepa == NULL );
5256 if ( cons != NULL )
5257 {
5260 cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5261 cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5262 }
5263 else if ( sepa != NULL )
5264 {
5265 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5266 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5267 }
5268 else
5269 {
5270 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcsup_%d", *ncuts);
5272 }
5273
5274 /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5276 assert(nmincovervars + nnonmincovervars == nvars - ntightened);
5277 for( j = 0; j < nmincovervars; j++ )
5278 {
5279 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[mincovervars[j]], 1.0) );
5280 }
5281 for( j = 0; j < nnonmincovervars; j++ )
5282 {
5283 assert(SCIPisFeasGE(scip, realliftcoefs[nonmincovervars[j]], 0.0));
5284 if( SCIPisFeasGT(scip, realliftcoefs[nonmincovervars[j]], 0.0) )
5285 {
5286 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[nonmincovervars[j]], realliftcoefs[nonmincovervars[j]]) );
5287 }
5288 }
5290
5291 /* checks if cut is violated enough */
5292 if( SCIPisCutEfficacious(scip, sol, row) )
5293 {
5294 if( cons != NULL )
5295 {
5297 }
5298 SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5299 (*ncuts)++;
5300 }
5301 SCIP_CALL( SCIPreleaseRow(scip, &row) );
5302 }
5303
5304 /* frees temporary memory */
5305 SCIPfreeBufferArray(scip, &realliftcoefs);
5306
5307 return SCIP_OKAY;
5308}
5309
5310/** converts given cover C to a minimal cover by removing variables in the reverse order in which the variables were chosen
5311 * to be in C, i.e. in the order of non-increasing (1 - x*_j)/a_j, if the transformed separation problem was used to find
5312 * C and in the order of non-increasing (1 - x*_j), if the modified transformed separation problem was used to find C;
5313 * note that all variables with x*_j = 1 will be removed last
5314 */
5315static
5317 SCIP* scip, /**< SCIP data structure */
5318 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5319 SCIP_Longint capacity, /**< capacity of knapsack */
5320 SCIP_Real* solvals, /**< solution values of all problem variables */
5321 int* covervars, /**< pointer to store cover variables */
5322 int* noncovervars, /**< pointer to store noncover variables */
5323 int* ncovervars, /**< pointer to store number of cover variables */
5324 int* nnoncovervars, /**< pointer to store number of noncover variables */
5325 SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5326 SCIP_Bool modtransused /**< TRUE if mod trans sepa prob was used to find cover */
5327 )
5328{
5329 SORTKEYPAIR** sortkeypairs;
5330 SORTKEYPAIR** sortkeypairssorted;
5331 SCIP_Longint minweight;
5332 int nsortkeypairs;
5333 int minweightidx;
5334 int j;
5335 int k;
5336
5337 assert(scip != NULL);
5338 assert(covervars != NULL);
5339 assert(noncovervars != NULL);
5340 assert(ncovervars != NULL);
5341 assert(*ncovervars > 0);
5342 assert(nnoncovervars != NULL);
5343 assert(*nnoncovervars >= 0);
5344 assert(coverweight != NULL);
5345 assert(*coverweight > 0);
5346 assert(*coverweight > capacity);
5347
5348 /* allocates temporary memory; we need two arrays for the keypairs in order to be able to free them in the correct
5349 * order */
5350 nsortkeypairs = *ncovervars;
5351 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairs, nsortkeypairs) );
5352 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairssorted, nsortkeypairs) );
5353
5354 /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5355 * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5356 * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5357 * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5358 */
5359 assert(*ncovervars == nsortkeypairs);
5360 if( modtransused )
5361 {
5362 for( j = 0; j < *ncovervars; j++ )
5363 {
5364 SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5365 sortkeypairssorted[j] = sortkeypairs[j];
5366
5367 sortkeypairs[j]->key1 = solvals[covervars[j]];
5368 sortkeypairs[j]->key2 = (SCIP_Real) weights[covervars[j]];
5369 }
5370 }
5371 else
5372 {
5373 for( j = 0; j < *ncovervars; j++ )
5374 {
5375 SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5376 sortkeypairssorted[j] = sortkeypairs[j];
5377
5378 sortkeypairs[j]->key1 = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5379 sortkeypairs[j]->key2 = (SCIP_Real) (-weights[covervars[j]]);
5380 }
5381 }
5382 SCIPsortPtrInt((void**)sortkeypairssorted, covervars, compSortkeypairs, *ncovervars);
5383
5384 /* gets j' with a_j' = min{ a_j : j in C } */
5385 minweightidx = 0;
5386 minweight = weights[covervars[minweightidx]];
5387 for( j = 1; j < *ncovervars; j++ )
5388 {
5389 if( weights[covervars[j]] <= minweight )
5390 {
5391 minweightidx = j;
5392 minweight = weights[covervars[minweightidx]];
5393 }
5394 }
5395 assert(minweightidx >= 0 && minweightidx < *ncovervars);
5396 assert(minweight > 0 && minweight <= *coverweight);
5397
5398 j = 0;
5399 /* removes variables from C until the remaining variables form a minimal cover */
5400 while( j < *ncovervars && ((*coverweight) - minweight > capacity) )
5401 {
5402 assert(minweightidx >= j);
5403 assert(checkMinweightidx(weights, capacity, covervars, *ncovervars, *coverweight, minweightidx, j));
5404
5405 /* if sum_{i in C} a_i - a_j <= a_0, j cannot be removed from C */
5406 if( (*coverweight) - weights[covervars[j]] <= capacity )
5407 {
5408 ++j;
5409 continue;
5410 }
5411
5412 /* adds j to N\C */
5413 noncovervars[*nnoncovervars] = covervars[j];
5414 (*nnoncovervars)++;
5415
5416 /* removes j from C */
5417 (*coverweight) -= weights[covervars[j]];
5418 for( k = j; k < (*ncovervars) - 1; k++ )
5419 covervars[k] = covervars[k+1];
5420 (*ncovervars)--;
5421
5422 /* updates j' with a_j' = min{ a_j : j in C } */
5423 if( j == minweightidx )
5424 {
5425 minweightidx = 0;
5426 minweight = weights[covervars[minweightidx]];
5427 for( k = 1; k < *ncovervars; k++ )
5428 {
5429 if( weights[covervars[k]] <= minweight )
5430 {
5431 minweightidx = k;
5432 minweight = weights[covervars[minweightidx]];
5433 }
5434 }
5435 assert(minweight > 0 && minweight <= *coverweight);
5436 assert(minweightidx >= 0 && minweightidx < *ncovervars);
5437 }
5438 else
5439 {
5440 assert(minweightidx > j);
5441 minweightidx--;
5442 }
5443 /* j needs to stay the same */
5444 }
5445 assert((*coverweight) > capacity);
5446 assert((*coverweight) - minweight <= capacity);
5447
5448 /* frees temporary memory */
5449 for( j = nsortkeypairs-1; j >= 0; j-- )
5450 SCIPfreeBuffer(scip, &(sortkeypairs[j])); /*lint !e866 */
5451 SCIPfreeBufferArray(scip, &sortkeypairssorted);
5452 SCIPfreeBufferArray(scip, &sortkeypairs);
5453
5454 return SCIP_OKAY;
5455}
5456
5457/** converts given initial cover C_init to a feasible set by removing variables in the reverse order in which
5458 * they were chosen to be in C_init:
5459 * non-increasing (1 - x*_j)/a_j, if transformed separation problem was used to find C_init
5460 * non-increasing (1 - x*_j), if modified transformed separation problem was used to find C_init.
5461 * separates lifted extended weight inequalities using sequential up- and down-lifting for this feasible set
5462 * and all subsequent feasible sets.
5463 */
5464static
5466 SCIP* scip, /**< SCIP data structure */
5467 SCIP_CONS* cons, /**< constraint that originates the knapsack problem */
5468 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5469 SCIP_VAR** vars, /**< variables in knapsack constraint */
5470 int nvars, /**< number of variables in knapsack constraint */
5471 int ntightened, /**< number of variables with tightened upper bound */
5472 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5473 SCIP_Longint capacity, /**< capacity of knapsack */
5474 SCIP_Real* solvals, /**< solution values of all problem variables */
5475 int* covervars, /**< pointer to store cover variables */
5476 int* noncovervars, /**< pointer to store noncover variables */
5477 int* ncovervars, /**< pointer to store number of cover variables */
5478 int* nnoncovervars, /**< pointer to store number of noncover variables */
5479 SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5480 SCIP_Bool modtransused, /**< TRUE if mod trans sepa prob was used to find cover */
5481 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5482 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5483 int* ncuts /**< pointer to add up the number of found cuts */
5484 )
5485{
5486 SCIP_Real* sortkeys;
5487 int j;
5488 int k;
5489
5490 assert(scip != NULL);
5491 assert(covervars != NULL);
5492 assert(noncovervars != NULL);
5493 assert(ncovervars != NULL);
5494 assert(*ncovervars > 0);
5495 assert(nnoncovervars != NULL);
5496 assert(*nnoncovervars >= 0);
5497 assert(coverweight != NULL);
5498 assert(*coverweight > 0);
5499 assert(*coverweight > capacity);
5500 assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5501 assert(cutoff != NULL);
5502
5503 *cutoff = FALSE;
5504
5505 /* allocates temporary memory */
5506 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, *ncovervars) );
5507
5508 /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5509 * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5510 * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5511 * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5512 */
5513 if( modtransused )
5514 {
5515 for( j = 0; j < *ncovervars; j++ )
5516 {
5517 sortkeys[j] = solvals[covervars[j]];
5518 assert(SCIPisFeasGE(scip, sortkeys[j], 0.0));
5519 }
5520 }
5521 else
5522 {
5523 for( j = 0; j < *ncovervars; j++ )
5524 {
5525 sortkeys[j] = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5526 assert(SCIPisFeasLE(scip, sortkeys[j], 0.0));
5527 }
5528 }
5529 SCIPsortRealInt(sortkeys, covervars, *ncovervars);
5530
5531 /* removes variables from C_init and separates lifted extended weight inequalities using sequential up- and down-lifting;
5532 * in addition to an extended weight inequality this gives cardinality inequalities */
5533 while( *ncovervars >= 2 )
5534 {
5535 /* adds first element of C_init to N\C_init */
5536 noncovervars[*nnoncovervars] = covervars[0];
5537 (*nnoncovervars)++;
5538
5539 /* removes first element from C_init */
5540 (*coverweight) -= weights[covervars[0]];
5541 for( k = 0; k < (*ncovervars) - 1; k++ )
5542 covervars[k] = covervars[k+1];
5543 (*ncovervars)--;
5544
5545 assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5546 if( (*coverweight) <= capacity )
5547 {
5548 SCIP_CALL( separateSequLiftedExtendedWeightInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals,
5549 covervars, noncovervars, *ncovervars, *nnoncovervars, sol, cutoff, ncuts) );
5550 }
5551
5552 /* stop if cover is too large */
5553 if ( *ncovervars >= MAXCOVERSIZEITERLEWI )
5554 break;
5555 }
5556
5557 /* frees temporary memory */
5558 SCIPfreeBufferArray(scip, &sortkeys);
5559
5560 return SCIP_OKAY;
5561}
5562
5563/** separates different classes of valid inequalities for the 0-1 knapsack problem */
5565 SCIP* scip, /**< SCIP data structure */
5566 SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5567 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5568 SCIP_VAR** vars, /**< variables in knapsack constraint */
5569 int nvars, /**< number of variables in knapsack constraint */
5570 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5571 SCIP_Longint capacity, /**< capacity of knapsack */
5572 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5573 SCIP_Bool usegubs, /**< should GUB information be used for separation? */
5574 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
5575 int* ncuts /**< pointer to add up the number of found cuts */
5576 )
5577{
5578 SCIP_Real* solvals;
5579 int* covervars;
5580 int* noncovervars;
5581 SCIP_Bool coverfound;
5582 SCIP_Bool fractional;
5583 SCIP_Bool modtransused;
5584 SCIP_Longint coverweight;
5585 int ncovervars;
5586 int nnoncovervars;
5587 int ntightened;
5588
5589 assert(scip != NULL);
5590 assert(capacity >= 0);
5591 assert(cutoff != NULL);
5592 assert(ncuts != NULL);
5593
5594 *cutoff = FALSE;
5595
5596 if( nvars == 0 )
5597 return SCIP_OKAY;
5598
5599 assert(vars != NULL);
5600 assert(nvars > 0);
5601 assert(weights != NULL);
5602
5603 /* increase age of constraint (age is reset to zero, if a cut was found) */
5604 if( cons != NULL )
5605 {
5606 SCIP_CALL( SCIPincConsAge(scip, cons) );
5607 }
5608
5609 /* allocates temporary memory */
5611 SCIP_CALL( SCIPallocBufferArray(scip, &covervars, nvars) );
5612 SCIP_CALL( SCIPallocBufferArray(scip, &noncovervars, nvars) );
5613
5614 /* gets solution values of all problem variables */
5615 SCIP_CALL( SCIPgetSolVals(scip, sol, nvars, vars, solvals) );
5616
5617#ifdef SCIP_DEBUG
5618 {
5619 int i;
5620
5621 SCIPdebugMsg(scip, "separate cuts for knapsack constraint originated by cons <%s>:\n",
5622 cons == NULL ? "-" : SCIPconsGetName(cons));
5623 for( i = 0; i < nvars; ++i )
5624 {
5625 SCIPdebugMsgPrint(scip, "%+" SCIP_LONGINT_FORMAT "<%s>(%g)", weights[i], SCIPvarGetName(vars[i]), solvals[i]);
5626 }
5627 SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT "\n", capacity);
5628 }
5629#endif
5630
5631 /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting) using GUB information
5632 */
5633 if( usegubs )
5634 {
5635 SCIP_GUBSET* gubset;
5636
5637 SCIPdebugMsg(scip, "separate LMCI1-GUB cuts:\n");
5638
5639 /* initializes partion of knapsack variables into nonoverlapping GUB constraints */
5640 SCIP_CALL( GUBsetCreate(scip, &gubset, nvars, weights, capacity) );
5641
5642 /* constructs sophisticated partition of knapsack variables into nonoverlapping GUBs */
5643 SCIP_CALL( GUBsetGetCliquePartition(scip, gubset, vars, solvals) );
5644 assert(gubset->ngubconss <= nvars);
5645
5646 /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5647 * MODIFIED transformed separation problem and taking into account the following fixing:
5648 * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5649 * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5650 * if one exists
5651 */
5652 modtransused = TRUE;
5653 SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5654 &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5655
5656 assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5657
5658 /* if x* is not fractional we stop the separation routine */
5659 if( !fractional )
5660 {
5661 SCIPdebugMsg(scip, " LMCI1-GUB terminated by no variable with fractional LP value.\n");
5662
5663 /* frees memory for GUB set data structure */
5664 GUBsetFree(scip, &gubset);
5665
5666 goto TERMINATE;
5667 }
5668
5669 /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5670 if( coverfound )
5671 {
5672 /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5673 * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5674 */
5675 SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5676 &nnoncovervars, &coverweight, modtransused) );
5677
5678 /* only separate with GUB information if we have at least one nontrivial GUB (with more than one variable) */
5679 if( gubset->ngubconss < nvars )
5680 {
5681 /* separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information */
5682 SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5683 solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, gubset, cutoff, ncuts) );
5684 }
5685 else
5686 {
5687 /* separates lifted minimal cover inequalities using sequential up- and down-lifting, but do not use trivial
5688 * GUB information
5689 */
5690 SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5691 solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5692 }
5693 }
5694
5695 /* frees memory for GUB set data structure */
5696 GUBsetFree(scip, &gubset);
5697 }
5698 else
5699 {
5700 /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting)
5701 * (and LMCI2 (lifted minimal cover inequalities using superadditive up-lifting))
5702 */
5703
5704 /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5705 * MODIFIED transformed separation problem and taking into account the following fixing:
5706 * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5707 * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5708 * if one exists
5709 */
5710 SCIPdebugMsg(scip, "separate LMCI1 cuts:\n");
5711 modtransused = TRUE;
5712 SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5713 &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5714 assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5715
5716 /* if x* is not fractional we stop the separation routine */
5717 if( !fractional )
5718 goto TERMINATE;
5719
5720 /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5721 if( coverfound )
5722 {
5723 /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5724 * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5725 */
5726 SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5727 &nnoncovervars, &coverweight, modtransused) );
5728
5729 /* separates lifted minimal cover inequalities using sequential up- and down-lifting */
5730 SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5731 solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5732
5733 if( USESUPADDLIFT ) /*lint !e506 !e774*/
5734 {
5735 SCIPdebugMsg(scip, "separate LMCI2 cuts:\n");
5736 /* separates lifted minimal cover inequalities using superadditive up-lifting */
5737 SCIP_CALL( separateSupLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5738 solvals, covervars, noncovervars, ncovervars, nnoncovervars, coverweight, sol, cutoff, ncuts) );
5739 }
5740 }
5741 }
5742
5743 /* LEWI (lifted extended weight inequalities using sequential up- and down-lifting) */
5744 if ( ! (*cutoff) )
5745 {
5746 /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5747 * transformed separation problem and taking into account the following fixing:
5748 * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5749 * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5750 * if one exists
5751 */
5752 SCIPdebugMsg(scip, "separate LEWI cuts:\n");
5753 modtransused = FALSE;
5754 SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5755 &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5756 assert(fractional);
5757 assert(!coverfound || ncovervars + nnoncovervars == nvars - ntightened);
5758
5759 /* if no cover was found we stop the separation routine */
5760 if( coverfound )
5761 {
5762 /* converts initial cover C_init to a feasible set by removing variables in the reverse order in which
5763 * they were chosen to be in C_init and separates lifted extended weight inequalities using sequential
5764 * up- and down-lifting for this feasible set and all subsequent feasible sets.
5765 */
5766 SCIP_CALL( getFeasibleSet(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals, covervars, noncovervars,
5767 &ncovervars, &nnoncovervars, &coverweight, modtransused, sol, cutoff, ncuts) );
5768 }
5769 }
5770
5771 TERMINATE:
5772 /* frees temporary memory */
5773 SCIPfreeBufferArray(scip, &noncovervars);
5774 SCIPfreeBufferArray(scip, &covervars);
5775 SCIPfreeBufferArray(scip, &solvals);
5776
5777 return SCIP_OKAY;
5778}
5779
5780/* relaxes given general linear constraint into a knapsack constraint and separates lifted knapsack cover inequalities */
5782 SCIP* scip, /**< SCIP data structure */
5783 SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5784 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5785 int nknapvars, /**< number of variables in the continuous knapsack constraint */
5786 SCIP_VAR** knapvars, /**< variables in the continuous knapsack constraint */
5787 SCIP_Real* knapvals, /**< coefficients of the variables in the continuous knapsack constraint */
5788 SCIP_Real valscale, /**< -1.0 if lhs of row is used as rhs of c. k. constraint, +1.0 otherwise */
5789 SCIP_Real rhs, /**< right hand side of the continuous knapsack constraint */
5790 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
5791 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff was found */
5792 int* ncuts /**< pointer to add up the number of found cuts */
5793 )
5794{
5795 SCIP_VAR** binvars;
5796 SCIP_VAR** consvars;
5797 SCIP_Real* binvals;
5798 SCIP_Longint* consvals;
5799 SCIP_Longint minact;
5800 SCIP_Longint maxact;
5801 SCIP_Real intscalar;
5802 SCIP_Bool success;
5803 int nbinvars;
5804 int nconsvars;
5805 int i;
5806
5807 int* tmpindices;
5808 int tmp;
5809 SCIP_CONSHDLR* conshdlr;
5810 SCIP_CONSHDLRDATA* conshdlrdata;
5811 SCIP_Bool noknapsackconshdlr;
5812 SCIP_Bool usegubs;
5813
5814 assert(nknapvars > 0);
5815 assert(knapvars != NULL);
5816 assert(cutoff != NULL);
5817
5818 tmpindices = NULL;
5819
5820 SCIPdebugMsg(scip, "separate linear constraint <%s> relaxed to knapsack\n", cons != NULL ? SCIPconsGetName(cons) : "-");
5821 SCIPdebug( if( cons != NULL ) { SCIPdebugPrintCons(scip, cons, NULL); } );
5822
5823 binvars = SCIPgetVars(scip);
5824
5825 /* all variables which are of integral type can be potentially of binary type; this can be checked via the method SCIPvarIsBinary(var) */
5826 nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
5827
5828 *cutoff = FALSE;
5829
5830 if( nbinvars == 0 )
5831 return SCIP_OKAY;
5832
5833 /* set up data structures */
5834 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nbinvars) );
5835 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nbinvars) );
5836
5837 /* get conshdlrdata to use cleared memory */
5838 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
5839 if( conshdlr == NULL )
5840 {
5841 noknapsackconshdlr = TRUE;
5842 usegubs = DEFAULT_USEGUBS;
5843
5844 SCIP_CALL( SCIPallocBufferArray(scip, &binvals, nbinvars) );
5845 BMSclearMemoryArray(binvals, nbinvars);
5846 }
5847 else
5848 {
5849 noknapsackconshdlr = FALSE;
5850 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5851 assert(conshdlrdata != NULL);
5852 usegubs = conshdlrdata->usegubs;
5853
5854 SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, nknapvars) );
5855
5856 /* increase array size to avoid an endless loop in the next block; this might happen if continuous variables
5857 * change their types to SCIP_VARTYPE_BINARY during presolving
5858 */
5859 if( conshdlrdata->reals1size == 0 )
5860 {
5861 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, conshdlrdata->reals1size, 1) );
5862 conshdlrdata->reals1size = 1;
5863 conshdlrdata->reals1[0] = 0.0;
5864 }
5865
5866 assert(conshdlrdata->reals1size > 0);
5867
5868 /* next if condition should normally not be true, because it means that presolving has created more binary
5869 * variables than binary + integer variables existed at the constraint initialization method, but for example if you would
5870 * transform all integers into their binary representation then it maybe happens
5871 */
5872 if( conshdlrdata->reals1size < nbinvars )
5873 {
5874 int oldsize = conshdlrdata->reals1size;
5875
5876 conshdlrdata->reals1size = nbinvars;
5877 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, oldsize, conshdlrdata->reals1size) );
5878 BMSclearMemoryArray(&(conshdlrdata->reals1[oldsize]), conshdlrdata->reals1size - oldsize); /*lint !e866 */
5879 }
5880 binvals = conshdlrdata->reals1;
5881
5882 /* check for cleared array, all entries have to be zero */
5883#ifndef NDEBUG
5884 for( tmp = nbinvars - 1; tmp >= 0; --tmp )
5885 {
5886 assert(binvals[tmp] == 0);
5887 }
5888#endif
5889 }
5890
5891 tmp = 0;
5892
5893 /* relax continuous knapsack constraint:
5894 * 1. make all variables binary:
5895 * if x_j is continuous or integer variable substitute:
5896 * - a_j < 0: x_j = lb or x_j = b*z + d with variable lower bound b*z + d with binary variable z
5897 * - a_j > 0: x_j = ub or x_j = b*z + d with variable upper bound b*z + d with binary variable z
5898 * 2. convert coefficients of all variables to positive integers:
5899 * - scale all coefficients a_j to a~_j integral
5900 * - substitute x~_j = 1 - x_j if a~_j < 0
5901 */
5902
5903 /* replace integer and continuous variables with binary variables */
5904 for( i = 0; i < nknapvars; i++ )
5905 {
5906 SCIP_VAR* var;
5907
5908 var = knapvars[i];
5909
5910 if( SCIPvarIsBinary(var) && SCIPvarIsActive(var) )
5911 {
5912 SCIP_Real solval;
5913 assert(0 <= SCIPvarGetProbindex(var) && SCIPvarGetProbindex(var) < nbinvars);
5914
5915 solval = SCIPgetSolVal(scip, sol, var);
5916
5917 /* knapsack relaxation assumes solution values between 0.0 and 1.0 for binary variables */
5918 if( SCIPisFeasLT(scip, solval, 0.0 )
5919 || SCIPisFeasGT(scip, solval, 1.0) )
5920 {
5921 SCIPdebugMsg(scip, "Solution value %.15g <%s> outside domain [0.0, 1.0]\n",
5922 solval, SCIPvarGetName(var));
5923 goto TERMINATE;
5924 }
5925
5926 binvals[SCIPvarGetProbindex(var)] += valscale * knapvals[i];
5927 if( !noknapsackconshdlr )
5928 {
5929 assert(tmpindices != NULL);
5930
5931 tmpindices[tmp] = SCIPvarGetProbindex(var);
5932 ++tmp;
5933 }
5934 SCIPdebugMsg(scip, " -> binary variable %+.15g<%s>(%.15g)\n", valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var));
5935 }
5936 else if( valscale * knapvals[i] > 0.0 )
5937 {
5938 SCIP_VAR** zvlb;
5939 SCIP_Real* bvlb;
5940 SCIP_Real* dvlb;
5941 SCIP_Real bestlbsol;
5942 int bestlbtype;
5943 int nvlb;
5944 int j;
5945
5946 /* a_j > 0: substitution with lb or vlb */
5947 nvlb = SCIPvarGetNVlbs(var);
5948 zvlb = SCIPvarGetVlbVars(var);
5949 bvlb = SCIPvarGetVlbCoefs(var);
5950 dvlb = SCIPvarGetVlbConstants(var);
5951
5952 /* search for lb or vlb with maximal bound value */
5953 bestlbsol = SCIPvarGetLbGlobal(var);
5954 bestlbtype = -1;
5955 for( j = 0; j < nvlb; j++ )
5956 {
5957 /* use only numerical stable vlb with binary variable z */
5958 if( SCIPvarIsBinary(zvlb[j]) && SCIPvarIsActive(zvlb[j]) && REALABS(bvlb[j]) <= MAXABSVBCOEF )
5959 {
5960 SCIP_Real vlbsol;
5961
5962 if( (bvlb[j] >= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetLbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) ||
5963 (bvlb[j] <= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetUbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) )
5964 {
5965 *cutoff = TRUE;
5966 SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] >= %g<%s>[%g,%g] + %g implies local cutoff\n",
5968 bvlb[j], SCIPvarGetName(zvlb[j]), SCIPvarGetLbLocal(zvlb[j]), SCIPvarGetUbLocal(zvlb[j]), dvlb[j]);
5969 goto TERMINATE;
5970 }
5971
5972 assert(0 <= SCIPvarGetProbindex(zvlb[j]) && SCIPvarGetProbindex(zvlb[j]) < nbinvars);
5973 vlbsol = bvlb[j] * SCIPgetSolVal(scip, sol, zvlb[j]) + dvlb[j];
5974 if( SCIPisGE(scip, vlbsol, bestlbsol) )
5975 {
5976 bestlbsol = vlbsol;
5977 bestlbtype = j;
5978 }
5979 }
5980 }
5981
5982 /* if no lb or vlb with binary variable was found, we have to abort */
5983 if( SCIPisInfinity(scip, -bestlbsol) )
5984 goto TERMINATE;
5985
5986 if( bestlbtype == -1 )
5987 {
5988 rhs -= valscale * knapvals[i] * bestlbsol;
5989 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with lower bound %.15g (rhs=%.15g)\n",
5990 valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetLbGlobal(var), rhs);
5991 }
5992 else
5993 {
5994 assert(0 <= SCIPvarGetProbindex(zvlb[bestlbtype]) && SCIPvarGetProbindex(zvlb[bestlbtype]) < nbinvars);
5995 rhs -= valscale * knapvals[i] * dvlb[bestlbtype];
5996 binvals[SCIPvarGetProbindex(zvlb[bestlbtype])] += valscale * knapvals[i] * bvlb[bestlbtype];
5997
5998 if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvlb[bestlbtype])])) )
5999 goto TERMINATE;
6000
6001 if( !noknapsackconshdlr )
6002 {
6003 assert(tmpindices != NULL);
6004
6005 tmpindices[tmp] = SCIPvarGetProbindex(zvlb[bestlbtype]);
6006 ++tmp;
6007 }
6008 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable lower bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
6009 valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
6010 bvlb[bestlbtype], SCIPvarGetName(zvlb[bestlbtype]),
6011 SCIPgetSolVal(scip, sol, zvlb[bestlbtype]), dvlb[bestlbtype], rhs);
6012 }
6013 }
6014 else
6015 {
6016 SCIP_VAR** zvub;
6017 SCIP_Real* bvub;
6018 SCIP_Real* dvub;
6019 SCIP_Real bestubsol;
6020 int bestubtype;
6021 int nvub;
6022 int j;
6023
6024 assert(valscale * knapvals[i] < 0.0);
6025
6026 /* a_j < 0: substitution with ub or vub */
6027 nvub = SCIPvarGetNVubs(var);
6028 zvub = SCIPvarGetVubVars(var);
6029 bvub = SCIPvarGetVubCoefs(var);
6030 dvub = SCIPvarGetVubConstants(var);
6031
6032 /* search for ub or vub with minimal bound value */
6033 bestubsol = SCIPvarGetUbGlobal(var);
6034 bestubtype = -1;
6035 for( j = 0; j < nvub; j++ )
6036 {
6037 /* use only numerical stable vub with active binary variable z */
6038 if( SCIPvarIsBinary(zvub[j]) && SCIPvarIsActive(zvub[j]) && REALABS(bvub[j]) <= MAXABSVBCOEF )
6039 {
6040 SCIP_Real vubsol;
6041
6042 if( (bvub[j] >= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetUbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) ||
6043 (bvub[j] <= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetLbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) )
6044 {
6045 *cutoff = TRUE;
6046 SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] <= %g<%s>[%g,%g] + %g implies local cutoff\n",
6048 bvub[j], SCIPvarGetName(zvub[j]), SCIPvarGetLbLocal(zvub[j]), SCIPvarGetUbLocal(zvub[j]), dvub[j]);
6049 goto TERMINATE;
6050 }
6051
6052 assert(0 <= SCIPvarGetProbindex(zvub[j]) && SCIPvarGetProbindex(zvub[j]) < nbinvars);
6053 vubsol = bvub[j] * SCIPgetSolVal(scip, sol, zvub[j]) + dvub[j];
6054 if( SCIPisLE(scip, vubsol, bestubsol) )
6055 {
6056 bestubsol = vubsol;
6057 bestubtype = j;
6058 }
6059 }
6060 }
6061
6062 /* if no ub or vub with binary variable was found, we have to abort */
6063 if( SCIPisInfinity(scip, bestubsol) )
6064 goto TERMINATE;
6065
6066 if( bestubtype == -1 )
6067 {
6068 rhs -= valscale * knapvals[i] * bestubsol;
6069 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with upper bound %.15g (rhs=%.15g)\n",
6070 valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetUbGlobal(var), rhs);
6071 }
6072 else
6073 {
6074 assert(0 <= SCIPvarGetProbindex(zvub[bestubtype]) && SCIPvarGetProbindex(zvub[bestubtype]) < nbinvars);
6075 rhs -= valscale * knapvals[i] * dvub[bestubtype];
6076 binvals[SCIPvarGetProbindex(zvub[bestubtype])] += valscale * knapvals[i] * bvub[bestubtype];
6077
6078 if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvub[bestubtype])])) )
6079 goto TERMINATE;
6080
6081 if( !noknapsackconshdlr )
6082 {
6083 assert(tmpindices != NULL);
6084
6085 tmpindices[tmp] = SCIPvarGetProbindex(zvub[bestubtype]);
6086 ++tmp;
6087 }
6088 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable upper bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
6089 valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
6090 bvub[bestubtype], SCIPvarGetName(zvub[bestubtype]),
6091 SCIPgetSolVal(scip, sol, zvub[bestubtype]), dvub[bestubtype], rhs);
6092 }
6093 }
6094 }
6095
6096 /* convert coefficients of all (now binary) variables to positive integers:
6097 * - make all coefficients integral
6098 * - make all coefficients positive (substitute negated variable)
6099 */
6100 nconsvars = 0;
6101
6102 /* calculate scalar which makes all coefficients integral in relative allowed difference in between
6103 * -SCIPepsilon(scip) and KNAPSACKRELAX_MAXDELTA
6104 */
6106 KNAPSACKRELAX_MAXDNOM, KNAPSACKRELAX_MAXSCALE, &intscalar, &success) );
6107 SCIPdebugMsg(scip, " -> intscalar = %.15g\n", intscalar);
6108
6109 /* if coefficients cannot be made integral, we have to use a scalar of 1.0 and only round fractional coefficients down */
6110 if( !success )
6111 intscalar = 1.0;
6112
6113 /* make all coefficients integral and positive:
6114 * - scale a~_j = a_j * intscalar
6115 * - substitute x~_j = 1 - x_j if a~_j < 0
6116 */
6117 rhs = rhs * intscalar;
6118
6119 SCIPdebugMsg(scip, " -> rhs = %.15g\n", rhs);
6120 minact = 0;
6121 maxact = 0;
6122 for( i = 0; i < nbinvars; i++ )
6123 {
6124 SCIP_VAR* var;
6125 SCIP_Longint val;
6126
6127 val = (SCIP_Longint)SCIPfloor(scip, binvals[i] * intscalar);
6128 if( val == 0 )
6129 continue;
6130
6131 if( val > 0 )
6132 {
6133 var = binvars[i];
6134 SCIPdebugMsg(scip, " -> positive scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): not changed (rhs=%.15g)\n",
6135 val, SCIPvarGetName(var), binvals[i], rhs);
6136 }
6137 else
6138 {
6139 assert(val < 0);
6140
6141 SCIP_CALL( SCIPgetNegatedVar(scip, binvars[i], &var) );
6142 val = -val; /*lint !e2704*/
6143 rhs += val;
6144 SCIPdebugMsg(scip, " -> negative scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): substituted by (1 - <%s>) (rhs=%.15g)\n",
6145 -val, SCIPvarGetName(binvars[i]), binvals[i], SCIPvarGetName(var), rhs);
6146 }
6147
6148 if( SCIPvarGetLbLocal(var) > 0.5 )
6149 minact += val;
6150 if( SCIPvarGetUbLocal(var) > 0.5 )
6151 maxact += val;
6152 consvals[nconsvars] = val;
6153 consvars[nconsvars] = var;
6154 nconsvars++;
6155 }
6156
6157 if( nconsvars > 0 )
6158 {
6159 SCIP_Longint capacity;
6160
6161 assert(consvars != NULL);
6162 assert(consvals != NULL);
6163 capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
6164
6165#ifdef SCIP_DEBUG
6166 {
6167 SCIP_Real act;
6168
6169 SCIPdebugMsg(scip, " -> linear constraint <%s> relaxed to knapsack:", cons != NULL ? SCIPconsGetName(cons) : "-");
6170 act = 0.0;
6171 for( i = 0; i < nconsvars; ++i )
6172 {
6173 SCIPdebugMsgPrint(scip, " %+" SCIP_LONGINT_FORMAT "<%s>(%.15g)", consvals[i], SCIPvarGetName(consvars[i]),
6174 SCIPgetSolVal(scip, sol, consvars[i]));
6175 act += consvals[i] * SCIPgetSolVal(scip, sol, consvars[i]);
6176 }
6177 SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT " (%.15g) [act: %.15g, min: %" SCIP_LONGINT_FORMAT " max: %" SCIP_LONGINT_FORMAT "]\n",
6178 capacity, rhs, act, minact, maxact);
6179 }
6180#endif
6181
6182 if( minact > capacity )
6183 {
6184 SCIPdebugMsg(scip, "minactivity of knapsack relaxation implies local cutoff\n");
6185 *cutoff = TRUE;
6186 goto TERMINATE;
6187 }
6188
6189 if( maxact > capacity )
6190 {
6191 /* separate lifted cut from relaxed knapsack constraint */
6192 SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, sepa, consvars, nconsvars, consvals, capacity, sol, usegubs, cutoff, ncuts) );
6193 }
6194 }
6195
6196 TERMINATE:
6197 /* free data structures */
6198 if( noknapsackconshdlr)
6199 {
6200 SCIPfreeBufferArray(scip, &binvals);
6201 }
6202 else
6203 {
6204 /* clear binvals */
6205 for( --tmp; tmp >= 0; --tmp)
6206 {
6207 assert(tmpindices != NULL);
6208 binvals[tmpindices[tmp]] = 0;
6209 }
6210 SCIPfreeBufferArray(scip, &tmpindices);
6211 }
6212 SCIPfreeBufferArray(scip, &consvals);
6213 SCIPfreeBufferArray(scip, &consvars);
6214
6215 return SCIP_OKAY;
6216}
6217
6218/** separates given knapsack constraint */
6219static
6221 SCIP* scip, /**< SCIP data structure */
6222 SCIP_CONS* cons, /**< knapsack constraint */
6223 SCIP_SOL* sol, /**< primal SCIP solution, NULL for current LP solution */
6224 SCIP_Bool sepacuts, /**< should knapsack cuts be separated? */
6225 SCIP_Bool usegubs, /**< should GUB information be used for separation? */
6226 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
6227 int* ncuts /**< pointer to add up the number of found cuts */
6228 )
6229{
6230 SCIP_CONSDATA* consdata;
6231 SCIP_Bool violated;
6232
6233 assert(ncuts != NULL);
6234 assert(cutoff != NULL);
6235 *cutoff = FALSE;
6236
6237 consdata = SCIPconsGetData(cons);
6238 assert(consdata != NULL);
6239
6240 SCIPdebugMsg(scip, "separating knapsack constraint <%s>\n", SCIPconsGetName(cons));
6241
6242 /* check knapsack constraint itself for feasibility */
6243 SCIP_CALL( checkCons(scip, cons, sol, (sol != NULL), FALSE, &violated) );
6244
6245 if( violated )
6246 {
6247 /* add knapsack constraint as LP row to the LP */
6248 SCIP_CALL( addRelaxation(scip, cons, cutoff) );
6249 (*ncuts)++;
6250 }
6251 else if( sepacuts )
6252 {
6253 SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, NULL, consdata->vars, consdata->nvars, consdata->weights,
6254 consdata->capacity, sol, usegubs, cutoff, ncuts) );
6255 }
6256
6257 return SCIP_OKAY;
6258}
6259
6260/** adds coefficient to constraint data */
6261static
6263 SCIP* scip, /**< SCIP data structure */
6264 SCIP_CONS* cons, /**< knapsack constraint */
6265 SCIP_VAR* var, /**< variable to add to knapsack */
6266 SCIP_Longint weight /**< weight of variable in knapsack */
6267 )
6268{
6269 SCIP_CONSDATA* consdata;
6270
6271 consdata = SCIPconsGetData(cons);
6272 assert(consdata != NULL);
6273 assert(SCIPvarIsBinary(var));
6274 assert(weight > 0);
6275
6276 /* add the new coefficient to the LP row */
6277 if( consdata->row != NULL )
6278 {
6279 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, (SCIP_Real)weight) );
6280 }
6281
6282 /* check for fixed variable */
6283 if( SCIPvarGetLbGlobal(var) > 0.5 )
6284 {
6285 /* variable is fixed to one: reduce capacity */
6286 consdata->capacity -= weight;
6287 }
6288 else if( SCIPvarGetUbGlobal(var) > 0.5 )
6289 {
6290 SCIP_Bool negated;
6291
6292 /* get binary representative of variable */
6293 SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &var, &negated) );
6294
6295 /* insert coefficient */
6296 SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1, SCIPconsIsTransformed(cons)) );
6297 consdata->vars[consdata->nvars] = var;
6298 consdata->weights[consdata->nvars] = weight;
6299 consdata->nvars++;
6300
6301 /* capture variable */
6302 SCIP_CALL( SCIPcaptureVar(scip, var) );
6303
6304 /* install the rounding locks of variable */
6305 SCIP_CALL( lockRounding(scip, cons, var) );
6306
6307 /* catch events */
6308 if( SCIPconsIsTransformed(cons) )
6309 {
6310 SCIP_CONSHDLRDATA* conshdlrdata;
6311
6312 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6313 assert(conshdlrdata != NULL);
6314 SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[consdata->nvars-1], cons, weight) );
6316 conshdlrdata->eventhdlr, consdata->eventdata[consdata->nvars-1],
6317 &consdata->eventdata[consdata->nvars-1]->filterpos) );
6318
6319 if( !consdata->existmultaggr && SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR )
6320 consdata->existmultaggr = TRUE;
6321
6322 /* mark constraint to be propagated and presolved */
6324 consdata->presolvedtiming = 0;
6325 consdata->cliquesadded = FALSE; /* new coefficient might lead to larger cliques */
6326 }
6327
6328 /* update weight sums */
6329 updateWeightSums(consdata, var, weight);
6330
6331 consdata->sorted = FALSE;
6332 consdata->cliquepartitioned = FALSE;
6333 consdata->negcliquepartitioned = FALSE;
6334 consdata->merged = FALSE;
6335 }
6336
6337 return SCIP_OKAY;
6338}
6339
6340/** deletes coefficient at given position from constraint data */
6341static
6343 SCIP* scip, /**< SCIP data structure */
6344 SCIP_CONS* cons, /**< knapsack constraint */
6345 int pos /**< position of coefficient to delete */
6346 )
6347{
6348 SCIP_CONSDATA* consdata;
6349 SCIP_VAR* var;
6350
6351 consdata = SCIPconsGetData(cons);
6352 assert(consdata != NULL);
6353 assert(0 <= pos && pos < consdata->nvars);
6354
6355 var = consdata->vars[pos];
6356 assert(var != NULL);
6357 assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
6358
6359 /* delete the coefficient from the LP row */
6360 if( consdata->row != NULL )
6361 {
6362 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, -(SCIP_Real)consdata->weights[pos]) );
6363 }
6364
6365 /* remove the rounding locks of variable */
6366 SCIP_CALL( unlockRounding(scip, cons, var) );
6367
6368 /* drop events and mark constraint to be propagated and presolved */
6369 if( SCIPconsIsTransformed(cons) )
6370 {
6371 SCIP_CONSHDLRDATA* conshdlrdata;
6372
6373 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6374 assert(conshdlrdata != NULL);
6376 conshdlrdata->eventhdlr, consdata->eventdata[pos], consdata->eventdata[pos]->filterpos) );
6377 SCIP_CALL( eventdataFree(scip, &consdata->eventdata[pos]) );
6378
6380 consdata->presolvedtiming = 0;
6381 consdata->sorted = (consdata->sorted && pos == consdata->nvars - 1);
6382 }
6383
6384 /* decrease weight sums */
6385 updateWeightSums(consdata, var, -consdata->weights[pos]);
6386
6387 /* move the last variable to the free slot */
6388 consdata->vars[pos] = consdata->vars[consdata->nvars-1];
6389 consdata->weights[pos] = consdata->weights[consdata->nvars-1];
6390 if( consdata->eventdata != NULL )
6391 consdata->eventdata[pos] = consdata->eventdata[consdata->nvars-1];
6392
6393 /* release variable */
6394 SCIP_CALL( SCIPreleaseVar(scip, &var) );
6395
6396 /* try to use old clique partitions */
6397 if( consdata->cliquepartitioned )
6398 {
6399 assert(consdata->cliquepartition != NULL);
6400 /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6401 * change the clique number */
6402 if( consdata->cliquepartition[consdata->nvars - 1] != consdata->nvars - 1 )
6403 {
6404 int oldcliqenum;
6405
6406 oldcliqenum = consdata->cliquepartition[pos];
6407 consdata->cliquepartition[pos] = consdata->cliquepartition[consdata->nvars-1];
6408
6409 /* the following if and else cases assure that we have increasing clique numbers */
6410 if( consdata->cliquepartition[pos] > pos )
6411 consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6412 else
6413 {
6414 int i;
6415 int cliquenumbefore;
6416
6417 /* if the old clique number was greater than the new one we have to check that before a bigger clique number
6418 * occurs the same as the old one is still in the cliquepartition */
6419 if( oldcliqenum > consdata->cliquepartition[pos] )
6420 {
6421 for( i = 0; i < consdata->nvars; ++i )
6422 if( oldcliqenum == consdata->cliquepartition[i] )
6423 break;
6424 else if( oldcliqenum < consdata->cliquepartition[i] )
6425 {
6426 consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6427 break;
6428 }
6429 /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6430 * the biggest index, so decrease the number of cliques
6431 */
6432 if( i == consdata->nvars )
6433 --(consdata->ncliques);
6434 }
6435 /* if the old clique number was smaller than the new one we have to check the front for an element with
6436 * clique number minus 1 */
6437 else if( oldcliqenum < consdata->cliquepartition[pos] )
6438 {
6439 cliquenumbefore = consdata->cliquepartition[pos] - 1;
6440 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6441
6442 if( i < cliquenumbefore )
6443 consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6444 }
6445 /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6446 else if( pos == consdata->nvars - 1)
6447 {
6448 cliquenumbefore = consdata->cliquepartition[pos];
6449 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6450
6451 if( i < cliquenumbefore )
6452 --(consdata->ncliques);
6453 }
6454 /* if the old clique number is equal to the new one the cliquepartition should be ok */
6455 }
6456 }
6457 else
6458 --(consdata->ncliques);
6459 }
6460
6461 if( consdata->negcliquepartitioned )
6462 {
6463 assert(consdata->negcliquepartition != NULL);
6464 /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6465 * change the clique number */
6466 if( consdata->negcliquepartition[consdata->nvars-1] != consdata->nvars - 1 )
6467 {
6468 int oldcliqenum;
6469
6470 oldcliqenum = consdata->negcliquepartition[pos];
6471 consdata->negcliquepartition[pos] = consdata->negcliquepartition[consdata->nvars-1];
6472
6473 /* the following if and else cases assure that we have increasing clique numbers */
6474 if( consdata->negcliquepartition[pos] > pos )
6475 consdata->negcliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6476 else
6477 {
6478 int i;
6479 int cliquenumbefore;
6480
6481 /* if the old clique number was greater than the new one we have to check that, before a bigger clique number
6482 * occurs, the same as the old one occurs */
6483 if( oldcliqenum > consdata->negcliquepartition[pos] )
6484 {
6485 for( i = 0; i < consdata->nvars; ++i )
6486 if( oldcliqenum == consdata->negcliquepartition[i] )
6487 break;
6488 else if( oldcliqenum < consdata->negcliquepartition[i] )
6489 {
6490 consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6491 break;
6492 }
6493 /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6494 * the biggest index, so decrease the number of negated cliques
6495 */
6496 if( i == consdata->nvars )
6497 --(consdata->nnegcliques);
6498 }
6499 /* if the old clique number was smaller than the new one we have to check the front for an element with
6500 * clique number minus 1 */
6501 else if( oldcliqenum < consdata->negcliquepartition[pos] )
6502 {
6503 cliquenumbefore = consdata->negcliquepartition[pos] - 1;
6504 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6505
6506 if( i < cliquenumbefore )
6507 consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6508 }
6509 /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6510 else if( pos == consdata->nvars - 1)
6511 {
6512 cliquenumbefore = consdata->negcliquepartition[pos];
6513 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6514
6515 if( i < cliquenumbefore )
6516 --(consdata->nnegcliques);
6517 }
6518 /* otherwise if the old clique number is equal to the new one the cliquepartition should be ok */
6519 }
6520 }
6521 else
6522 --(consdata->nnegcliques);
6523 }
6524
6525 --(consdata->nvars);
6526
6527 return SCIP_OKAY;
6528}
6529
6530/** removes all items with weight zero from knapsack constraint */
6531static
6533 SCIP* scip, /**< SCIP data structure */
6534 SCIP_CONS* cons /**< knapsack constraint */
6535 )
6536{
6537 SCIP_CONSDATA* consdata;
6538 int v;
6539
6540 consdata = SCIPconsGetData(cons);
6541 assert(consdata != NULL);
6542
6543 for( v = consdata->nvars-1; v >= 0; --v )
6544 {
6545 if( consdata->weights[v] == 0 )
6546 {
6547 SCIP_CALL( delCoefPos(scip, cons, v) );
6548 }
6549 }
6550
6551 return SCIP_OKAY;
6552}
6553
6554/* perform deletion of variables in all constraints of the constraint handler */
6555static
6557 SCIP* scip, /**< SCIP data structure */
6558 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6559 SCIP_CONS** conss, /**< array of constraints */
6560 int nconss /**< number of constraints */
6561 )
6562{
6563 SCIP_CONSDATA* consdata;
6564 int i;
6565 int v;
6566
6567 assert(scip != NULL);
6568 assert(conshdlr != NULL);
6569 assert(conss != NULL);
6570 assert(nconss >= 0);
6571 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
6572
6573 /* iterate over all constraints */
6574 for( i = 0; i < nconss; i++ )
6575 {
6576 consdata = SCIPconsGetData(conss[i]);
6577
6578 /* constraint is marked, that some of its variables were deleted */
6579 if( consdata->varsdeleted )
6580 {
6581 /* iterate over all variables of the constraint and delete them from the constraint */
6582 for( v = consdata->nvars - 1; v >= 0; --v )
6583 {
6584 if( SCIPvarIsDeleted(consdata->vars[v]) )
6585 {
6586 SCIP_CALL( delCoefPos(scip, conss[i], v) );
6587 }
6588 }
6589 consdata->varsdeleted = FALSE;
6590 }
6591 }
6592
6593 return SCIP_OKAY;
6594}
6595
6596/** replaces multiple occurrences of a variable or its negation by a single coefficient */
6597static
6599 SCIP* scip, /**< SCIP data structure */
6600 SCIP_CONS* cons, /**< knapsack constraint */
6601 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
6602 )
6603{
6604 SCIP_CONSDATA* consdata;
6605 int v;
6606 int prev;
6607
6608 assert(scip != NULL);
6609 assert(cons != NULL);
6610 assert(cutoff != NULL);
6611
6612 consdata = SCIPconsGetData(cons);
6613 assert(consdata != NULL);
6614
6615 *cutoff = FALSE;
6616
6617 if( consdata->merged )
6618 return SCIP_OKAY;
6619
6620 if( consdata->nvars <= 1 )
6621 {
6622 consdata->merged = TRUE;
6623 return SCIP_OKAY;
6624 }
6625
6626 assert(consdata->vars != NULL || consdata->nvars == 0);
6627
6628 /* sorting array after indices of variables, that's only for faster merging */
6629 SCIPsortPtrPtrLongIntInt((void**)consdata->vars, (void**)consdata->eventdata, consdata->weights,
6630 consdata->cliquepartition, consdata->negcliquepartition, SCIPvarCompActiveAndNegated, consdata->nvars);
6631
6632 /* knapsack-sorting (decreasing weights) now lost */
6633 consdata->sorted = FALSE;
6634
6635 v = consdata->nvars - 1;
6636 prev = v - 1;
6637 /* loop backwards through the items: deletion only affects rear items */
6638 while( prev >= 0 )
6639 {
6640 SCIP_VAR* var1;
6641 SCIP_VAR* var2;
6642 SCIP_Bool negated1;
6643 SCIP_Bool negated2;
6644
6645 negated1 = FALSE;
6646 negated2 = FALSE;
6647
6648 var1 = consdata->vars[v];
6649 assert(SCIPvarIsBinary(var1));
6652 {
6653 var1 = SCIPvarGetNegatedVar(var1);
6654 negated1 = TRUE;
6655 }
6656 assert(var1 != NULL);
6657
6658 var2 = consdata->vars[prev];
6659 assert(SCIPvarIsBinary(var2));
6662 {
6663 var2 = SCIPvarGetNegatedVar(var2);
6664 negated2 = TRUE;
6665 }
6666 assert(var2 != NULL);
6667
6668 if( var1 == var2 )
6669 {
6670 /* both variables are either active or negated */
6671 if( negated1 == negated2 )
6672 {
6673 /* variables var1 and var2 are equal: add weight of var1 to var2, and delete var1 */
6674 consdataChgWeight(consdata, prev, consdata->weights[v] + consdata->weights[prev]);
6675 SCIP_CALL( delCoefPos(scip, cons, v) );
6676 }
6677 /* variables var1 and var2 are opposite: subtract smaller weight from larger weight, reduce capacity,
6678 * and delete item of smaller weight
6679 */
6680 else if( consdata->weights[v] == consdata->weights[prev] )
6681 {
6682 /* both variables eliminate themselves: w*x + w*(1-x) == w */
6683 consdata->capacity -= consdata->weights[v];
6684 SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6685 SCIP_CALL( delCoefPos(scip, cons, prev) );
6686
6687 --prev;
6688 }
6689 else if( consdata->weights[v] < consdata->weights[prev] )
6690 {
6691 consdata->capacity -= consdata->weights[v];
6692 consdataChgWeight(consdata, prev, consdata->weights[prev] - consdata->weights[v]);
6693 assert(consdata->weights[prev] > 0);
6694 SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6695 }
6696 else
6697 {
6698 consdata->capacity -= consdata->weights[prev];
6699 consdataChgWeight(consdata, v, consdata->weights[v] - consdata->weights[prev]);
6700 assert(consdata->weights[v] > 0);
6701 SCIP_CALL( delCoefPos(scip, cons, prev) ); /* attention: normally we lose our order */
6702 /* restore order iff necessary */
6703 if( consdata->nvars != v ) /* otherwise the order still stands */
6704 {
6705 assert(prev == 0 || ((prev > 0) && (SCIPvarIsActive(consdata->vars[prev - 1]) || SCIPvarGetStatus(consdata->vars[prev - 1]) == SCIP_VARSTATUS_NEGATED)) );
6706 /* either that was the last pair or both, the negated and "normal" variable in front doesn't match var1, so the order is irrelevant */
6707 if( prev == 0 || (var1 != consdata->vars[prev - 1] && var1 != SCIPvarGetNegatedVar(consdata->vars[prev - 1])) )
6708 --prev;
6709 else /* we need to let v at the same position*/
6710 {
6711 consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6712 /* don't decrease v, the same variable may exist up front */
6713 --prev;
6714 continue;
6715 }
6716 }
6717 }
6718 consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6719 }
6720 v = prev;
6721 --prev;
6722 }
6723
6724 consdata->merged = TRUE;
6725
6726 /* check infeasibility */
6727 if( consdata->onesweightsum > consdata->capacity )
6728 {
6729 SCIPdebugMsg(scip, "merge multiples detected cutoff.\n");
6730 *cutoff = TRUE;
6731 return SCIP_OKAY;
6732 }
6733
6734 return SCIP_OKAY;
6735}
6736
6737/** in case the knapsack constraint is independent of every else, solve the knapsack problem (exactly) and apply the
6738 * fixings (dual reductions)
6739 */
6740static
6742 SCIP* scip, /**< SCIP data structure */
6743 SCIP_CONS* cons, /**< knapsack constraint */
6744 int* nfixedvars, /**< pointer to count number of fixings */
6745 int* ndelconss, /**< pointer to count number of deleted constraints */
6746 SCIP_Bool* deleted /**< pointer to store if the constraint is deleted */
6747 )
6748{
6749 SCIP_CONSDATA* consdata;
6750 SCIP_VAR** vars;
6751 SCIP_Real* profits;
6752 int* solitems;
6753 int* nonsolitems;
6754 int* items;
6755 SCIP_Real solval;
6756 SCIP_Bool infeasible;
6757 SCIP_Bool tightened;
6758 SCIP_Bool applicable;
6759 int nsolitems;
6760 int nnonsolitems;
6761 int nvars;
6762 int v;
6763
6764 assert(!SCIPconsIsModifiable(cons));
6765
6766 /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
6767 * use the locks to decide for a dual reduction using this constraint; for example after a restart the cuts which are
6768 * added to the problems have the check flag set to FALSE
6769 */
6770 if( !SCIPconsIsChecked(cons) )
6771 return SCIP_OKAY;
6772
6773 consdata = SCIPconsGetData(cons);
6774 assert(consdata != NULL);
6775
6776 nvars = consdata->nvars;
6777 vars = consdata->vars;
6778
6781 SCIP_CALL( SCIPallocBufferArray(scip, &solitems, nvars) );
6782 SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, nvars) );
6783
6784 applicable = TRUE;
6785
6786 /* check if we can apply the dual reduction; this can be done if the knapsack has the only locks on this constraint;
6787 * collect object values which are the profits of the knapsack problem
6788 */
6789 for( v = 0; v < nvars; ++v )
6790 {
6791 SCIP_VAR* var;
6792 SCIP_Bool negated;
6793
6794 var = vars[v];
6795 assert(var != NULL);
6796
6797 /* the variable should not be (globally) fixed */
6798 assert(SCIPvarGetLbGlobal(var) < 0.5 && SCIPvarGetUbGlobal(var) > 0.5);
6799
6802 {
6803 applicable = FALSE;
6804 break;
6805 }
6806
6807 negated = FALSE;
6808
6809 /* get the active variable */
6810 SCIP_CALL( SCIPvarGetProbvarBinary(&var, &negated) );
6811 assert(SCIPvarIsActive(var));
6812
6813 if( negated )
6814 profits[v] = SCIPvarGetObj(var);
6815 else
6816 profits[v] = -SCIPvarGetObj(var);
6817
6818 SCIPdebugMsg(scip, "variable <%s> -> item size %" SCIP_LONGINT_FORMAT ", profit <%g>\n",
6819 SCIPvarGetName(vars[v]), consdata->weights[v], profits[v]);
6820 items[v] = v;
6821 }
6822
6823 if( applicable )
6824 {
6825 SCIP_Bool success;
6826
6827 SCIPdebugMsg(scip, "the knapsack constraint <%s> is independent to rest of the problem\n", SCIPconsGetName(cons));
6829
6830 /* solve knapsack problem exactly */
6831 SCIP_CALL( SCIPsolveKnapsackExactly(scip, consdata->nvars, consdata->weights, profits, consdata->capacity,
6832 items, solitems, nonsolitems, &nsolitems, &nnonsolitems, &solval, &success) );
6833
6834 if( success )
6835 {
6836 SCIP_VAR* var;
6837
6838 /* apply solution of the knapsack as dual reductions */
6839 for( v = 0; v < nsolitems; ++v )
6840 {
6841 var = vars[solitems[v]];
6842 assert(var != NULL);
6843
6844 SCIPdebugMsg(scip, "variable <%s> only locked up in knapsack constraints: dual presolve <%s>[%.15g,%.15g] >= 1.0\n",
6846 SCIP_CALL( SCIPtightenVarLb(scip, var, 1.0, TRUE, &infeasible, &tightened) );
6847 assert(!infeasible);
6848 assert(tightened);
6849 (*nfixedvars)++;
6850 }
6851
6852 for( v = 0; v < nnonsolitems; ++v )
6853 {
6854 var = vars[nonsolitems[v]];
6855 assert(var != NULL);
6856
6857 SCIPdebugMsg(scip, "variable <%s> has no down locks: dual presolve <%s>[%.15g,%.15g] <= 0.0\n",
6859 SCIP_CALL( SCIPtightenVarUb(scip, var, 0.0, TRUE, &infeasible, &tightened) );
6860 assert(!infeasible);
6861 assert(tightened);
6862 (*nfixedvars)++;
6863 }
6864
6865 SCIP_CALL( SCIPdelCons(scip, cons) );
6866 (*ndelconss)++;
6867 (*deleted) = TRUE;
6868 }
6869 }
6870
6871 SCIPfreeBufferArray(scip, &nonsolitems);
6872 SCIPfreeBufferArray(scip, &solitems);
6873 SCIPfreeBufferArray(scip, &items);
6874 SCIPfreeBufferArray(scip, &profits);
6875
6876 return SCIP_OKAY;
6877}
6878
6879/** check if the knapsack constraint is parallel to objective function; if so update the cutoff bound and avoid that the
6880 * constraint enters the LP by setting the initial and separated flag to FALSE
6881 */
6882static
6884 SCIP* scip, /**< SCIP data structure */
6885 SCIP_CONS* cons, /**< knapsack constraint */
6886 SCIP_CONSHDLRDATA* conshdlrdata /**< knapsack constraint handler data */
6887 )
6888{
6889 SCIP_CONSDATA* consdata;
6890 SCIP_VAR** vars;
6891 SCIP_VAR* var;
6892 SCIP_Real offset;
6893 SCIP_Real scale;
6894 SCIP_Real objval;
6895 SCIP_Bool applicable;
6896 SCIP_Bool negated;
6897 int nobjvars;
6898 int nvars;
6899 int v;
6900
6901 assert(scip != NULL);
6902 assert(cons != NULL);
6903 assert(conshdlrdata != NULL);
6904
6905 consdata = SCIPconsGetData(cons);
6906 assert(consdata != NULL);
6907
6908 nvars = consdata->nvars;
6909 nobjvars = SCIPgetNObjVars(scip);
6910
6911 /* check if the knapsack constraints has the same number of variables as the objective function and if the initial
6912 * and/or separated flag is set to FALSE
6913 */
6914 if( nvars != nobjvars || (!SCIPconsIsInitial(cons) && !SCIPconsIsSeparated(cons)) )
6915 return SCIP_OKAY;
6916
6917 /* There are no variables in the ojective function and in the constraint. Thus, the constraint is redundant. Since we
6918 * have a pure feasibility problem, we do not want to set a cutoff or lower bound.
6919 */
6920 if( nobjvars == 0 )
6921 return SCIP_OKAY;
6922
6923 vars = consdata->vars;
6924 assert(vars != NULL);
6925
6926 applicable = TRUE;
6927 offset = 0.0;
6928 scale = 1.0;
6929
6930 for( v = 0; v < nvars && applicable; ++v )
6931 {
6932 negated = FALSE;
6933 var = vars[v];
6934 assert(var != NULL);
6935
6936 if( SCIPvarIsNegated(var) )
6937 {
6938 negated = TRUE;
6939 var = SCIPvarGetNegatedVar(var);
6940 assert(var != NULL);
6941 }
6942
6943 objval = SCIPvarGetObj(var);
6944
6945 /* if a variable has a zero objective coefficient the knapsack constraint is not parallel to objective function */
6946 if( SCIPisZero(scip, objval) )
6947 applicable = FALSE;
6948 else
6949 {
6950 SCIP_Real weight;
6951
6952 weight = (SCIP_Real)consdata->weights[v];
6953
6954 if( negated )
6955 {
6956 if( v == 0 )
6957 {
6958 /* the first variable defines the scale */
6959 scale = weight / -objval;
6960
6961 offset += weight;
6962 }
6963 else if( SCIPisEQ(scip, -objval * scale, weight) )
6964 offset += weight;
6965 else
6966 applicable = FALSE;
6967 }
6968 else if( v == 0 )
6969 {
6970 /* the first variable define the scale */
6971 scale = weight / objval;
6972 }
6973 else if( !SCIPisEQ(scip, objval * scale, weight) )
6974 applicable = FALSE;
6975 }
6976 }
6977
6978 if( applicable )
6979 {
6980 if( SCIPisPositive(scip, scale) && conshdlrdata->detectcutoffbound )
6981 {
6982 SCIP_Real cutoffbound;
6983
6984 /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
6987
6988 cutoffbound = (consdata->capacity - offset) / scale;
6989
6990 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
6991 SCIPconsGetName(cons), cutoffbound);
6992
6993 /* increase the cutoff bound value by an epsilon to ensue that solution with the value of the cutoff bound are
6994 * still excepted
6995 */
6996 cutoffbound += SCIPcutoffbounddelta(scip);
6997
6998 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
6999 SCIPconsGetName(cons), cutoffbound);
7000
7001 if( cutoffbound < SCIPgetCutoffbound(scip) )
7002 {
7003 SCIPdebugMsg(scip, "update cutoff bound <%g>\n", cutoffbound);
7004
7005 SCIP_CALL( SCIPupdateCutoffbound(scip, cutoffbound) );
7006 }
7007 else
7008 {
7009 /* in case the cutoff bound is worse then currently known one we avoid additionaly enforcement and
7010 * propagation
7011 */
7014 }
7015 }
7016 else if( SCIPisNegative(scip, scale) && conshdlrdata->detectlowerbound )
7017 {
7018 SCIP_Real lowerbound;
7019
7020 /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
7023
7024 lowerbound = (consdata->capacity - offset) / scale;
7025
7026 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a lower bound <%g>\n",
7027 SCIPconsGetName(cons), lowerbound);
7028
7030 }
7031 }
7032
7033 return SCIP_OKAY;
7034}
7035
7036/** sort the variables and weights w.r.t. the clique partition; thereby ensure the current order of the variables when a
7037 * weight of one variable is greater or equal another weight and both variables are in the same cliques */
7038static
7040 SCIP* scip, /**< SCIP data structure */
7041 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
7042 SCIP_VAR** vars, /**< array for sorted variables */
7043 SCIP_Longint* weights, /**< array for sorted weights */
7044 int* cliquestartposs, /**< starting position array for each clique */
7045 SCIP_Bool usenegatedclique /**< should negated or normal clique partition be used */
7046 )
7047{
7048 SCIP_VAR** origvars;
7049 int norigvars;
7050 SCIP_Longint* origweights;
7051 int* cliquepartition;
7052 int ncliques;
7053
7054 SCIP_VAR*** varpointers;
7055 SCIP_Longint** weightpointers;
7056 int* cliquecount;
7057
7058 int nextpos;
7059 int c;
7060 int v;
7061
7062 assert(scip != NULL);
7063 assert(consdata != NULL);
7064 assert(vars != NULL);
7065 assert(weights != NULL);
7066 assert(cliquestartposs != NULL);
7067
7068 origweights = consdata->weights;
7069 origvars = consdata->vars;
7070 norigvars = consdata->nvars;
7071
7072 assert(origvars != NULL || norigvars == 0);
7073 assert(origweights != NULL || norigvars == 0);
7074
7075 if( norigvars == 0 )
7076 return SCIP_OKAY;
7077
7078 if( usenegatedclique )
7079 {
7080 assert(consdata->negcliquepartitioned);
7081
7082 cliquepartition = consdata->negcliquepartition;
7083 ncliques = consdata->nnegcliques;
7084 }
7085 else
7086 {
7087 assert(consdata->cliquepartitioned);
7088
7089 cliquepartition = consdata->cliquepartition;
7090 ncliques = consdata->ncliques;
7091 }
7092
7093 assert(cliquepartition != NULL);
7094 assert(ncliques > 0);
7095
7096 /* we first count all clique items and alloc temporary memory for a bucket sort */
7097 SCIP_CALL( SCIPallocBufferArray(scip, &cliquecount, ncliques) );
7098 BMSclearMemoryArray(cliquecount, ncliques);
7099
7100 /* first we count for each clique the number of elements */
7101 for( v = norigvars - 1; v >= 0; --v )
7102 {
7103 assert(0 <= cliquepartition[v] && cliquepartition[v] < ncliques);
7104 ++(cliquecount[cliquepartition[v]]);
7105 }
7106
7107 /*@todo: maybe it is better to put largest cliques up front */
7108
7109#ifndef NDEBUG
7110 BMSclearMemoryArray(vars, norigvars);
7111 BMSclearMemoryArray(weights, norigvars);
7112#endif
7113 SCIP_CALL( SCIPallocBufferArray(scip, &varpointers, ncliques) );
7114 SCIP_CALL( SCIPallocBufferArray(scip, &weightpointers, ncliques) );
7115
7116 nextpos = 0;
7117 /* now we initialize all start pointers for each clique, so they will be ordered */
7118 for( c = 0; c < ncliques; ++c )
7119 {
7120 /* to reach the goal that all variables of each clique will be standing next to each other we will initialize the
7121 * starting pointers for each clique by adding the number of each clique to the last clique starting pointer
7122 * e.g. clique1 has 4 elements and clique2 has 3 elements the the starting pointer for clique1 will be the pointer
7123 * to vars[0], the starting pointer to clique2 will be the pointer to vars[4] and to clique3 it will be
7124 * vars[7]
7125 *
7126 */
7127 varpointers[c] = (SCIP_VAR**) (vars + nextpos);
7128 cliquestartposs[c] = nextpos;
7129 weightpointers[c] = (SCIP_Longint*) (weights + nextpos);
7130 assert(cliquecount[c] > 0);
7131 nextpos += cliquecount[c];
7132 assert(nextpos > 0);
7133 }
7134 assert(nextpos == norigvars);
7135 cliquestartposs[c] = nextpos;
7136
7137 /* now we copy all variable and weights to the right order */
7138 for( v = 0; v < norigvars; ++v )
7139 {
7140 *(varpointers[cliquepartition[v]]) = origvars[v]; /*lint !e613*/
7141 ++(varpointers[cliquepartition[v]]);
7142 *(weightpointers[cliquepartition[v]]) = origweights[v]; /*lint !e613*/
7143 ++(weightpointers[cliquepartition[v]]);
7144 }
7145#ifndef NDEBUG
7146 for( v = 0; v < norigvars; ++v )
7147 {
7148 assert(vars[v] != NULL);
7149 assert(weights[v] > 0);
7150 }
7151#endif
7152
7153 /* free temporary memory */
7154 SCIPfreeBufferArray(scip, &weightpointers);
7155 SCIPfreeBufferArray(scip, &varpointers);
7156 SCIPfreeBufferArray(scip, &cliquecount);
7157
7158 return SCIP_OKAY;
7159}
7160
7161/** deletes all fixed variables from knapsack constraint, and replaces variables with binary representatives */
7162static
7164 SCIP* scip, /**< SCIP data structure */
7165 SCIP_CONS* cons, /**< knapsack constraint */
7166 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off, or NULL if this
7167 * information is not needed; in this case, we apply all fixings
7168 * instead of stopping after the first infeasible one */
7169 )
7170{
7171 SCIP_CONSDATA* consdata;
7172 int v;
7173
7174 assert(scip != NULL);
7175 assert(cons != NULL);
7176
7177 consdata = SCIPconsGetData(cons);
7178 assert(consdata != NULL);
7179 assert(consdata->nvars == 0 || consdata->vars != NULL);
7180
7181 if( cutoff != NULL )
7182 *cutoff = FALSE;
7183
7184 SCIPdebugMsg(scip, "apply fixings:\n");
7186
7187 /* check infeasibility */
7188 if ( consdata->onesweightsum > consdata->capacity )
7189 {
7190 SCIPdebugMsg(scip, "apply fixings detected cutoff.\n");
7191
7192 if( cutoff != NULL )
7193 *cutoff = TRUE;
7194
7195 return SCIP_OKAY;
7196 }
7197
7198 /* all multi-aggregations should be resolved */
7199 consdata->existmultaggr = FALSE;
7200
7201 v = 0;
7202 while( v < consdata->nvars )
7203 {
7204 SCIP_VAR* var;
7205
7206 var = consdata->vars[v];
7207 assert(SCIPvarIsBinary(var));
7208
7209 if( SCIPvarGetLbGlobal(var) > 0.5 )
7210 {
7211 assert(SCIPisFeasEQ(scip, SCIPvarGetUbGlobal(var), 1.0));
7212 consdata->capacity -= consdata->weights[v];
7213 SCIP_CALL( delCoefPos(scip, cons, v) );
7214 consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
7215 }
7216 else if( SCIPvarGetUbGlobal(var) < 0.5 )
7217 {
7218 assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(var), 0.0));
7219 SCIP_CALL( delCoefPos(scip, cons, v) );
7220 }
7221 else
7222 {
7223 SCIP_VAR* repvar;
7224 SCIP_VAR* negvar;
7225 SCIP_VAR* workvar;
7226 SCIP_Longint weight;
7227 SCIP_Bool negated;
7228
7229 weight = consdata->weights[v];
7230
7231 /* get binary representative of variable */
7232 SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &repvar, &negated) );
7233 assert(repvar != NULL);
7234
7235 /* check for multi-aggregation */
7236 if( SCIPvarIsNegated(repvar) )
7237 {
7238 workvar = SCIPvarGetNegatedVar(repvar);
7239 assert(workvar != NULL);
7240 negated = TRUE;
7241 }
7242 else
7243 {
7244 workvar = repvar;
7245 negated = FALSE;
7246 }
7247
7248 /* @todo maybe resolve the problem that the eliminating of the multi-aggregation leads to a non-knapsack
7249 * constraint (converting into a linear constraint), for example the multi-aggregation consist of a non-binary
7250 * variable or due to resolving now their are non-integral coefficients or a non-integral capacity
7251 *
7252 * If repvar is not negated so workvar = repvar, otherwise workvar = 1 - repvar. This means,
7253 * weight * workvar = weight * (a_1*y_1 + ... + a_n*y_n + c)
7254 *
7255 * The explanation for the following block:
7256 * 1a) If repvar is a multi-aggregated variable weight * repvar should be replaced by
7257 * weight * (a_1*y_1 + ... + a_n*y_n + c).
7258 * 1b) If repvar is a negated variable of a multi-aggregated variable weight * repvar should be replaced by
7259 * weight - weight * (a_1*y_1 + ... + a_n*y_n + c), for better further use here we switch the sign of weight
7260 * so now we have the replacement -weight + weight * (a_1*y_1 + ... + a_n*y_n + c).
7261 * 2) For all replacement variable we check:
7262 * 2a) weight * a_i < 0 than we add -weight * a_i * y_i_neg to the constraint and adjust the capacity through
7263 * capacity -= weight * a_i caused by the negation of y_i.
7264 * 2b) weight * a_i >= 0 than we add weight * a_i * y_i to the constraint.
7265 * 3a) If repvar was not negated we need to subtract weight * c from capacity.
7266 * 3b) If repvar was negated we need to subtract weight * (c - 1) from capacity(note we switched the sign of
7267 * weight in this case.
7268 */
7270 {
7271 SCIP_VAR** aggrvars;
7272 SCIP_Real* aggrscalars;
7273 SCIP_Real aggrconst;
7274 int naggrvars;
7275 int i;
7276
7278 naggrvars = SCIPvarGetMultaggrNVars(workvar);
7279 aggrvars = SCIPvarGetMultaggrVars(workvar);
7280 aggrscalars = SCIPvarGetMultaggrScalars(workvar);
7281 aggrconst = SCIPvarGetMultaggrConstant(workvar);
7282 assert((aggrvars != NULL && aggrscalars != NULL) || naggrvars == 0);
7283
7284 if( !SCIPisIntegral(scip, weight * aggrconst) )
7285 {
7286 SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrconst = %g\n", weight*aggrconst);
7287 return SCIP_ERROR;
7288 }
7289
7290 /* if workvar was negated, we have to flip the weight */
7291 if( negated )
7292 weight *= -1;
7293
7294 for( i = naggrvars - 1; i >= 0; --i )
7295 {
7296 assert(aggrvars != NULL);
7297 assert(aggrscalars != NULL);
7298
7299 if( !SCIPvarIsBinary(aggrvars[i]) )
7300 {
7301 SCIPerrorMessage("try to resolve a multi-aggregation with a non-binary %svariable <%s> with bounds [%g,%g]\n",
7302 SCIPvarIsIntegral(aggrvars[i]) ? "integral " : "", SCIPvarGetName(aggrvars[i]), SCIPvarGetLbGlobal(aggrvars[i]), SCIPvarGetUbGlobal(aggrvars[i]));
7303 return SCIP_ERROR;
7304 }
7305 if( !SCIPisIntegral(scip, weight * aggrscalars[i]) )
7306 {
7307 SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrscalars = %g\n", weight*aggrscalars[i]);
7308 return SCIP_ERROR;
7309 }
7310 /* if the new coefficient is smaller than zero, we need to add the negated variable instead and adjust the capacity */
7311 if( SCIPisNegative(scip, weight * aggrscalars[i]) )
7312 {
7313 SCIP_CALL( SCIPgetNegatedVar(scip, aggrvars[i], &negvar) );
7314 assert(negvar != NULL);
7315 SCIP_CALL( addCoef(scip, cons, negvar, (SCIP_Longint)(SCIPfloor(scip, -weight * aggrscalars[i] + 0.5))) );
7316 consdata->capacity -= (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5));
7317 }
7318 else
7319 {
7320 SCIP_CALL( addCoef(scip, cons, aggrvars[i], (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5))) );
7321 }
7322 }
7323 /* delete old coefficient */
7324 SCIP_CALL( delCoefPos(scip, cons, v) );
7325
7326 /* adjust the capacity with the aggregation constant and if necessary the extra weight through the negation */
7327 if( negated )
7328 consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * (aggrconst - 1) + 0.5);
7329 else
7330 consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * aggrconst + 0.5);
7331
7332 if( consdata->capacity < 0 )
7333 {
7334 if( cutoff != NULL )
7335 {
7336 *cutoff = TRUE;
7337 break;
7338 }
7339 }
7340 }
7341 /* check, if the variable should be replaced with the representative */
7342 else if( repvar != var )
7343 {
7344 /* delete old (aggregated) variable */
7345 SCIP_CALL( delCoefPos(scip, cons, v) );
7346
7347 /* add representative instead */
7348 SCIP_CALL( addCoef(scip, cons, repvar, weight) );
7349 }
7350 else
7351 ++v;
7352 }
7353 }
7354 assert(consdata->onesweightsum == 0);
7355
7356 SCIPdebugMsg(scip, "after applyFixings, before merging:\n");
7358
7359 /* if aggregated variables have been replaced, multiple entries of the same variable are possible and we have to
7360 * clean up the constraint
7361 */
7362 if( cutoff != NULL && !(*cutoff) )
7363 {
7364 SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
7365 SCIPdebugMsg(scip, "after applyFixings and merging:\n");
7367 }
7368
7369 return SCIP_OKAY;
7370}
7371
7372
7373/** propagation method for knapsack constraints */
7374static
7376 SCIP* scip, /**< SCIP data structure */
7377 SCIP_CONS* cons, /**< knapsack constraint */
7378 SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
7379 SCIP_Bool* redundant, /**< pointer to store whether constraint is redundant */
7380 int* nfixedvars, /**< pointer to count number of fixings */
7381 SCIP_Bool usenegatedclique /**< should negated clique information be used */
7382 )
7383{
7384 SCIP_CONSDATA* consdata;
7385 SCIP_Bool infeasible;
7386 SCIP_Bool tightened;
7387 SCIP_Longint* secondmaxweights;
7388 SCIP_Longint minweightsum;
7389 SCIP_Longint residualcapacity;
7390
7391 int nvars;
7392 int i;
7393 int nnegcliques;
7394
7395 SCIP_VAR** myvars;
7396 SCIP_Longint* myweights;
7397 int* cliquestartposs;
7398 int* cliqueendposs;
7399 SCIP_Longint localminweightsum;
7400 SCIP_Bool foundmax;
7401 int c;
7402
7403 assert(scip != NULL);
7404 assert(cons != NULL);
7405 assert(cutoff != NULL);
7406 assert(redundant != NULL);
7407 assert(nfixedvars != NULL);
7408
7409 consdata = SCIPconsGetData(cons);
7410 assert(consdata != NULL);
7411
7412 *cutoff = FALSE;
7413 *redundant = FALSE;
7414
7415 SCIPdebugMsg(scip, "propagating knapsack constraint <%s>\n", SCIPconsGetName(cons));
7416
7417 /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */
7419 {
7420 SCIP_CALL( SCIPincConsAge(scip, cons) );
7421 }
7422
7423#ifndef NDEBUG
7424 /* assert that only active or negated variables are present */
7425 for( i = 0; i < consdata->nvars && consdata->merged; ++i )
7426 {
7427 assert(SCIPvarIsActive(consdata->vars[i]) || SCIPvarIsNegated(consdata->vars[i]) || SCIPvarGetStatus(consdata->vars[i]) == SCIP_VARSTATUS_FIXED);
7428 }
7429#endif
7430
7431 usenegatedclique = usenegatedclique && consdata->merged;
7432
7433 /* init for debugging */
7434 myvars = NULL;
7435 myweights = NULL;
7436 cliquestartposs = NULL;
7437 secondmaxweights = NULL;
7438 minweightsum = 0;
7439 nvars = consdata->nvars;
7440 /* make sure, the items are sorted by non-increasing weight */
7441 sortItems(consdata);
7442
7443 do
7444 {
7445 localminweightsum = 0;
7446
7447 /* (1) compute the minimum weight of the knapsack constraint using negated clique information;
7448 * a negated clique means, that at most one of the clique variables can be zero
7449 * - minweightsum = sum_{negated cliques C} ( sum(wi : i \in C) - W_max(C) ), where W_max(C) is the maximal weight of C
7450 *
7451 * if for i \in C (a negated clique) oneweightsum + minweightsum - wi + W_max(C) > capacity => xi = 1
7452 * since replacing i with the element of maximal weight leads to infeasibility
7453 */
7454 if( usenegatedclique && nvars > 0 )
7455 {
7456 SCIP_CONSHDLRDATA* conshdlrdata;
7457 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7458 assert(conshdlrdata != NULL);
7459
7460 /* compute clique partitions */
7461 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
7462 nnegcliques = consdata->nnegcliques;
7463
7464 /* if we have no real negated cliques we can stop here */
7465 if( nnegcliques == nvars )
7466 {
7467 /* run the standard algorithm that does not involve cliques */
7468 usenegatedclique = FALSE;
7469 break;
7470 }
7471
7472 /* allocate temporary memory and initialize it */
7473 SCIP_CALL( SCIPduplicateBufferArray(scip, &myvars, consdata->vars, nvars) );
7474 SCIP_CALL( SCIPduplicateBufferArray(scip, &myweights, consdata->weights, nvars) ) ;
7475 SCIP_CALL( SCIPallocBufferArray(scip, &cliquestartposs, nnegcliques + 1) );
7476 SCIP_CALL( SCIPallocBufferArray(scip, &cliqueendposs, nnegcliques) );
7477 SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
7478 BMSclearMemoryArray(secondmaxweights, nnegcliques);
7479
7480 /* resort variables to avoid quadratic algorithm later on */
7481 SCIP_CALL( stableSort(scip, consdata, myvars, myweights, cliquestartposs, TRUE) );
7482
7483 /* save the end positions of the cliques because start positions are moved in the following loop */
7484 for( c = 0; c < nnegcliques; ++c )
7485 {
7486 cliqueendposs[c] = cliquestartposs[c+1] - 1;
7487 assert(cliqueendposs[c] - cliquestartposs[c] >= 0);
7488 }
7489
7490 c = 0;
7491 foundmax = FALSE;
7492 i = 0;
7493
7494 while( i < nvars )
7495 {
7496 /* ignore variables of the negated clique which are fixed to one since these are counted in
7497 * consdata->onesweightsum
7498 */
7499
7500 /* if there are only one variable negated cliques left we can stop */
7501 if( nnegcliques - c == nvars - i )
7502 {
7503 minweightsum += localminweightsum;
7504 localminweightsum = 0;
7505 break;
7506 }
7507
7508 /* for summing up the minimum active weights due to cliques we have to omit the biggest weights of each
7509 * clique, we can only skip this clique if this variables is not fixed to zero, otherwise we have to fix all
7510 * other clique variables to one
7511 */
7512 if( cliquestartposs[c] == i )
7513 {
7514 assert(myweights[i] > 0);
7515 ++c;
7516 minweightsum += localminweightsum;
7517 localminweightsum = 0;
7518 foundmax = TRUE;
7519
7520 if( SCIPvarGetLbLocal(myvars[i]) > 0.5 )
7521 foundmax = FALSE;
7522
7523 if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7524 {
7525 ++i;
7526 continue;
7527 }
7528 }
7529
7530 if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7531 {
7532 assert(myweights[i] > 0);
7533
7534 if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7535 {
7536 assert(myweights[i] <= myweights[cliquestartposs[c - 1]]);
7537
7538 if( !foundmax )
7539 {
7540 foundmax = TRUE;
7541
7542 /* overwrite cliquestartpos to the position of the first unfixed variable in this clique */
7543 cliquestartposs[c - 1] = i;
7544 ++i;
7545
7546 continue;
7547 }
7548 /* memorize second max weight for each clique */
7549 if( secondmaxweights[c - 1] == 0 )
7550 secondmaxweights[c - 1] = myweights[i];
7551
7552 localminweightsum += myweights[i];
7553 }
7554 /* we found a fixed variable to zero so all other variables in this negated clique have to be fixed to one */
7555 else
7556 {
7557 int v;
7558 /* fix all other variables of the negated clique to 1 */
7559 for( v = cliquestartposs[c - 1]; v < cliquestartposs[c]; ++v )
7560 {
7561 if( v != i && SCIPvarGetLbLocal(myvars[v]) < 0.5 )
7562 {
7563 SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[v]));
7564 SCIP_CALL( SCIPinferBinvarCons(scip, myvars[v], TRUE, cons, SCIPvarGetIndex(myvars[i]), &infeasible, &tightened) );
7565
7566 if( infeasible )
7567 {
7568 assert( SCIPvarGetUbLocal(myvars[v]) < 0.5 );
7569
7570 /* analyze the infeasibility if conflict analysis is applicable */
7572 {
7573 /* conflict analysis can only be applied in solving stage */
7575
7576 /* initialize the conflict analysis */
7578
7579 /* add the two variables which are fixed to zero within a negated clique */
7580 SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[i]) );
7581 SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[v]) );
7582
7583 /* start the conflict analysis */
7585 }
7586 *cutoff = TRUE;
7587 break;
7588 }
7589 assert(tightened);
7590 ++(*nfixedvars);
7592 }
7593 }
7594
7595 /* reset local minweightsum for clique because all fixed to one variables are now counted in consdata->onesweightsum */
7596 localminweightsum = 0;
7597 /* we can jump to the end of this clique */
7598 i = cliqueendposs[c - 1];
7599
7600 if( *cutoff )
7601 break;
7602 }
7603 }
7604 ++i;
7605 }
7606 /* add last clique minweightsum */
7607 minweightsum += localminweightsum;
7608
7609 SCIPdebugMsg(scip, "knapsack constraint <%s> has minimum weight sum of <%" SCIP_LONGINT_FORMAT ">\n",
7610 SCIPconsGetName(cons), minweightsum + consdata->onesweightsum );
7611
7612 /* check, if weights of fixed variables don't exceeds knapsack capacity */
7613 if( !(*cutoff) && consdata->capacity >= minweightsum + consdata->onesweightsum )
7614 {
7615 SCIP_Longint maxcliqueweight = -1LL;
7616
7617 /* loop over cliques */
7618 for( c = 0; c < nnegcliques; ++c )
7619 {
7620 SCIP_VAR* maxvar;
7621 SCIP_Bool maxvarfixed;
7622 int endvarposclique;
7623 int startvarposclique;
7624
7625 assert(myvars != NULL);
7626 assert(nnegcliques == consdata->nnegcliques);
7627 assert(myweights != NULL);
7628 assert(secondmaxweights != NULL);
7629 assert(cliquestartposs != NULL);
7630
7631 endvarposclique = cliqueendposs[c];
7632 startvarposclique = cliquestartposs[c];
7633
7634 maxvar = myvars[startvarposclique];
7635
7636 /* no need to process this negated clique because all variables are already fixed (which we detect from a fixed maxvar) */
7637 if( SCIPvarGetUbLocal(maxvar) - SCIPvarGetLbLocal(maxvar) < 0.5 )
7638 continue;
7639
7640 maxcliqueweight = myweights[startvarposclique];
7641 maxvarfixed = FALSE;
7642 /* if the sum of all weights of fixed variables to one plus the minimalweightsum (minimal weight which is already
7643 * used in this knapsack due to negated cliques) plus any weight minus the second largest weight in this clique
7644 * exceeds the capacity the maximum weight variable can be fixed to zero.
7645 */
7646 if( consdata->onesweightsum + minweightsum + (maxcliqueweight - secondmaxweights[c]) > consdata->capacity )
7647 {
7648#ifndef NDEBUG
7649 SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7650#endif
7651 assert(maxcliqueweight >= secondmaxweights[c]);
7652 assert(SCIPvarGetLbLocal(maxvar) < 0.5 && SCIPvarGetUbLocal(maxvar) > 0.5);
7653
7654 SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(maxvar));
7656 SCIP_CALL( SCIPinferBinvarCons(scip, maxvar, FALSE, cons, cliquestartposs[c], &infeasible, &tightened) );
7657 assert(consdata->onesweightsum == oldonesweightsum); /* cppcheck-suppress knownConditionTrueFalse */
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 noldchgcoefs;
8181 int nvars;
8182 int v;
8183 int w;
8184
8185 assert(scip != NULL);
8186 assert(cons != NULL);
8187 assert(ndelconss != NULL);
8188 assert(nchgcoefs != NULL);
8189 assert(nchgsides != NULL);
8190 assert(naddconss != NULL);
8191
8192 consdata = SCIPconsGetData(cons);
8193 assert(consdata != NULL);
8194 assert(consdata->nvars >= 2);
8195 assert(consdata->weightsum > consdata->capacity);
8196
8197 noldchgcoefs = *nchgcoefs;
8198 vars = consdata->vars;
8199 weights = consdata->weights;
8200 nvars = consdata->nvars;
8201 capacity = consdata->capacity;
8202 sum = 0;
8203
8204 /* search for maximal fitting items */
8205 for( v = 0; v < nvars && sum + weights[v] <= capacity; ++v )
8206 sum += weights[v];
8207
8208 assert(v < nvars);
8209
8210 /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8211 if( SCIPconsGetNUpgradeLocks(cons) == 0 && v == nvars - 1 )
8212 {
8213 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8214 assert(SCIPconsIsDeleted(cons));
8215
8216 return SCIP_OKAY;
8217 }
8218
8219 if( v < nvars - 1 )
8220 {
8221 /* try to delete variables */
8222 SCIP_CALL( deleteRedundantVars(scip, cons, sum, v, nchgcoefs, nchgsides, naddconss) );
8223 assert(consdata->nvars > 1);
8224
8225 /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8226 if( SCIPconsGetNUpgradeLocks(cons) == 0 && v == consdata->nvars - 1 )
8227 {
8228 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8229 assert(SCIPconsIsDeleted(cons));
8230 }
8231
8232 return SCIP_OKAY;
8233 }
8234
8235 /* if we already found some redundant variables, stop here */
8236 if( *nchgcoefs > noldchgcoefs )
8237 return SCIP_OKAY;
8238
8239 assert(vars == consdata->vars);
8240 assert(weights == consdata->weights);
8241 assert(nvars == consdata->nvars);
8242 assert(capacity == consdata->capacity);
8243
8244 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
8245 assert(conshdlrdata != NULL);
8246 /* calculate clique partition */
8247 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
8248
8249 /* check for real existing cliques */
8250 if( consdata->cliquepartition[v] < v )
8251 {
8252 SCIP_Longint sumfront;
8253 SCIP_Longint maxactduetoclqfront;
8254 int* clqpart;
8255 int cliquenum;
8256
8257 sumfront = 0;
8258 maxactduetoclqfront = 0;
8259
8260 clqpart = consdata->cliquepartition;
8261 cliquenum = 0;
8262
8263 /* calculate maximal activity due to cliques */
8264 for( w = 0; w < nvars; ++w )
8265 {
8266 assert(clqpart[w] >= 0 && clqpart[w] <= w);
8267 if( clqpart[w] == cliquenum )
8268 {
8269 if( maxactduetoclqfront + weights[w] <= capacity )
8270 {
8271 maxactduetoclqfront += weights[w];
8272 ++cliquenum;
8273 }
8274 else
8275 break;
8276 }
8277 sumfront += weights[w];
8278 }
8279 assert(w >= v);
8280
8281 /* if all items fit, then delete the whole constraint but create clique constraints which led to this
8282 * information
8283 */
8284 if( conshdlrdata->disaggregation && SCIPconsGetNUpgradeLocks(cons) == 0 && w == nvars )
8285 {
8286 SCIP_VAR** clqvars;
8287 int nclqvars;
8288 int c;
8289 int ncliques;
8290
8291 assert(maxactduetoclqfront <= capacity);
8292
8293 SCIPdebugMsg(scip, "Found redundant constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8294
8295 ncliques = consdata->ncliques;
8296
8297 /* allocate temporary memory */
8298 SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, nvars - ncliques + 1) );
8299
8300 for( c = 0; c < ncliques; ++c )
8301 {
8302 nclqvars = 0;
8303 for( w = 0; w < nvars; ++w )
8304 {
8305 if( clqpart[w] == c )
8306 {
8307 clqvars[nclqvars] = vars[w];
8308 ++nclqvars;
8309 }
8310 }
8311
8312 /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8313 if( nclqvars > 1 )
8314 {
8315 SCIP_CONS* cliquecons;
8316 char name[SCIP_MAXSTRLEN];
8317
8318 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8319 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8323 SCIPconsIsStickingAtNode(cons)) );
8324
8325 /* add the special constraint to the problem */
8326 SCIPdebugMsg(scip, " -> adding clique constraint: ");
8327 SCIPdebugPrintCons(scip, cliquecons, NULL);
8328 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8329 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8330 ++(*naddconss);
8331 }
8332 }
8333
8334 /* delete old constraint */
8335 SCIP_CALL( SCIPdelCons(scip, cons) );
8336 ++(*ndelconss);
8337
8338 SCIPfreeBufferArray(scip, &clqvars);
8339
8340 return SCIP_OKAY;
8341 }
8342
8343 if( w > v && w < nvars - 1 )
8344 {
8345 /* try to delete variables */
8346 SCIP_CALL( deleteRedundantVars(scip, cons, sumfront, w, nchgcoefs, nchgsides, naddconss) );
8347 }
8348 }
8349
8350 return SCIP_OKAY;
8351}
8352
8353/** divides weights by their greatest common divisor and divides capacity by the same value, rounding down the result */
8354static
8356 SCIP_CONS* cons, /**< knapsack constraint */
8357 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
8358 int* nchgsides /**< pointer to count number of side changes */
8359 )
8360{
8361 SCIP_CONSDATA* consdata;
8362 SCIP_Longint gcd;
8363 int i;
8364
8365 assert(nchgcoefs != NULL);
8366 assert(nchgsides != NULL);
8367 assert(!SCIPconsIsModifiable(cons));
8368
8369 consdata = SCIPconsGetData(cons);
8370 assert(consdata != NULL);
8371 assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
8372 assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
8373 assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
8374 assert(consdata->nvars >= 1);
8375
8376 /* sort items, because we can stop earlier if the smaller weights are evaluated first */
8377 sortItems(consdata);
8378
8379 gcd = consdata->weights[consdata->nvars-1];
8380 for( i = consdata->nvars-2; i >= 0 && gcd >= 2; --i )
8381 {
8382 assert(SCIPvarGetLbLocal(consdata->vars[i]) < 0.5);
8383 assert(SCIPvarGetUbLocal(consdata->vars[i]) > 0.5); /* all fixed variables should have been removed */
8384
8385 gcd = SCIPcalcGreComDiv(gcd, consdata->weights[i]);
8386 }
8387
8388 if( gcd >= 2 )
8389 {
8390 SCIPdebugMessage("knapsack constraint <%s>: dividing weights by %" SCIP_LONGINT_FORMAT "\n", SCIPconsGetName(cons), gcd);
8391
8392 for( i = 0; i < consdata->nvars; ++i )
8393 {
8394 consdataChgWeight(consdata, i, consdata->weights[i]/gcd);
8395 }
8396 consdata->capacity /= gcd;
8397 (*nchgcoefs) += consdata->nvars;
8398 (*nchgsides)++;
8399
8400 /* weight should still be sorted, because the reduction preserves this */
8401#ifndef NDEBUG
8402 for( i = consdata->nvars - 1; i > 0; --i )
8403 assert(consdata->weights[i] <= consdata->weights[i - 1]);
8404#endif
8405 consdata->sorted = TRUE;
8406 }
8407}
8408
8409/** dual weights tightening for knapsack constraints
8410 *
8411 * 1. a) check if all two pairs exceed the capacity, then we can upgrade this constraint to a set-packing constraint
8412 * b) check if all but the smallest weight fit into the knapsack, then we can upgrade this constraint to a logicor
8413 * constraint
8414 *
8415 * 2. check if besides big coefficients, that fit only by itself, for a certain amount of variables all combination of
8416 * these are a minimal cover, then might reduce the weights and the capacity, e.g.
8417 *
8418 * +219y1 + 180y2 + 74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8419 *
8420 * 3. use the duality between a^Tx <= capacity <=> a^T~x >= weightsum - capacity to tighten weights, e.g.
8421 *
8422 * 11x1 + 10x2 + 7x3 + 7x4 + 5x5 <= 27 <=> 11~x1 + 10~x2 + 7~x3 + 7~x4 + 5~x5 >= 13
8423 *
8424 * the above constraint can be changed to 8~x1 + 8~x2 + 6.5~x3 + 6.5~x4 + 5~x5 >= 13
8425 *
8426 * 16~x1 + 16~x2 + 13~x3 + 13~x4 + 10~x5 >= 26 <=> 16x1 + 16x2 + 13x3 + 13x4 + 10x5 <= 42
8427 */
8428static
8430 SCIP* scip, /**< SCIP data structure */
8431 SCIP_CONS* cons, /**< knapsack constraint */
8432 int* ndelconss, /**< pointer to store the amount of deleted constraints */
8433 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8434 int* nchgsides, /**< pointer to store the amount of changed sides */
8435 int* naddconss /**< pointer to count number of added constraints */
8436 )
8437{
8438 SCIP_CONSDATA* consdata;
8439 SCIP_Longint* weights;
8440 SCIP_Longint dualcapacity;
8441 SCIP_Longint reductionsum;
8442 SCIP_Longint capacity;
8443 SCIP_Longint exceedsum;
8444 int oldnchgcoefs;
8445 int nvars;
8446 int vbig;
8447 int v;
8448 int w;
8449#ifndef NDEBUG
8450 int oldnchgsides;
8451#endif
8452
8453 assert(scip != NULL);
8454 assert(cons != NULL);
8455 assert(ndelconss != NULL);
8456 assert(nchgcoefs != NULL);
8457 assert(nchgsides != NULL);
8458 assert(naddconss != NULL);
8459
8460 if( SCIPconsGetNUpgradeLocks(cons) >= 1 )
8461 return SCIP_OKAY;
8462
8463#ifndef NDEBUG
8464 oldnchgsides = *nchgsides;
8465#endif
8466
8467 consdata = SCIPconsGetData(cons);
8468 assert(consdata != NULL);
8469 assert(consdata->weightsum > consdata->capacity);
8470 assert(consdata->nvars >= 2);
8471 assert(consdata->sorted);
8472
8473 /* constraint should be merged */
8474 assert(consdata->merged);
8475
8476 nvars = consdata->nvars;
8477 weights = consdata->weights;
8478 capacity = consdata->capacity;
8479
8480 oldnchgcoefs = *nchgcoefs;
8481
8482 /* case 1. */
8483 if( weights[nvars - 1] + weights[nvars - 2] > capacity )
8484 {
8485 SCIP_CONS* newcons;
8486
8487 /* two variable are enough to exceed the constraint, so we can update it to a set-packing
8488 *
8489 * e.g. 5x1 + 4x2 + 3x3 <= 5 <=> x1 + x2 + x3 <= 1
8490 */
8491 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
8492
8493 SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
8497 SCIPconsIsStickingAtNode(cons)) );
8498
8499 /* add the upgraded constraint to the problem */
8500 SCIP_CALL( SCIPaddConsUpgrade(scip, cons, &newcons) );
8501 ++(*naddconss);
8502
8503 /* remove the underlying constraint from the problem */
8504 SCIP_CALL( SCIPdelCons(scip, cons) );
8505 ++(*ndelconss);
8506
8507 return SCIP_OKAY;
8508 }
8509
8510 /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8511 if( consdata->weightsum - weights[nvars - 1] <= consdata->capacity )
8512 {
8513 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8514 assert(SCIPconsIsDeleted(cons));
8515
8516 return SCIP_OKAY;
8517 }
8518
8519 /* early termination, if the pair with biggest coeffcients together does not exceed the dualcapacity */
8520 /* @todo might be changed/removed when improving the coeffcients tightening */
8521 if( consdata->weightsum - capacity > weights[0] + weights[1] )
8522 return SCIP_OKAY;
8523
8524 /* case 2. */
8525
8526 v = 0;
8527
8528 /* @todo generalize the following algorithm for several parts of the knapsack
8529 *
8530 * the following is done without looking at the dualcapacity; it is enough to check whether for a certain amount of
8531 * variables each combination is a minimal cover, some examples
8532 *
8533 * +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 74~x1 + 70~x2 + 63~x3 + 62~x4 + 53~x5 >= 103
8534 * <=> ~x1 + ~x2 + ~x3 + ~x4 + ~x5 >= 2
8535 * <=> x1 + x2 + x3 + x4 + x5 <= 3
8536 *
8537 * +219y1 + 180y_2 +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8538 *
8539 */
8540
8541 /* determine big weights that fit only by itself */
8542 while( v < nvars && weights[v] + weights[nvars - 1] > capacity )
8543 ++v;
8544
8545 vbig = v;
8546 assert(vbig < nvars - 1);
8547 exceedsum = 0;
8548
8549 /* determine the amount needed to exceed the capacity */
8550 while( v < nvars && exceedsum <= capacity )
8551 {
8552 exceedsum += weights[v];
8553 ++v;
8554 }
8555
8556 /* if we exceeded the capacity we might reduce the weights */
8557 if( exceedsum > capacity )
8558 {
8559 assert(vbig > 0 || v < nvars);
8560
8561 /* all small weights were needed to exceed the capacity */
8562 if( v == nvars )
8563 {
8564 SCIP_Longint newweight = (SCIP_Longint)nvars - vbig - 1;
8565 assert(newweight > 0);
8566
8567 /* reduce big weights */
8568 for( v = 0; v < vbig; ++v )
8569 {
8570 if( weights[v] > newweight )
8571 {
8572 consdataChgWeight(consdata, v, newweight);
8573 ++(*nchgcoefs);
8574 }
8575 }
8576
8577 /* reduce small weights */
8578 for( ; v < nvars; ++v )
8579 {
8580 if( weights[v] > 1 )
8581 {
8582 consdataChgWeight(consdata, v, 1LL);
8583 ++(*nchgcoefs);
8584 }
8585 }
8586
8587 consdata->capacity = newweight;
8588
8589 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8590 * weight must not be sorted by their index
8591 */
8592#ifndef NDEBUG
8593 for( v = nvars - 1; v > 0; --v )
8594 assert(weights[v] <= weights[v-1]);
8595#endif
8596
8597 return SCIP_OKAY;
8598 }
8599 /* a certain amount of small variables exceed the capacity, so check if this holds for all combinations of the
8600 * small weights
8601 */
8602 else
8603 {
8604 SCIP_Longint exceedsumback = 0;
8605 int nexceed = v - vbig;
8606
8607 assert(nexceed > 1);
8608
8609 /* determine weightsum of the same amount as before but of the smallest weight */
8610 for( w = nvars - 1; w >= nvars - nexceed; --w )
8611 exceedsumback += weights[w];
8612
8613 assert(w >= 0);
8614
8615 /* if the same amount but with the smallest possible weights also exceed the capacity, it holds for all
8616 * combinations of all small weights
8617 */
8618 if( exceedsumback > capacity )
8619 {
8620 SCIP_Longint newweight = nexceed - 1;
8621
8622 /* taking out the smallest element needs to fit */
8623 assert(exceedsumback - weights[nvars - 1] <= capacity);
8624
8625 /* reduce big weights */
8626 for( v = 0; v < vbig; ++v )
8627 {
8628 if( weights[v] > newweight )
8629 {
8630 consdataChgWeight(consdata, v, newweight);
8631 ++(*nchgcoefs);
8632 }
8633 }
8634
8635 /* reduce small weights */
8636 for( ; v < nvars; ++v )
8637 {
8638 if( weights[v] > 1 )
8639 {
8640 consdataChgWeight(consdata, v, 1LL);
8641 ++(*nchgcoefs);
8642 }
8643 }
8644
8645 consdata->capacity = newweight;
8646
8647 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8648 * weight must not be sorted by their index
8649 */
8650#ifndef NDEBUG
8651 for( v = nvars - 1; v > 0; --v )
8652 assert(weights[v] <= weights[v-1]);
8653#endif
8654 return SCIP_OKAY;
8655 }
8656 }
8657 }
8658 else
8659 {
8660 /* if the following assert fails we have either a redundant constraint or a set-packing constraint, this should
8661 * not happen here
8662 */
8663 assert(vbig > 0 && vbig < nvars);
8664
8665 /* either choose a big coefficients or all other variables
8666 *
8667 * 973x1 + 189x2 + 189x3 + 145x4 + 110x5 + 104x6 + 93x7 + 71x8 + 68x9 + 10x10 <= 979
8668 *
8669 * either choose x1, or all other variables (weightsum of x2 to x10 is 979 above), so we can tighten this
8670 * constraint to
8671 *
8672 * 9x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 <= 9
8673 */
8674
8675 if( weights[vbig - 1] > (SCIP_Longint)nvars - vbig || weights[vbig] > 1 )
8676 {
8677 SCIP_Longint newweight = (SCIP_Longint)nvars - vbig;
8678#ifndef NDEBUG
8679 SCIP_Longint resweightsum = consdata->weightsum;
8680
8681 for( v = 0; v < vbig; ++v )
8682 resweightsum -= weights[v];
8683
8684 assert(exceedsum == resweightsum);
8685#endif
8686 assert(newweight > 0);
8687
8688 /* reduce big weights */
8689 for( v = 0; v < vbig; ++v )
8690 {
8691 if( weights[v] > newweight )
8692 {
8693 consdataChgWeight(consdata, v, newweight);
8694 ++(*nchgcoefs);
8695 }
8696 }
8697
8698 /* reduce small weights */
8699 for( ; v < nvars; ++v )
8700 {
8701 if( weights[v] > 1 )
8702 {
8703 consdataChgWeight(consdata, v, 1LL);
8704 ++(*nchgcoefs);
8705 }
8706 }
8707
8708 consdata->capacity = newweight;
8709
8710 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8711 * weight must not be sorted by their index
8712 */
8713#ifndef NDEBUG
8714 for( v = nvars - 1; v > 0; --v )
8715 assert(weights[v] <= weights[v-1]);
8716#endif
8717 return SCIP_OKAY;
8718 }
8719 }
8720
8721 /* case 3. */
8722
8723 dualcapacity = consdata->weightsum - capacity;
8724 reductionsum = 0;
8725 v = 0;
8726
8727 /* reduce big weights
8728 *
8729 * e.g. 11x0 + 11x1 + 10x2 + 10x3 <= 32 <=> 11~x0 + 11~x1 + 10~x2 + 10~x3 >= 10
8730 * <=> 10~x0 + 10~x1 + 10~x2 + 10~x3 >= 10
8731 * <=> x0 + x1 + x2 + x3 <= 3
8732 */
8733 while( weights[v] > dualcapacity )
8734 {
8735 reductionsum += (weights[v] - dualcapacity);
8736 consdataChgWeight(consdata, v, dualcapacity);
8737 ++v;
8738 assert(v < nvars);
8739 }
8740 (*nchgcoefs) += v;
8741
8742 /* skip weights equal to the dualcapacity, because we cannot change them */
8743 while( v < nvars && weights[v] == dualcapacity )
8744 ++v;
8745
8746 /* any negated variable out of the first n - 1 items is enough to fulfill the constraint, so we can update it to a logicor
8747 * after a possible removal of the last, redundant item
8748 *
8749 * e.g. 10x1 + 10x2 + 10x3 <= 20 <=> 10~x1 + 10~x2 + 10~x3 >= 10 <=> ~x1 + ~x2 + ~x3 >= 1
8750 */
8751 if( v >= nvars - 1 )
8752 {
8753 /* the last weight is not enough to satisfy the dual capacity -> remove this redundant item */
8754 if( v == nvars - 1 )
8755 {
8756 SCIP_CALL( delCoefPos(scip, cons, nvars - 1) );
8757 }
8758 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8759 assert(SCIPconsIsDeleted(cons));
8760
8761 return SCIP_OKAY;
8762 }
8763 /* at least two items with weight smaller than the dual capacity */
8764 else
8765 {
8766 /* @todo generalize the following algorithm for more than two variables */
8767
8768 if( weights[nvars - 1] + weights[nvars - 2] >= dualcapacity )
8769 {
8770 /* we have a dual-knapsack constraint where we either need to choose one variable out of a subset (big
8771 * coefficients) of all or two variables of the rest
8772 *
8773 * e.g. 9x1 + 9x2 + 6x3 + 4x4 <= 19 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 >= 9
8774 * <=> 2~x1 + 2~x2 + ~x3 + ~x4 >= 2
8775 * <=> 2x1 + 2x2 + x3 + x4 <= 4
8776 *
8777 * 3x1 + 3x2 + 2x3 + 2x4 + 2x5 + 2x6 + x7 <= 12 <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + 2~x5 + 2~x6 + ~x7 >= 3
8778 * <=> 2~x1 + 2~x2 + ~x3 + ~x4 + ~x5 + ~x6 + ~x7 >= 2
8779 * <=> 2 x1 + 2 x2 + x3 + x4 + x5 + x6 + x7 <= 7
8780 *
8781 */
8782 if( v > 0 && weights[nvars - 2] > 1 )
8783 {
8784 int ncoefchg = 0;
8785
8786 /* reduce all bigger weights */
8787 for( w = 0; w < v; ++w )
8788 {
8789 if( weights[w] > 2 )
8790 {
8791 consdataChgWeight(consdata, w, 2LL);
8792 ++ncoefchg;
8793 }
8794 else
8795 {
8796 assert(weights[0] == 2);
8797 assert(weights[v - 1] == 2);
8798 break;
8799 }
8800 }
8801
8802 /* reduce all smaller weights */
8803 for( w = v; w < nvars; ++w )
8804 {
8805 if( weights[w] > 1 )
8806 {
8807 consdataChgWeight(consdata, w, 1LL);
8808 ++ncoefchg;
8809 }
8810 }
8811 assert(ncoefchg > 0);
8812
8813 (*nchgcoefs) += ncoefchg;
8814
8815 /* correct the capacity */
8816 consdata->capacity = (-2 + v * 2 + nvars - v); /*lint !e647*/
8817 assert(consdata->capacity > 0);
8818 assert(weights[0] <= consdata->capacity);
8819 assert(consdata->weightsum > consdata->capacity);
8820 /* reset the reductionsum */
8821 reductionsum = 0;
8822 }
8823 else if( v == 0 )
8824 {
8825 assert(weights[nvars - 2] == 1);
8826 }
8827 }
8828 else
8829 {
8830 SCIP_Longint minweight = weights[nvars - 1];
8831 SCIP_Longint newweight = dualcapacity - minweight;
8832 SCIP_Longint restsumweights = 0;
8833 SCIP_Longint sumcoef;
8834 SCIP_Bool sumcoefcase = FALSE;
8835 int startv = v;
8836 int end;
8837 int k;
8838
8839 assert(weights[nvars - 1] + weights[nvars - 2] <= capacity);
8840
8841 /* reduce big weights of pairs that exceed the dualcapacity
8842 *
8843 * e.g. 9x1 + 9x2 + 6x3 + 4x4 + 4x5 + 4x6 <= 27 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8844 * <=> 9~x1 + 9~x2 + 5~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8845 * <=> 9x1 + 9x2 + 5x3 + 4x4 + 4x5 + 4x6 <= 27
8846 */
8847 while( weights[v] > newweight )
8848 {
8849 reductionsum += (weights[v] - newweight);
8850 consdataChgWeight(consdata, v, newweight);
8851 ++v;
8852 assert(v < nvars);
8853 }
8854 (*nchgcoefs) += (v - startv);
8855
8856 /* skip equal weights */
8857 while( weights[v] == newweight )
8858 ++v;
8859
8860 if( v > 0 )
8861 {
8862 for( w = v; w < nvars; ++w )
8863 restsumweights += weights[w];
8864 }
8865 else
8866 restsumweights = consdata->weightsum;
8867
8868 if( restsumweights < dualcapacity )
8869 {
8870 /* we found redundant variables, which does not influence the feasibility of any integral solution, e.g.
8871 *
8872 * +61x1 + 61x2 + 61x3 + 61x4 + 61x5 + 61x6 + 35x7 + 10x8 <= 350 <=>
8873 * +61~x1 + 61~x2 + 61~x3 + 61~x4 + 61~x5 + 61~x6 + 35~x7 + 10~x8 >= 61
8874 */
8875 if( startv == v )
8876 {
8877 /* remove redundant variables */
8878 for( w = nvars - 1; w >= v; --w )
8879 {
8880 SCIP_CALL( delCoefPos(scip, cons, v) );
8881 ++(*nchgcoefs);
8882 }
8883
8884#ifndef NDEBUG
8885 /* each coefficients should exceed the dualcapacity by itself */
8886 for( ; w >= 0; --w )
8887 assert(weights[w] == dualcapacity);
8888#endif
8889 /* for performance reasons we do not update the capacity(, i.e. reduce it by reductionsum) and directly
8890 * upgrade this constraint
8891 */
8892 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8893 assert(SCIPconsIsDeleted(cons));
8894
8895 return SCIP_OKAY;
8896 }
8897
8898 /* special case where we have three different coefficient types
8899 *
8900 * e.g. 9x1 + 9x2 + 6x3 + 6x4 + 4x5 + 4x6 <= 29 <=> 9~x1 + 9~x2 + 6~x3 + 6~x4 + 4~x5 + 4~x6 >= 9
8901 * <=> 9~x1 + 9~x2 + 5~x3 + 5~x4 + 4~x5 + 4~x6 >= 9
8902 * <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + ~x5 + ~x6 >= 3
8903 * <=> 3x1 + 3x2 + 2x3 + 2x4 + x5 + x6 <= 9
8904 */
8905 if( weights[v] > 1 || (weights[startv] > (SCIP_Longint)nvars - v) || (startv > 0 && weights[0] == (SCIP_Longint)nvars - v + 1) )
8906 {
8907 SCIP_Longint newcap;
8908
8909 /* adjust smallest coefficients, which all together do not exceed the dualcapacity */
8910 for( w = nvars - 1; w >= v; --w )
8911 {
8912 if( weights[w] > 1 )
8913 {
8914 consdataChgWeight(consdata, w, 1LL);
8915 ++(*nchgcoefs);
8916 }
8917 }
8918
8919 /* adjust middle sized coefficients, which when choosing also one small coefficients exceed the
8920 * dualcapacity
8921 */
8922 newweight = (SCIP_Longint)nvars - v;
8923 assert(newweight > 1);
8924 for( ; w >= startv; --w )
8925 {
8926 if( weights[w] > newweight )
8927 {
8928 consdataChgWeight(consdata, w, newweight);
8929 ++(*nchgcoefs);
8930 }
8931 else
8932 assert(weights[w] == newweight);
8933 }
8934
8935 /* adjust big sized coefficients, where each of them exceeds the dualcapacity by itself */
8936 ++newweight;
8937 assert(newweight > 2);
8938 for( ; w >= 0; --w )
8939 {
8940 if( weights[w] > newweight )
8941 {
8942 consdataChgWeight(consdata, w, newweight);
8943 ++(*nchgcoefs);
8944 }
8945 else
8946 assert(weights[w] == newweight);
8947 }
8948
8949 /* update the capacity */
8950 newcap = ((SCIP_Longint)startv - 1) * newweight + ((SCIP_Longint)v - startv) * (newweight - 1) + ((SCIP_Longint)nvars - v);
8951 if( consdata->capacity > newcap )
8952 {
8953 consdata->capacity = newcap;
8954 ++(*nchgsides);
8955 }
8956 else
8957 assert(consdata->capacity == newcap);
8958 }
8959 assert(weights[v] == 1 && (weights[startv] == (SCIP_Longint)nvars - v) && (startv == 0 || weights[0] == (SCIP_Longint)nvars - v + 1));
8960
8961 /* the new dualcapacity should still be equal to the (nvars - v + 1) */
8962 assert(consdata->weightsum - consdata->capacity == (SCIP_Longint)nvars - v + 1);
8963
8964 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8965 * weight must not be sorted by their index
8966 */
8967#ifndef NDEBUG
8968 for( w = nvars - 1; w > 0; --w )
8969 assert(weights[w] <= weights[w - 1]);
8970#endif
8971 return SCIP_OKAY;
8972 }
8973
8974 /* check if all rear items have the same weight as the last one, so we cannot tighten the constraint further */
8975 end = nvars - 2;
8976 while( end >= 0 && weights[end] == weights[end + 1] )
8977 {
8978 assert(end >= v);
8979 --end;
8980 }
8981
8982 if( v >= end )
8983 goto TERMINATE;
8984
8985 end = nvars - 2;
8986
8987 /* can we stop early, another special reduction case might exist */
8988 if( 2 * weights[end] > dualcapacity )
8989 {
8990 restsumweights = 0;
8991
8992 /* determine capacity of the small items */
8993 for( w = end + 1; w < nvars; ++w )
8994 restsumweights += weights[w];
8995
8996 if( restsumweights * 2 <= dualcapacity )
8997 {
8998 /* check for further posssible reductions in the middle */
8999 while( v < end && restsumweights + weights[v] >= dualcapacity )
9000 ++v;
9001
9002 if( v >= end )
9003 goto TERMINATE;
9004
9005 /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
9006 if( (dualcapacity & 1) == 0 )
9007 {
9008 newweight = dualcapacity / 2;
9009
9010 /* set all middle coefficients */
9011 for( ; v <= end; ++v )
9012 {
9013 if( weights[v] > newweight )
9014 {
9015 reductionsum += (weights[v] - newweight);
9016 consdataChgWeight(consdata, v, newweight);
9017 ++(*nchgcoefs);
9018 }
9019 }
9020 }
9021 /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
9022 * other coefficients by 2
9023 */
9024 else
9025 {
9026 /* correct the reductionsum */
9027 reductionsum *= 2;
9028
9029 /* multiply big coefficients by 2 */
9030 for( w = 0; w < v; ++w )
9031 {
9032 consdataChgWeight(consdata, w, weights[w] * 2);
9033 }
9034
9035 newweight = dualcapacity;
9036 /* set all middle coefficients */
9037 for( ; v <= end; ++v )
9038 {
9039 reductionsum += (2 * weights[v] - newweight);
9040 consdataChgWeight(consdata, v, newweight);
9041 }
9042
9043 /* multiply small coefficients by 2 */
9044 for( w = end + 1; w < nvars; ++w )
9045 {
9046 consdataChgWeight(consdata, w, weights[w] * 2);
9047 }
9048 (*nchgcoefs) += nvars;
9049
9050 dualcapacity *= 2;
9051 consdata->capacity *= 2;
9052 ++(*nchgsides);
9053 }
9054 }
9055
9056 goto TERMINATE;
9057 }
9058
9059 /* further reductions using the next possible coefficient sum
9060 *
9061 * e.g. 9x1 + 8x2 + 7x3 + 3x4 + x5 <= 19 <=> 9~x1 + 8~x2 + 7~x3 + 3~x4 + ~x5 >= 9
9062 * <=> 9~x1 + 8~x2 + 6~x3 + 3~x4 + ~x5 >= 9
9063 * <=> 9x1 + 8x2 + 6x3 + 3x4 + x5 <= 18
9064 */
9065 /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
9066 for( k = 0; k < 4; ++k )
9067 {
9068 /* determine next minimal coefficient sum */
9069 switch( k )
9070 {
9071 case 0:
9072 sumcoef = weights[nvars - 1] + weights[nvars - 2];
9073 break;
9074 case 1:
9075 assert(nvars >= 3);
9076 sumcoef = weights[nvars - 1] + weights[nvars - 3];
9077 break;
9078 case 2:
9079 assert(nvars >= 4);
9080 if( weights[nvars - 1] + weights[nvars - 4] < weights[nvars - 2] + weights[nvars - 3] )
9081 {
9082 sumcoefcase = TRUE;
9083 sumcoef = weights[nvars - 1] + weights[nvars - 4];
9084 }
9085 else
9086 {
9087 sumcoefcase = FALSE;
9088 sumcoef = weights[nvars - 2] + weights[nvars - 3];
9089 }
9090 break;
9091 case 3:
9092 assert(nvars >= 5);
9093 if( sumcoefcase )
9094 {
9095 sumcoef = MIN(weights[nvars - 1] + weights[nvars - 5], weights[nvars - 2] + weights[nvars - 3]);
9096 }
9097 else
9098 {
9099 sumcoef = MIN(weights[nvars - 1] + weights[nvars - 4], weights[nvars - 1] + weights[nvars - 2] + weights[nvars - 3]);
9100 }
9101 break;
9102 default:
9103 return SCIP_ERROR;
9104 }
9105
9106 /* tighten next coefficients that, pair with the current small coefficient, exceed the dualcapacity */
9107 minweight = weights[end];
9108 while( minweight <= sumcoef )
9109 {
9110 newweight = dualcapacity - minweight;
9111 startv = v;
9112 assert(v < nvars);
9113
9114 /* @todo check for further reductions, when two times the minweight exceeds the dualcapacity */
9115 /* shrink big coefficients */
9116 while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9117 {
9118 reductionsum += (weights[v] - newweight);
9119 consdataChgWeight(consdata, v, newweight);
9120 ++v;
9121 assert(v < nvars);
9122 }
9123 (*nchgcoefs) += (v - startv);
9124
9125 /* skip unchangable weights */
9126 while( weights[v] + minweight == dualcapacity )
9127 {
9128 assert(v < nvars);
9129 ++v;
9130 }
9131
9132 --end;
9133 /* skip same end weights */
9134 while( end >= 0 && weights[end] == weights[end + 1] )
9135 --end;
9136
9137 if( v >= end )
9138 goto TERMINATE;
9139
9140 minweight = weights[end];
9141 }
9142
9143 if( v >= end )
9144 goto TERMINATE;
9145
9146 /* now check if a combination of small coefficients allows us to tighten big coefficients further */
9147 if( sumcoef < minweight )
9148 {
9149 minweight = sumcoef;
9150 newweight = dualcapacity - minweight;
9151 startv = v;
9152 assert(v < nvars);
9153
9154 /* shrink big coefficients */
9155 while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9156 {
9157 reductionsum += (weights[v] - newweight);
9158 consdataChgWeight(consdata, v, newweight);
9159 ++v;
9160 assert(v < nvars);
9161 }
9162 (*nchgcoefs) += (v - startv);
9163
9164 /* skip unchangable weights */
9165 while( weights[v] + minweight == dualcapacity )
9166 {
9167 assert(v < nvars);
9168 ++v;
9169 }
9170 }
9171
9172 if( v >= end )
9173 goto TERMINATE;
9174
9175 /* can we stop early, another special reduction case might exist */
9176 if( 2 * weights[end] > dualcapacity )
9177 {
9178 restsumweights = 0;
9179
9180 /* determine capacity of the small items */
9181 for( w = end + 1; w < nvars; ++w )
9182 restsumweights += weights[w];
9183
9184 if( restsumweights * 2 <= dualcapacity )
9185 {
9186 /* check for further posssible reductions in the middle */
9187 while( v < end && restsumweights + weights[v] >= dualcapacity )
9188 ++v;
9189
9190 if( v >= end )
9191 goto TERMINATE;
9192
9193 /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
9194 if( (dualcapacity & 1) == 0 )
9195 {
9196 newweight = dualcapacity / 2;
9197
9198 /* set all middle coefficients */
9199 for( ; v <= end; ++v )
9200 {
9201 if( weights[v] > newweight )
9202 {
9203 reductionsum += (weights[v] - newweight);
9204 consdataChgWeight(consdata, v, newweight);
9205 ++(*nchgcoefs);
9206 }
9207 }
9208 }
9209 /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
9210 * other coefficients by 2
9211 */
9212 else
9213 {
9214 /* correct the reductionsum */
9215 reductionsum *= 2;
9216
9217 /* multiply big coefficients by 2 */
9218 for( w = 0; w < v; ++w )
9219 {
9220 consdataChgWeight(consdata, w, weights[w] * 2);
9221 }
9222
9223 newweight = dualcapacity;
9224 /* set all middle coefficients */
9225 for( ; v <= end; ++v )
9226 {
9227 reductionsum += (2 * weights[v] - newweight);
9228 consdataChgWeight(consdata, v, newweight);
9229 }
9230
9231 /* multiply small coefficients by 2 */
9232 for( w = end + 1; w < nvars; ++w )
9233 {
9234 consdataChgWeight(consdata, w, weights[w] * 2);
9235 }
9236 (*nchgcoefs) += nvars;
9237
9238 dualcapacity *= 2;
9239 consdata->capacity *= 2;
9240 ++(*nchgsides);
9241 }
9242 }
9243
9244 goto TERMINATE;
9245 }
9246
9247 /* cannot tighten any further */
9248 if( 2 * sumcoef > dualcapacity )
9249 goto TERMINATE;
9250 }
9251 }
9252 }
9253
9254 TERMINATE:
9255 /* correct capacity */
9256 if( reductionsum > 0 )
9257 {
9258 assert(v > 0);
9259
9260 consdata->capacity -= reductionsum;
9261 ++(*nchgsides);
9262
9263 assert(consdata->weightsum - dualcapacity == consdata->capacity);
9264 }
9265 assert(weights[0] <= consdata->capacity);
9266
9267 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
9268 * weight must not be sorted by their index
9269 */
9270#ifndef NDEBUG
9271 for( w = nvars - 1; w > 0; --w )
9272 assert(weights[w] <= weights[w - 1]);
9273#endif
9274
9275 if( oldnchgcoefs < *nchgcoefs )
9276 {
9277 assert(!SCIPconsIsDeleted(cons));
9278
9279 /* it might be that we can divide the weights by their greatest common divisor */
9280 normalizeWeights(cons, nchgcoefs, nchgsides);
9281 }
9282 else
9283 {
9284 assert(oldnchgcoefs == *nchgcoefs);
9285 assert(oldnchgsides == *nchgsides);
9286 }
9287
9288 return SCIP_OKAY;
9289}
9290
9291
9292/** fixes variables with weights bigger than the capacity and delete redundant constraints, also sort weights */
9293static
9295 SCIP* scip, /**< SCIP data structure */
9296 SCIP_CONS* cons, /**< knapsack constraint */
9297 int* nfixedvars, /**< pointer to store the amount of fixed variables */
9298 int* ndelconss, /**< pointer to store the amount of deleted constraints */
9299 int* nchgcoefs /**< pointer to store the amount of changed coefficients */
9300 )
9301{
9302 SCIP_VAR** vars;
9303 SCIP_CONSDATA* consdata;
9304 SCIP_Longint* weights;
9305 SCIP_Longint capacity;
9306 SCIP_Bool infeasible;
9307 SCIP_Bool fixed;
9308 int nvars;
9309 int v;
9310
9311 assert(scip != NULL);
9312 assert(cons != NULL);
9313 assert(nfixedvars != NULL);
9314 assert(ndelconss != NULL);
9315 assert(nchgcoefs != NULL);
9316
9317 consdata = SCIPconsGetData(cons);
9318 assert(consdata != NULL);
9319
9320 nvars = consdata->nvars;
9321
9322 /* no variables left, then delete constraint */
9323 if( nvars == 0 )
9324 {
9325 assert(consdata->capacity >= 0);
9326
9327 SCIP_CALL( SCIPdelCons(scip, cons) );
9328 ++(*ndelconss);
9329
9330 return SCIP_OKAY;
9331 }
9332
9333 /* sort items */
9334 sortItems(consdata);
9335
9336 vars = consdata->vars;
9337 weights = consdata->weights;
9338 capacity = consdata->capacity;
9339 v = 0;
9340
9341 /* check for weights bigger than the capacity */
9342 while( v < nvars && weights[v] > capacity )
9343 {
9344 SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, &infeasible, &fixed) );
9345 assert(!infeasible);
9346
9347 if( fixed )
9348 ++(*nfixedvars);
9349
9350 ++v;
9351 }
9352
9353 /* if we fixed at least one variable we need to delete them from the constraint */
9354 if( v > 0 )
9355 {
9356 if( v == nvars )
9357 {
9358 SCIP_CALL( SCIPdelCons(scip, cons) );
9359 ++(*ndelconss);
9360
9361 return SCIP_OKAY;
9362 }
9363
9364 /* delete all position from back to front */
9365 for( --v; v >= 0; --v )
9366 {
9367 SCIP_CALL( delCoefPos(scip, cons, v) );
9368 ++(*nchgcoefs);
9369 }
9370
9371 /* sort items again because of deletion */
9372 sortItems(consdata);
9373 assert(vars == consdata->vars);
9374 assert(weights == consdata->weights);
9375 }
9376 assert(consdata->sorted);
9377 assert(weights[0] <= capacity);
9378
9379 if( !SCIPisHugeValue(scip, (SCIP_Real) capacity) && consdata->weightsum <= capacity )
9380 {
9381 SCIP_CALL( SCIPdelCons(scip, cons) );
9382 ++(*ndelconss);
9383 }
9384
9385 return SCIP_OKAY;
9386}
9387
9388
9389/** tries to simplify weights and delete redundant variables in knapsack a^Tx <= capacity
9390 *
9391 * 1. use the duality between a^Tx <= capacity <=> -a^T~x <= capacity - weightsum to tighten weights, e.g.
9392 *
9393 * 11x1 + 10x2 + 7x3 + 5x4 + 5x5 <= 25 <=> -10~x1 - 10~x2 - 7~x3 - 5~x4 - 5~x5 <= -13
9394 *
9395 * the above constraint can be changed to
9396 *
9397 * -8~x1 - 8~x2 - 7~x3 - 5~x4 - 5~x5 <= -12 <=> 8x1 + 8x2 + 7x3 + 5x4 + 5x5 <= 20
9398 *
9399 * 2. if variables in a constraint do not affect the (in-)feasibility of the constraint, we can delete them, e.g.
9400 *
9401 * 7x1 + 6x2 + 5x3 + 5x4 + x5 + x6 <= 20 => x5 and x6 are redundant and can be removed
9402 *
9403 * 3. Tries to use gcd information an all but one weight to change this not-included weight and normalize the
9404 * constraint further, e.g.
9405 *
9406 * 9x1 + 6x2 + 6x3 + 5x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => 3x1 + 2x2 + 2x3 + 2x4 <= 4 => 4x1 + 2x2 + 2x3 + 2x4 <= 4
9407 * => 2x1 + x2 + x3 + x4 <= 2
9408 * 9x1 + 6x2 + 6x3 + 7x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => see above
9409 */
9410static
9412 SCIP* scip, /**< SCIP data structure */
9413 SCIP_CONS* cons, /**< knapsack constraint */
9414 int* nfixedvars, /**< pointer to store the amount of fixed variables */
9415 int* ndelconss, /**< pointer to store the amount of deleted constraints */
9416 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
9417 int* nchgsides, /**< pointer to store the amount of changed sides */
9418 int* naddconss, /**< pointer to count number of added constraints */
9419 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9420 )
9421{
9422 SCIP_VAR** vars;
9423 SCIP_CONSDATA* consdata;
9424 SCIP_Longint* weights;
9425 SCIP_Longint restweight;
9426 SCIP_Longint newweight;
9427 SCIP_Longint weight;
9428 SCIP_Longint oldgcd;
9429 SCIP_Longint rest;
9430 SCIP_Longint gcd;
9431 int oldnchgcoefs; /* cppcheck-suppress unassignedVariable */
9432 int oldnchgsides; /* cppcheck-suppress unassignedVariable */
9433 int candpos;
9434 int candpos2;
9435 int offsetv;
9436 int nvars;
9437 int v;
9438
9439 assert(scip != NULL);
9440 assert(cons != NULL);
9441 assert(nfixedvars != NULL);
9442 assert(ndelconss != NULL);
9443 assert(nchgcoefs != NULL);
9444 assert(nchgsides != NULL);
9445 assert(naddconss != NULL);
9446 assert(cutoff != NULL);
9447 assert(!SCIPconsIsModifiable(cons));
9448
9449 consdata = SCIPconsGetData(cons);
9450 assert( consdata != NULL );
9451
9452 *cutoff = FALSE;
9453
9454 /* remove double enties and also combinations of active and negated variables */
9455 SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
9456 assert(consdata->merged);
9457 if( *cutoff )
9458 return SCIP_OKAY;
9459
9460 assert(consdata->capacity >= 0);
9461
9462 /* fix variables with big coefficients and remove redundant constraints, sort weights */
9463 SCIP_CALL( prepareCons(scip, cons, nfixedvars, ndelconss, nchgcoefs) );
9464
9465 if( SCIPconsIsDeleted(cons) )
9466 return SCIP_OKAY;
9467
9468 if( !SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
9469 {
9470 /* 1. dual weights tightening */
9471 SCIP_CALL( dualWeightsTightening(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9472
9473 if( SCIPconsIsDeleted(cons) )
9474 return SCIP_OKAY;
9475 /* 2. delete redundant variables */
9476 SCIP_CALL( detectRedundantVars(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9477
9478 if( SCIPconsIsDeleted(cons) )
9479 return SCIP_OKAY;
9480 }
9481
9482 weights = consdata->weights;
9483 nvars = consdata->nvars;
9484
9485#ifndef NDEBUG
9486 /* constraint might not be sorted, but the weights are already sorted */
9487 for( v = nvars - 1; v > 0; --v )
9488 assert(weights[v] <= weights[v-1]);
9489#endif
9490
9491 /* determine greatest common divisor */
9492 gcd = weights[nvars - 1];
9493 for( v = nvars - 2; v >= 0 && gcd > 1; --v )
9494 {
9495 gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9496 }
9497
9498 /* divide the constraint by their greatest common divisor */
9499 if( gcd >= 2 )
9500 {
9501 for( v = nvars - 1; v >= 0; --v )
9502 {
9503 consdataChgWeight(consdata, v, weights[v]/gcd);
9504 }
9505 (*nchgcoefs) += nvars;
9506
9507 consdata->capacity /= gcd;
9508 (*nchgsides)++;
9509 }
9510 assert(consdata->nvars == nvars);
9511
9512 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal weight
9513 * must not be sorted by their index
9514 */
9515#ifndef NDEBUG
9516 for( v = nvars - 1; v > 0; --v )
9517 assert(weights[v] <= weights[v-1]);
9518#endif
9519
9520 /* 3. start gcd procedure for all variables */
9521 do
9522 {
9523 SCIPdebug( oldnchgcoefs = *nchgcoefs; )
9524 SCIPdebug( oldnchgsides = *nchgsides; )
9525
9526 vars = consdata->vars;
9527 weights = consdata->weights;
9528 nvars = consdata->nvars;
9529
9530 /* stop if we have two coefficients which are one in absolute value */
9531 if( weights[nvars - 1] == 1 && weights[nvars - 2] == 1 )
9532 return SCIP_OKAY;
9533
9534 v = 0;
9535 /* determine coefficients as big as the capacity, these we do not need to take into account when calculating the
9536 * gcd
9537 */
9538 while( weights[v] == consdata->capacity )
9539 {
9540 ++v;
9541 assert(v < nvars);
9542 }
9543
9544 /* all but one variable are as big as the capacity, this is handled elsewhere */
9545 if( v == nvars - 1 )
9546 return SCIP_OKAY;
9547
9548 offsetv = v;
9549
9550 gcd = -1;
9551 candpos = -1;
9552 candpos2 = -1;
9553
9554 /* calculate greatest common divisor over all integer and binary variables and determine the candidate where we might
9555 * change the coefficient
9556 */
9557 for( v = nvars - 1; v >= offsetv; --v )
9558 {
9559 weight = weights[v];
9560 assert(weight >= 1);
9561
9562 oldgcd = gcd;
9563
9564 if( gcd == -1 )
9565 {
9566 gcd = weights[v];
9567 assert(gcd >= 1);
9568 }
9569 else
9570 {
9571 /* calculate greatest common divisor for all variables */
9572 gcd = SCIPcalcGreComDiv(gcd, weight);
9573 }
9574
9575 /* if the greatest commmon divisor has become 1, we might have found the possible coefficient to change or we
9576 * can terminate
9577 */
9578 if( gcd == 1 )
9579 {
9580 /* found candidate */
9581 if( candpos == -1 )
9582 {
9583 gcd = oldgcd;
9584 candpos = v;
9585
9586 /* if both first coefficients have a gcd of 1, both are candidates for the coefficient change */
9587 if( v == nvars - 2 )
9588 candpos2 = v + 1;
9589 }
9590 /* two different variables lead to a gcd of one, so we cannot change a coefficient */
9591 else
9592 {
9593 if( candpos == v + 1 && candpos2 == v + 2 )
9594 {
9595 assert(candpos2 == nvars - 1);
9596
9597 /* take new candidates */
9598 candpos = candpos2;
9599
9600 /* recalculate gcd from scratch */
9601 gcd = weights[v+1];
9602 assert(gcd >= 1);
9603
9604 /* calculate greatest common divisor for variables */
9605 gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9606 if( gcd == 1 )
9607 return SCIP_OKAY;
9608 }
9609 else
9610 /* cannot determine a possible coefficient for reduction */
9611 return SCIP_OKAY;
9612 }
9613 }
9614 }
9615 assert(gcd >= 2);
9616
9617 /* we should have found one coefficient, that led to a gcd of 1, otherwise we could normalize the constraint
9618 * further
9619 */
9620 assert(((candpos >= offsetv) || (candpos == -1 && offsetv > 0)) && candpos < nvars);
9621
9622 /* determine the remainder of the capacity and the gcd */
9623 rest = consdata->capacity % gcd;
9624 assert(rest >= 0);
9625 assert(rest < gcd);
9626
9627 if( candpos == -1 )
9628 {
9629 /* we assume that the constraint was normalized */
9630 assert(rest > 0);
9631
9632 /* replace old with new capacity */
9633 consdata->capacity -= rest;
9634 ++(*nchgsides);
9635
9636 /* replace old big coefficients with new capacity */
9637 for( v = 0; v < offsetv; ++v )
9638 {
9639 consdataChgWeight(consdata, v, consdata->capacity);
9640 }
9641
9642 *nchgcoefs += offsetv;
9643 goto CONTINUE;
9644 }
9645
9646 /* determine the remainder of the coefficient candidate and the gcd */
9647 restweight = weights[candpos] % gcd;
9648 assert(restweight >= 1);
9649 assert(restweight < gcd);
9650
9651 /* calculate new coefficient */
9652 if( restweight > rest )
9653 newweight = weights[candpos] - restweight + gcd;
9654 else
9655 newweight = weights[candpos] - restweight;
9656
9657 assert(newweight == 0 || SCIPcalcGreComDiv(gcd, newweight) == gcd);
9658
9659 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);
9660
9661 /* must not change weights and capacity if one variable would be removed and we have a big coefficient,
9662 * e.g., 11x1 + 6x2 + 6x3 + 5x4 <= 11 => gcd = 6, offsetv = 1 => newweight = 0, but we would lose x1 = 1 => x4 = 0
9663 */
9664 if( newweight == 0 && offsetv > 0 )
9665 return SCIP_OKAY;
9666
9667 if( rest > 0 )
9668 {
9669 /* replace old with new capacity */
9670 consdata->capacity -= rest;
9671 ++(*nchgsides);
9672
9673 /* replace old big coefficients with new capacity */
9674 for( v = 0; v < offsetv; ++v )
9675 {
9676 consdataChgWeight(consdata, v, consdata->capacity);
9677 }
9678
9679 *nchgcoefs += offsetv;
9680 }
9681
9682 if( newweight == 0 )
9683 {
9684 /* delete redundant coefficient */
9685 SCIP_CALL( delCoefPos(scip, cons, candpos) );
9686 assert(consdata->nvars == nvars - 1);
9687 --nvars;
9688 }
9689 else
9690 {
9691 /* replace old with new coefficient */
9692 consdataChgWeight(consdata, candpos, newweight);
9693 }
9694 ++(*nchgcoefs);
9695
9696 assert(consdata->vars == vars);
9697 assert(consdata->nvars == nvars);
9698 assert(consdata->weights == weights);
9699
9700 CONTINUE:
9701 /* now constraint can be normalized, dividing it by the gcd */
9702 for( v = nvars - 1; v >= 0; --v )
9703 {
9704 consdataChgWeight(consdata, v, weights[v]/gcd);
9705 }
9706 (*nchgcoefs) += nvars;
9707
9708 consdata->capacity /= gcd;
9709 ++(*nchgsides);
9710
9712
9713 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));
9714 }
9715 while( nvars >= 2 );
9716
9717 return SCIP_OKAY;
9718}
9719
9720
9721/** inserts an element into the list of binary zero implications */
9722static
9724 SCIP* scip, /**< SCIP data structure */
9725 int** liftcands, /**< array of the lifting candidates */
9726 int* nliftcands, /**< number of lifting candidates */
9727 int** firstidxs, /**< array of first zeroitems indices */
9728 SCIP_Longint** zeroweightsums, /**< array of sums of weights of the implied-to-zero items */
9729 int** zeroitems, /**< pointer to zero items array */
9730 int** nextidxs, /**< pointer to array of next zeroitems indeces */
9731 int* zeroitemssize, /**< pointer to size of zero items array */
9732 int* nzeroitems, /**< pointer to length of zero items array */
9733 int probindex, /**< problem index of variable y in implication y == v -> x == 0 */
9734 SCIP_Bool value, /**< value v of variable y in implication */
9735 int knapsackidx, /**< index of variable x in knapsack */
9736 SCIP_Longint knapsackweight, /**< weight of variable x in knapsack */
9737 SCIP_Bool* memlimitreached /**< pointer to store whether the memory limit was reached */
9738 )
9739{
9740 int nzeros;
9741
9742 assert(liftcands != NULL);
9743 assert(liftcands[value] != NULL);
9744 assert(nliftcands != NULL);
9745 assert(firstidxs != NULL);
9746 assert(firstidxs[value] != NULL);
9747 assert(zeroweightsums != NULL);
9748 assert(zeroweightsums[value] != NULL);
9749 assert(zeroitems != NULL);
9750 assert(nextidxs != NULL);
9751 assert(zeroitemssize != NULL);
9752 assert(nzeroitems != NULL);
9753 assert(*nzeroitems <= *zeroitemssize);
9754 assert(0 <= probindex && probindex < SCIPgetNVars(scip) - SCIPgetNContVars(scip));
9755 assert(memlimitreached != NULL);
9756
9757 nzeros = *nzeroitems;
9758
9759 /* allocate enough memory */
9760 if( nzeros == *zeroitemssize )
9761 {
9762 /* we explicitly construct the complete implication graph where the knapsack variables are involved;
9763 * this can be too huge - abort on memory limit
9764 */
9765 if( *zeroitemssize >= MAX_ZEROITEMS_SIZE )
9766 {
9767 SCIPdebugMsg(scip, "memory limit of %d bytes reached in knapsack preprocessing - abort collecting zero items\n",
9768 *zeroitemssize);
9769 *memlimitreached = TRUE;
9770 return SCIP_OKAY;
9771 }
9772 *zeroitemssize *= 2;
9773 *zeroitemssize = MIN(*zeroitemssize, MAX_ZEROITEMS_SIZE);
9774 SCIP_CALL( SCIPreallocBufferArray(scip, zeroitems, *zeroitemssize) );
9775 SCIP_CALL( SCIPreallocBufferArray(scip, nextidxs, *zeroitemssize) );
9776 }
9777 assert(nzeros < *zeroitemssize);
9778
9779 if( *memlimitreached )
9780 *memlimitreached = FALSE;
9781
9782 /* insert element */
9783 (*zeroitems)[nzeros] = knapsackidx;
9784 (*nextidxs)[nzeros] = firstidxs[value][probindex];
9785 if( firstidxs[value][probindex] == 0 )
9786 {
9787 liftcands[value][nliftcands[value]] = probindex;
9788 ++nliftcands[value];
9789 }
9790 firstidxs[value][probindex] = nzeros;
9791 ++(*nzeroitems);
9792 zeroweightsums[value][probindex] += knapsackweight;
9793
9794 return SCIP_OKAY;
9795}
9796
9797#define MAX_CLIQUELENGTH 50
9798/** applies rule (3) of the weight tightening procedure, which can lift other variables into the knapsack:
9799 * (3) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
9800 * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
9801 * if cliqueweightsum(xi == v) < capacity:
9802 * - fixing variable xi to v would make the knapsack constraint redundant
9803 * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
9804 * redundancy effect:
9805 * wi' := capacity - cliqueweightsum(xi == v)
9806 * this rule can also be applied to binary variables not in the knapsack!
9807 */
9808static
9810 SCIP* scip, /**< SCIP data structure */
9811 SCIP_CONS* cons, /**< knapsack constraint */
9812 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9813 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9814 )
9815{
9816 SCIP_CONSDATA* consdata;
9817 SCIP_VAR** binvars;
9818 int nbinvars;
9819 int* liftcands[2]; /* binary variables that have at least one entry in zeroitems */
9820 int* firstidxs[2]; /* first index in zeroitems for each binary variable/value pair, or zero for empty list */
9821 SCIP_Longint* zeroweightsums[2]; /* sums of weights of the implied-to-zero items */
9822 int* zeroitems; /* item number in knapsack that is implied to zero */
9823 int* nextidxs; /* next index in zeroitems for the same binary variable, or zero for end of list */
9824 int zeroitemssize;
9825 int nzeroitems;
9826 SCIP_Bool* zeroiteminserted[2];
9827 SCIP_Bool memlimitreached;
9828 int nliftcands[2];
9829 SCIP_Bool* cliqueused;
9830 SCIP_Bool* itemremoved;
9831 SCIP_Longint maxcliqueweightsum;
9832 SCIP_VAR** addvars;
9833 SCIP_Longint* addweights;
9834 SCIP_Longint addweightsum;
9835 int nvars;
9836 int cliquenum;
9837 int naddvars;
9838 int val;
9839 int i;
9840
9841 int* tmpindices;
9842 SCIP_Bool* tmpboolindices;
9843 int* tmpindices2;
9844 SCIP_Bool* tmpboolindices2;
9845 int* tmpindices3;
9846 SCIP_Bool* tmpboolindices3;
9847 int tmp;
9848 int tmp2;
9849 int tmp3;
9850 SCIP_CONSHDLR* conshdlr;
9851 SCIP_CONSHDLRDATA* conshdlrdata;
9852
9853 assert(nchgcoefs != NULL);
9854 assert(!SCIPconsIsModifiable(cons));
9855
9856 consdata = SCIPconsGetData(cons);
9857 assert(consdata != NULL);
9858 assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
9859 assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
9860 assert(consdata->nvars > 0);
9861 assert(consdata->merged);
9862
9863 nvars = consdata->nvars;
9864
9865 /* check if the knapsack has too many items/cliques for applying this costly method */
9866 if( (!consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE) || consdata->ncliques > MAX_USECLIQUES_SIZE )
9867 return SCIP_OKAY;
9868
9869 /* sort items, s.t. the heaviest one is in the first position */
9870 sortItems(consdata);
9871
9872 if( !consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE )
9873 return SCIP_OKAY;
9874
9875 /* we have to consider all integral variables since even integer and implicit integer variables can have binary bounds */
9876 nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
9877 assert(nbinvars > 0);
9878 binvars = SCIPgetVars(scip);
9879
9880 /* get conshdlrdata to use cleared memory */
9881 conshdlr = SCIPconsGetHdlr(cons);
9882 assert(conshdlr != NULL);
9883 conshdlrdata = SCIPconshdlrGetData(conshdlr);
9884 assert(conshdlrdata != NULL);
9885
9886 /* allocate temporary memory for the list of implied to zero variables */
9887 zeroitemssize = MIN(nbinvars, MAX_ZEROITEMS_SIZE); /* initial size of zeroitems buffer */
9888 SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[0], nbinvars) );
9889 SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[1], nbinvars) );
9890
9891 assert(conshdlrdata->ints1size > 0);
9892 assert(conshdlrdata->ints2size > 0);
9893 assert(conshdlrdata->longints1size > 0);
9894 assert(conshdlrdata->longints2size > 0);
9895
9896 /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9897 * than binary + integer variables existed at the presolving initialization method, but for example if you would
9898 * transform all integers into their binary representation then it maybe happens
9899 */
9900 if( conshdlrdata->ints1size < nbinvars )
9901 {
9902 int oldsize = conshdlrdata->ints1size;
9903
9904 conshdlrdata->ints1size = nbinvars;
9905 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints1, oldsize, conshdlrdata->ints1size) );
9906 BMSclearMemoryArray(&(conshdlrdata->ints1[oldsize]), conshdlrdata->ints1size - oldsize); /*lint !e866*/
9907 }
9908 if( conshdlrdata->ints2size < nbinvars )
9909 {
9910 int oldsize = conshdlrdata->ints2size;
9911
9912 conshdlrdata->ints2size = nbinvars;
9913 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints2, oldsize, conshdlrdata->ints2size) );
9914 BMSclearMemoryArray(&(conshdlrdata->ints2[oldsize]), conshdlrdata->ints2size - oldsize); /*lint !e866*/
9915 }
9916 if( conshdlrdata->longints1size < nbinvars )
9917 {
9918 int oldsize = conshdlrdata->longints1size;
9919
9920 conshdlrdata->longints1size = nbinvars;
9921 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints1, oldsize, conshdlrdata->longints1size) );
9922 BMSclearMemoryArray(&(conshdlrdata->longints1[oldsize]), conshdlrdata->longints1size - oldsize); /*lint !e866*/
9923 }
9924 if( conshdlrdata->longints2size < nbinvars )
9925 {
9926 int oldsize = conshdlrdata->longints2size;
9927
9928 conshdlrdata->longints2size = nbinvars;
9929 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints2, oldsize, conshdlrdata->longints2size) );
9930 BMSclearMemoryArray(&(conshdlrdata->longints2[oldsize]), conshdlrdata->longints2size - oldsize); /*lint !e866*/
9931 }
9932
9933 firstidxs[0] = conshdlrdata->ints1;
9934 firstidxs[1] = conshdlrdata->ints2;
9935 zeroweightsums[0] = conshdlrdata->longints1;
9936 zeroweightsums[1] = conshdlrdata->longints2;
9937
9938 /* check for cleared arrays, all entries are zero */
9939#ifndef NDEBUG
9940 for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9941 {
9942 assert(firstidxs[0][tmp] == 0);
9943 assert(firstidxs[1][tmp] == 0);
9944 assert(zeroweightsums[0][tmp] == 0);
9945 assert(zeroweightsums[1][tmp] == 0);
9946 }
9947#endif
9948
9949 SCIP_CALL( SCIPallocBufferArray(scip, &zeroitems, zeroitemssize) );
9950 SCIP_CALL( SCIPallocBufferArray(scip, &nextidxs, zeroitemssize) );
9951
9952 zeroitems[0] = -1; /* dummy element */
9953 nextidxs[0] = -1;
9954 nzeroitems = 1;
9955 nliftcands[0] = 0;
9956 nliftcands[1] = 0;
9957
9958 assert(conshdlrdata->bools1size > 0);
9959 assert(conshdlrdata->bools2size > 0);
9960
9961 /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9962 * than binary + integer variables existed at the presolving initialization method, but for example if you would
9963 * transform all integers into their binary representation then it maybe happens
9964 */
9965 if( conshdlrdata->bools1size < nbinvars )
9966 {
9967 int oldsize = conshdlrdata->bools1size;
9968
9969 conshdlrdata->bools1size = nbinvars;
9970 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools1, oldsize, conshdlrdata->bools1size) );
9971 BMSclearMemoryArray(&(conshdlrdata->bools1[oldsize]), conshdlrdata->bools1size - oldsize); /*lint !e866*/
9972 }
9973 if( conshdlrdata->bools2size < nbinvars )
9974 {
9975 int oldsize = conshdlrdata->bools2size;
9976
9977 conshdlrdata->bools2size = nbinvars;
9978 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools2, oldsize, conshdlrdata->bools2size) );
9979 BMSclearMemoryArray(&(conshdlrdata->bools2[oldsize]), conshdlrdata->bools2size - oldsize); /*lint !e866*/
9980 }
9981
9982 zeroiteminserted[0] = conshdlrdata->bools1;
9983 zeroiteminserted[1] = conshdlrdata->bools2;
9984
9985 /* check for cleared arrays, all entries are zero */
9986#ifndef NDEBUG
9987 for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9988 {
9989 assert(zeroiteminserted[0][tmp] == 0);
9990 assert(zeroiteminserted[1][tmp] == 0);
9991 }
9992#endif
9993
9994 SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices3, consdata->nvars) );
9995 SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices2, 2 * nbinvars) );
9996 SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices3, consdata->nvars) );
9997 SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices2, 2 * nbinvars) );
9998 SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, 2 * nbinvars) );
9999 SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices, 2 * nbinvars) );
10000
10001 tmp2 = 0;
10002 tmp3 = 0;
10003
10004 memlimitreached = FALSE;
10005 for( i = 0; i < consdata->nvars && !memlimitreached; ++i )
10006 {
10007 SCIP_CLIQUE** cliques;
10008 SCIP_VAR* var;
10009 SCIP_Longint weight;
10010 SCIP_Bool value;
10011 int varprobindex;
10012 int ncliques;
10013 int j;
10014
10015 tmp = 0;
10016
10017 /* get corresponding active problem variable */
10018 var = consdata->vars[i];
10019 weight = consdata->weights[i];
10020 value = TRUE;
10021 SCIP_CALL( SCIPvarGetProbvarBinary(&var, &value) );
10022 varprobindex = SCIPvarGetProbindex(var);
10023 assert(0 <= varprobindex && varprobindex < nbinvars);
10024
10025 /* update the zeroweightsum */
10026 zeroweightsums[!value][varprobindex] += weight; /*lint !e514*/
10027 tmpboolindices3[tmp3] = !value;
10028 tmpindices3[tmp3] = varprobindex;
10029 ++tmp3;
10030
10031 /* initialize the arrays of inserted zero items */
10032 /* first add the implications (~x == 1 -> x == 0) */
10033 {
10034 SCIP_Bool implvalue;
10035 int probindex;
10036
10037 probindex = SCIPvarGetProbindex(var);
10038 assert(0 <= probindex && probindex < nbinvars);
10039
10040 implvalue = !value;
10041
10042 /* insert the item into the list of the implied variable/value */
10043 assert( !zeroiteminserted[implvalue][probindex] );
10044
10045 if( firstidxs[implvalue][probindex] == 0 )
10046 {
10047 tmpboolindices2[tmp2] = implvalue;
10048 tmpindices2[tmp2] = probindex;
10049 ++tmp2;
10050 }
10051 SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
10052 &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
10053 &memlimitreached) );
10054 zeroiteminserted[implvalue][probindex] = TRUE;
10055 tmpboolindices[tmp] = implvalue;
10056 tmpindices[tmp] = probindex;
10057 ++tmp;
10058 }
10059
10060 /* get the cliques where the knapsack item is member of with value 1 */
10061 ncliques = SCIPvarGetNCliques(var, value);
10062 cliques = SCIPvarGetCliques(var, value);
10063 for( j = 0; j < ncliques && !memlimitreached; ++j )
10064 {
10065 SCIP_VAR** cliquevars;
10066 SCIP_Bool* cliquevalues;
10067 int ncliquevars;
10068 int k;
10069
10070 ncliquevars = SCIPcliqueGetNVars(cliques[j]);
10071
10072 /* discard big cliques */
10073 if( ncliquevars > MAX_CLIQUELENGTH )
10074 continue;
10075
10076 cliquevars = SCIPcliqueGetVars(cliques[j]);
10077 cliquevalues = SCIPcliqueGetValues(cliques[j]);
10078
10079 for( k = ncliquevars - 1; k >= 0; --k )
10080 {
10081 SCIP_Bool implvalue;
10082 int probindex;
10083
10084 if( var == cliquevars[k] )
10085 continue;
10086
10087 probindex = SCIPvarGetProbindex(cliquevars[k]);
10088 if( probindex == -1 )
10089 continue;
10090
10091 assert(0 <= probindex && probindex < nbinvars);
10092 implvalue = cliquevalues[k];
10093
10094 /* insert the item into the list of the clique variable/value */
10095 if( !zeroiteminserted[implvalue][probindex] )
10096 {
10097 if( firstidxs[implvalue][probindex] == 0 )
10098 {
10099 tmpboolindices2[tmp2] = implvalue;
10100 tmpindices2[tmp2] = probindex;
10101 ++tmp2;
10102 }
10103
10104 SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
10105 &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
10106 &memlimitreached) );
10107 zeroiteminserted[implvalue][probindex] = TRUE;
10108 tmpboolindices[tmp] = implvalue;
10109 tmpindices[tmp] = probindex;
10110 ++tmp;
10111
10112 if( memlimitreached )
10113 break;
10114 }
10115 }
10116 }
10117 /* clear zeroiteminserted */
10118 for( --tmp; tmp >= 0; --tmp)
10119 zeroiteminserted[tmpboolindices[tmp]][tmpindices[tmp]] = FALSE;
10120 }
10121 SCIPfreeBufferArray(scip, &tmpboolindices);
10122
10123 /* calculate the clique partition and the maximal sum of weights using the clique information */
10124 assert(consdata->sorted);
10125 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10126
10127 assert(conshdlrdata->bools3size > 0);
10128
10129 /* next if condition should normally not be true, because it means that presolving has created more binary variables
10130 * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10131 * method, but for example if you would transform all integers into their binary representation then it maybe happens
10132 */
10133 if( conshdlrdata->bools3size < consdata->nvars )
10134 {
10135 int oldsize = conshdlrdata->bools3size;
10136
10137 conshdlrdata->bools3size = consdata->nvars;;
10138 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools3, oldsize, conshdlrdata->bools3size) );
10139 BMSclearMemoryArray(&(conshdlrdata->bools3[oldsize]), conshdlrdata->bools3size - oldsize); /*lint !e866*/
10140 }
10141
10142 cliqueused = conshdlrdata->bools3;
10143
10144 /* check for cleared array, all entries are zero */
10145#ifndef NDEBUG
10146 for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10147 assert(cliqueused[tmp] == 0);
10148#endif
10149
10150 maxcliqueweightsum = 0;
10151 tmp = 0;
10152
10153 /* calculates maximal weight of cliques */
10154 for( i = 0; i < consdata->nvars; ++i )
10155 {
10156 cliquenum = consdata->cliquepartition[i];
10157 assert(0 <= cliquenum && cliquenum < consdata->nvars);
10158
10159 if( !cliqueused[cliquenum] )
10160 {
10161 maxcliqueweightsum += consdata->weights[i];
10162 cliqueused[cliquenum] = TRUE;
10163 tmpindices[tmp] = cliquenum;
10164 ++tmp;
10165 }
10166 }
10167 /* clear cliqueused */
10168 for( --tmp; tmp >= 0; --tmp)
10169 cliqueused[tmp] = FALSE;
10170
10171 assert(conshdlrdata->bools4size > 0);
10172
10173 /* next if condition should normally not be true, because it means that presolving has created more binary variables
10174 * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10175 * method, but for example if you would transform all integers into their binary representation then it maybe happens
10176 */
10177 if( conshdlrdata->bools4size < consdata->nvars )
10178 {
10179 int oldsize = conshdlrdata->bools4size;
10180
10181 conshdlrdata->bools4size = consdata->nvars;
10182 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools4, oldsize, conshdlrdata->bools4size) );
10183 BMSclearMemoryArray(&conshdlrdata->bools4[oldsize], conshdlrdata->bools4size - oldsize); /*lint !e866*/
10184 }
10185
10186 itemremoved = conshdlrdata->bools4;
10187
10188 /* check for cleared array, all entries are zero */
10189#ifndef NDEBUG
10190 for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10191 assert(itemremoved[tmp] == 0);
10192#endif
10193
10194 /* for each binary variable xi and each fixing v, calculate the cliqueweightsum and update the weight of the
10195 * variable in the knapsack (this is sequence-dependent because the new or modified weights have to be
10196 * included in subsequent cliqueweightsum calculations)
10197 */
10198 SCIP_CALL( SCIPallocBufferArray(scip, &addvars, 2*nbinvars) );
10199 SCIP_CALL( SCIPallocBufferArray(scip, &addweights, 2*nbinvars) );
10200 naddvars = 0;
10201 addweightsum = 0;
10202 for( val = 0; val < 2 && addweightsum < consdata->capacity; ++val )
10203 {
10204 for( i = 0; i < nliftcands[val] && addweightsum < consdata->capacity; ++i )
10205 {
10206 SCIP_Longint cliqueweightsum;
10207 int probindex;
10208 int idx;
10209 int j;
10210
10211 tmp = 0;
10212
10213 probindex = liftcands[val][i];
10214 assert(0 <= probindex && probindex < nbinvars);
10215
10216 /* ignore empty zero lists and variables that cannot be lifted anyways */
10217 if( firstidxs[val][probindex] == 0
10218 || maxcliqueweightsum - zeroweightsums[val][probindex] + addweightsum >= consdata->capacity )
10219 continue;
10220
10221 /* mark the items that are implied to zero by setting the current variable to the current value */
10222 for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10223 {
10224 assert(0 < idx && idx < nzeroitems);
10225 assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10226 itemremoved[zeroitems[idx]] = TRUE;
10227 }
10228
10229 /* calculate the residual cliqueweight sum */
10230 cliqueweightsum = addweightsum; /* the previously added items are single-element cliques */
10231 for( j = 0; j < consdata->nvars; ++j )
10232 {
10233 cliquenum = consdata->cliquepartition[j];
10234 assert(0 <= cliquenum && cliquenum < consdata->nvars);
10235 if( !itemremoved[j] )
10236 {
10237 if( !cliqueused[cliquenum] )
10238 {
10239 cliqueweightsum += consdata->weights[j];
10240 cliqueused[cliquenum] = TRUE;
10241 tmpindices[tmp] = cliquenum;
10242 ++tmp;
10243 }
10244
10245 if( cliqueweightsum >= consdata->capacity )
10246 break;
10247 }
10248 }
10249
10250 /* check if the weight of the variable/value can be increased */
10251 if( cliqueweightsum < consdata->capacity )
10252 {
10253 SCIP_VAR* var;
10254 SCIP_Longint weight;
10255
10256 /* insert the variable (with value TRUE) in the list of additional items */
10257 assert(naddvars < 2*nbinvars);
10258 var = binvars[probindex];
10259 if( val == FALSE )
10260 {
10261 SCIP_CALL( SCIPgetNegatedVar(scip, var, &var) );
10262 }
10263 weight = consdata->capacity - cliqueweightsum;
10264 addvars[naddvars] = var;
10265 addweights[naddvars] = weight;
10266 addweightsum += weight;
10267 naddvars++;
10268
10269 SCIPdebugMsg(scip, "knapsack constraint <%s>: adding lifted item %" SCIP_LONGINT_FORMAT "<%s>\n",
10270 SCIPconsGetName(cons), weight, SCIPvarGetName(var));
10271 }
10272
10273 /* clear itemremoved */
10274 for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10275 {
10276 assert(0 < idx && idx < nzeroitems);
10277 assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10278 itemremoved[zeroitems[idx]] = FALSE;
10279 }
10280 /* clear cliqueused */
10281 for( --tmp; tmp >= 0; --tmp)
10282 cliqueused[tmpindices[tmp]] = FALSE;
10283 }
10284 }
10285
10286 /* clear part of zeroweightsums */
10287 for( --tmp3; tmp3 >= 0; --tmp3)
10288 zeroweightsums[tmpboolindices3[tmp3]][tmpindices3[tmp3]] = 0;
10289
10290 /* clear rest of zeroweightsums and firstidxs */
10291 for( --tmp2; tmp2 >= 0; --tmp2)
10292 {
10293 zeroweightsums[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10294 firstidxs[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10295 }
10296
10297 /* add all additional item weights */
10298 for( i = 0; i < naddvars; ++i )
10299 {
10300 SCIP_CALL( addCoef(scip, cons, addvars[i], addweights[i]) );
10301 }
10302 *nchgcoefs += naddvars;
10303
10304 if( naddvars > 0 )
10305 {
10306 /* if new items were added, multiple entries of the same variable are possible and we have to clean up the constraint */
10307 SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10308 }
10309
10310 /* free temporary memory */
10311 SCIPfreeBufferArray(scip, &addweights);
10312 SCIPfreeBufferArray(scip, &addvars);
10313 SCIPfreeBufferArray(scip, &tmpindices);
10314 SCIPfreeBufferArray(scip, &tmpindices2);
10315 SCIPfreeBufferArray(scip, &tmpindices3);
10316 SCIPfreeBufferArray(scip, &tmpboolindices2);
10317 SCIPfreeBufferArray(scip, &tmpboolindices3);
10318 SCIPfreeBufferArray(scip, &nextidxs);
10319 SCIPfreeBufferArray(scip, &zeroitems);
10320 SCIPfreeBufferArray(scip, &liftcands[1]);
10321 SCIPfreeBufferArray(scip, &liftcands[0]);
10322
10323 return SCIP_OKAY;
10324}
10325
10326/** tightens item weights and capacity in presolving:
10327 * given a knapsack sum(wi*xi) <= capacity
10328 * (1) let weightsum := sum(wi)
10329 * if weightsum - wi < capacity:
10330 * - not using item i would make the knapsack constraint redundant
10331 * - wi and capacity can be changed to have the same redundancy effect and the same results for
10332 * fixing xi to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10333 * - change coefficients:
10334 * wi' := weightsum - capacity
10335 * capacity' := capacity - (wi - wi')
10336 * (2) increase weights from front to back(sortation is necessary) if there is no space left for another weight
10337 * - determine the four(can be adjusted) minimal weightsums of the knapsack, i.e. in increasing order
10338 * weights[nvars - 1], weights[nvars - 2], MIN(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]),
10339 * MIN(MAX(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]), weights[nvars - 4]), note that there
10340 * can be multiple times the same weight, this can be improved
10341 * - check if summing up a minimal weightsum with a big weight exceeds the capacity, then we can increase the big
10342 * weight, to capacity - lastmininmalweightsum, e.g. :
10343 * 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19
10344 * -> minimal weightsums: 5, 5, 10, 10
10345 * -> 15 + 5 > 19 => increase 15 to 19 - 0 = 19
10346 * -> 10 + 10 > 19 => increase 10 to 19 - 5 = 14, resulting in
10347 * 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10348 * (3) let W(C) be the maximal weight of clique C,
10349 * cliqueweightsum := sum(W(C))
10350 * if cliqueweightsum - W(C) < capacity:
10351 * - not using any item of C would make the knapsack constraint redundant
10352 * - weights wi, i in C, and capacity can be changed to have the same redundancy effect and the same results for
10353 * fixing xi, i in C, to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10354 * - change coefficients:
10355 * delta := capacity - (cliqueweightsum - W(C))
10356 * wi' := max(wi - delta, 0)
10357 * capacity' := capacity - delta
10358 * This rule has to add the used cliques in order to ensure they are enforced - otherwise, the reduction might
10359 * introduce infeasible solutions.
10360 * (4) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
10361 * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
10362 * if cliqueweightsum(xi == v) < capacity:
10363 * - fixing variable xi to v would make the knapsack constraint redundant
10364 * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
10365 * redundancy effect:
10366 * wi' := capacity - cliqueweightsum(xi == v)
10367 * This rule can also be applied to binary variables not in the knapsack!
10368 * (5) if min{w} + wi > capacity:
10369 * - using item i would force to fix other items to zero
10370 * - wi can be increased to the capacity
10371 */
10372static
10374 SCIP* scip, /**< SCIP data structure */
10375 SCIP_CONS* cons, /**< knapsack constraint */
10376 SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
10377 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10378 int* nchgsides, /**< pointer to count number of side changes */
10379 int* naddconss, /**< pointer to count number of added constraints */
10380 int* ndelconss, /**< pointer to count number of deleted constraints */
10381 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
10382 )
10383{
10384 SCIP_CONSHDLRDATA* conshdlrdata;
10385 SCIP_CONSDATA* consdata;
10386 SCIP_Longint* weights;
10387 SCIP_Longint sumcoef;
10388 SCIP_Longint capacity;
10389 SCIP_Longint newweight;
10390 SCIP_Longint maxweight;
10391 SCIP_Longint minweight;
10392 SCIP_Bool sumcoefcase = FALSE;
10393 int startpos;
10394 int backpos;
10395 int nvars;
10396 int pos;
10397 int k;
10398 int i;
10399
10400 assert(nchgcoefs != NULL);
10401 assert(nchgsides != NULL);
10402 assert(!SCIPconsIsModifiable(cons));
10403
10404 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
10405 assert(conshdlrdata != NULL);
10406
10407 consdata = SCIPconsGetData(cons);
10408 assert(consdata != NULL);
10409 assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
10410 assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
10411 assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
10412 assert(consdata->nvars > 0);
10413
10414 SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10415 if( *cutoff )
10416 return SCIP_OKAY;
10417
10418 /* apply rule (1) */
10419 if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10420 {
10421 do
10422 {
10423 assert(consdata->merged);
10424
10425 /* sort items, s.t. the heaviest one is in the first position */
10426 sortItems(consdata);
10427
10428 for( i = 0; i < consdata->nvars; ++i )
10429 {
10430 SCIP_Longint weight;
10431
10432 weight = consdata->weights[i];
10433 if( consdata->weightsum - weight < consdata->capacity )
10434 {
10435 newweight = consdata->weightsum - consdata->capacity;
10436 consdataChgWeight(consdata, i, newweight);
10437 consdata->capacity -= (weight - newweight);
10438 (*nchgcoefs)++;
10439 (*nchgsides)++;
10440 assert(!consdata->sorted);
10441 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",
10442 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, newweight,
10443 consdata->capacity + (weight-newweight), consdata->capacity);
10444 }
10445 else
10446 break;
10447 }
10448 }
10449 while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10450 }
10451
10452 /* check for redundancy */
10453 if( consdata->weightsum <= consdata->capacity )
10454 return SCIP_OKAY;
10455
10456 pos = 0;
10457 while( pos < consdata->nvars && consdata->weights[pos] == consdata->capacity )
10458 ++pos;
10459
10460 sumcoef = 0;
10461 weights = consdata->weights;
10462 nvars = consdata->nvars;
10463 capacity = consdata->capacity;
10464
10465 if( (presoltiming & (SCIP_PRESOLTIMING_FAST | SCIP_PRESOLTIMING_MEDIUM)) != 0 &&
10466 pos < nvars && weights[pos] + weights[pos + 1] > capacity )
10467 {
10468 /* further reductions using the next possible coefficient sum
10469 *
10470 * e.g. 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19 <=> 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10471 */
10472 /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
10473 for( k = 0; k < 4; ++k )
10474 {
10475 newweight = capacity - sumcoef;
10476
10477 /* determine next minimal coefficient sum */
10478 switch( k )
10479 {
10480 case 0:
10481 sumcoef = weights[nvars - 1];
10482 backpos = nvars - 1;
10483 break;
10484 case 1:
10485 sumcoef = weights[nvars - 2];
10486 backpos = nvars - 2;
10487 break;
10488 case 2:
10489 if( weights[nvars - 3] < weights[nvars - 1] + weights[nvars - 2] )
10490 {
10491 sumcoefcase = TRUE;
10492 sumcoef = weights[nvars - 3];
10493 backpos = nvars - 3;
10494 }
10495 else
10496 {
10497 sumcoefcase = FALSE;
10498 sumcoef = weights[nvars - 1] + weights[nvars - 2];
10499 backpos = nvars - 2;
10500 }
10501 break;
10502 default:
10503 assert(k == 3);
10504 if( sumcoefcase )
10505 {
10506 if( weights[nvars - 4] < weights[nvars - 1] + weights[nvars - 2] )
10507 {
10508 sumcoef = weights[nvars - 4];
10509 backpos = nvars - 4;
10510 }
10511 else
10512 {
10513 sumcoef = weights[nvars - 1] + weights[nvars - 2];
10514 backpos = nvars - 2;
10515 }
10516 }
10517 else
10518 {
10519 sumcoef = weights[nvars - 3];
10520 backpos = nvars - 3;
10521 }
10522 break;
10523 }
10524
10525 if( backpos <= pos )
10526 break;
10527
10528 /* tighten next coefficients that, paired with the current small coefficient, exceed the capacity */
10529 maxweight = weights[pos];
10530 startpos = pos;
10531 while( 2 * maxweight > capacity && maxweight + sumcoef > capacity )
10532 {
10533 assert(newweight > weights[pos]);
10534
10535 SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10536 SCIPconsGetName(cons), maxweight, newweight);
10537
10538 consdataChgWeight(consdata, pos, newweight);
10539
10540 ++pos;
10541 assert(pos < nvars);
10542
10543 maxweight = weights[pos];
10544
10545 if( backpos <= pos )
10546 break;
10547 }
10548 (*nchgcoefs) += (pos - startpos);
10549
10550 /* skip unchangable weights */
10551 while( pos < nvars && weights[pos] + sumcoef == capacity )
10552 ++pos;
10553
10554 /* check special case were there is only one weight left to tighten
10555 *
10556 * e.g. 95x1 + 59x2 + 37x3 + 36x4 <= 95 (37 > 36)
10557 *
10558 * => 95x1 + 59x2 + 59x3 + 36x4 <= 95
10559 *
10560 * 197x1 + 120x2 + 77x3 + 10x4 <= 207 (here we cannot tighten the coefficient further)
10561 */
10562 if( pos + 1 == backpos && weights[pos] > sumcoef &&
10563 ((k == 0) || (k == 1 && weights[nvars - 1] + sumcoef + weights[pos] > capacity)) )
10564 {
10565 newweight = capacity - sumcoef;
10566 assert(newweight > weights[pos]);
10567
10568 SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10569 SCIPconsGetName(cons), maxweight, newweight);
10570
10571 consdataChgWeight(consdata, pos, newweight);
10572
10573 break;
10574 }
10575
10576 if( backpos <= pos )
10577 break;
10578 }
10579 }
10580
10581 /* apply rule (2) (don't apply, if the knapsack has too many items for applying this costly method) */
10582 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
10583 {
10584 if( conshdlrdata->disaggregation && SCIPconsGetNUpgradeLocks(cons) == 0
10585 && consdata->nvars - pos <= MAX_USECLIQUES_SIZE && consdata->nvars >= 2 && pos > 0
10586 && (SCIP_Longint)consdata->nvars - pos <= consdata->capacity
10587 && consdata->weights[pos - 1] == consdata->capacity
10588 && ( pos == consdata->nvars || consdata->weights[pos] == 1 ) )
10589 {
10590 SCIP_VAR** clqvars;
10591 SCIP_CONS* cliquecons;
10592 char name[SCIP_MAXSTRLEN];
10593 int* clqpart;
10594 int nclqvars;
10595 int nclq;
10596 int len;
10597 int c;
10598 int w;
10599
10600 assert(!SCIPconsIsDeleted(cons));
10601
10602 if( pos == consdata->nvars )
10603 {
10604 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
10605
10606 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, SCIPconsGetName(cons), pos, consdata->vars,
10610 SCIPconsIsStickingAtNode(cons)) );
10611
10612 /* add the upgraded constraint to the problem */
10613 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10614 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10615 ++(*naddconss);
10616
10617 /* delete old constraint */
10618 SCIP_CALL( SCIPdelCons(scip, cons) );
10619 ++(*ndelconss);
10620
10621 return SCIP_OKAY;
10622 }
10623
10624 len = consdata->nvars - pos;
10625
10626 /* allocate temporary memory */
10627 SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
10628
10629 /* calculate clique partition */
10630 SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[pos]), len, &conshdlrdata->probtoidxmap, &conshdlrdata->probtoidxmapsize, clqpart, &nclq) );
10631 assert(nclq <= len);
10632
10633#ifndef NDEBUG
10634 /* clique numbers must be at least as high as the index */
10635 for( w = 0; w < nclq; ++w )
10636 assert(clqpart[w] <= w);
10637#endif
10638
10639 SCIPdebugMsg(scip, "Disaggregating knapsack constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
10640
10641 /* allocate temporary memory */
10642 SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, pos + len - nclq + 1) );
10643
10644 /* copy corresponding variables with big coefficients */
10645 for( w = pos - 1; w >= 0; --w )
10646 clqvars[w] = consdata->vars[w];
10647
10648 /* create for each clique a set-packing constraint */
10649 for( c = 0; c < nclq; ++c )
10650 {
10651 nclqvars = pos;
10652
10653 for( w = c; w < len; ++w )
10654 {
10655 if( clqpart[w] == c )
10656 {
10657 assert(nclqvars < pos + len - nclq + 1);
10658 clqvars[nclqvars] = consdata->vars[w + pos];
10659 ++nclqvars;
10660 }
10661 }
10662
10663 assert(nclqvars > 1);
10664
10665 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, c);
10666 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
10670 SCIPconsIsStickingAtNode(cons)) );
10671
10672 /* add the special constraint to the problem */
10673 SCIPdebugMsg(scip, " -> adding clique constraint: ");
10674 SCIPdebugPrintCons(scip, cliquecons, NULL);
10675 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10676 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10677 ++(*naddconss);
10678 }
10679
10680 /* delete old constraint */
10681 SCIP_CALL( SCIPdelCons(scip, cons) );
10682 ++(*ndelconss);
10683
10684 SCIPfreeBufferArray(scip, &clqvars);
10685 SCIPfreeBufferArray(scip, &clqpart);
10686
10687 return SCIP_OKAY;
10688 }
10689 else if( consdata->nvars <= MAX_USECLIQUES_SIZE || (consdata->cliquepartitioned && consdata->ncliques <= MAX_USECLIQUES_SIZE) )
10690 {
10691 SCIP_Longint* maxcliqueweights;
10692 SCIP_Longint* newweightvals;
10693 int* newweightidxs;
10694 SCIP_Longint cliqueweightsum;
10695
10696 SCIP_CALL( SCIPallocBufferArray(scip, &maxcliqueweights, consdata->nvars) );
10697 SCIP_CALL( SCIPallocBufferArray(scip, &newweightvals, consdata->nvars) );
10698 SCIP_CALL( SCIPallocBufferArray(scip, &newweightidxs, consdata->nvars) );
10699
10700 /* repeat as long as changes have been applied */
10701 do
10702 {
10703 int ncliques;
10704 int cliquenum;
10705 SCIP_Bool zeroweights;
10706
10707 assert(consdata->merged);
10708
10709 /* sort items, s.t. the heaviest one is in the first position */
10710 sortItems(consdata);
10711
10712 /* calculate a clique partition */
10713 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10714
10715 /* if there are only single element cliques, rule (2) is equivalent to rule (1) */
10716 if( consdata->cliquepartition[consdata->nvars - 1] == consdata->nvars - 1 )
10717 break;
10718
10719 /* calculate the maximal weight of the cliques and store the clique type */
10720 cliqueweightsum = 0;
10721 ncliques = 0;
10722
10723 for( i = 0; i < consdata->nvars; ++i )
10724 {
10725 SCIP_Longint weight;
10726
10727 cliquenum = consdata->cliquepartition[i];
10728 assert(0 <= cliquenum && cliquenum <= ncliques);
10729
10730 weight = consdata->weights[i];
10731 assert(weight > 0);
10732
10733 if( cliquenum == ncliques )
10734 {
10735 maxcliqueweights[ncliques] = weight;
10736 cliqueweightsum += weight;
10737 ++ncliques;
10738 }
10739
10740 assert(maxcliqueweights[cliquenum] >= weight);
10741 }
10742
10743 /* apply rule on every clique */
10744 zeroweights = FALSE;
10745 for( i = 0; i < ncliques; ++i )
10746 {
10747 SCIP_Longint delta;
10748
10749 delta = consdata->capacity - (cliqueweightsum - maxcliqueweights[i]);
10750 if( delta > 0 )
10751 {
10752 SCIP_Longint newcapacity;
10753#ifndef NDEBUG
10754 SCIP_Longint newmincliqueweight;
10755#endif
10756 SCIP_Longint newminweightsuminclique;
10757 SCIP_Bool forceclique;
10758 int nnewweights;
10759 int j;
10760
10761 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",
10762 SCIPconsGetName(cons), i, maxcliqueweights[i], cliqueweightsum, consdata->capacity, delta);
10763 newcapacity = consdata->capacity - delta;
10764 forceclique = FALSE;
10765 nnewweights = 0;
10766#ifndef NDEBUG
10767 newmincliqueweight = newcapacity + 1;
10768 for( j = 0; j < i; ++j )
10769 assert(consdata->cliquepartition[j] < i); /* no element j < i can be in clique i */
10770#endif
10771 for( j = i; j < consdata->nvars; ++j )
10772 {
10773 if( consdata->cliquepartition[j] == i )
10774 {
10775 newweight = consdata->weights[j] - delta;
10776 newweight = MAX(newweight, 0);
10777
10778 /* cache the new weight */
10779 assert(nnewweights < consdata->nvars);
10780 newweightvals[nnewweights] = newweight;
10781 newweightidxs[nnewweights] = j;
10782 nnewweights++;
10783
10784#ifndef NDEBUG
10785 assert(newweight <= newmincliqueweight); /* items are sorted by non-increasing weight! */
10786 newmincliqueweight = newweight;
10787#endif
10788 }
10789 }
10790
10791 /* check if our clique information results out of this knapsack constraint and if so check if we would loose the clique information */
10792 if( nnewweights > 1 )
10793 {
10794#ifndef NDEBUG
10795 j = newweightidxs[nnewweights - 2];
10796 assert(0 <= j && j < consdata->nvars);
10797 assert(consdata->cliquepartition[j] == i);
10798 j = newweightidxs[nnewweights - 1];
10799 assert(0 <= j && j < consdata->nvars);
10800 assert(consdata->cliquepartition[j] == i);
10801#endif
10802
10803 newminweightsuminclique = newweightvals[nnewweights - 2];
10804 newminweightsuminclique += newweightvals[nnewweights - 1];
10805
10806 /* check if these new two minimal weights both fit into the knapsack;
10807 * if this is true, we have to add a clique constraint in order to enforce the clique
10808 * (otherwise, the knapsack might have been one of the reasons for the clique, and the weight
10809 * reduction might be infeasible, i.e., allows additional solutions)
10810 */
10811 if( newminweightsuminclique <= newcapacity )
10812 forceclique = TRUE;
10813 }
10814
10815 /* check if we really want to apply the change */
10816 if( conshdlrdata->disaggregation || !forceclique )
10817 {
10818 SCIPdebugMsg(scip, " -> change capacity from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT " (forceclique:%u)\n",
10819 consdata->capacity, newcapacity, forceclique);
10820 consdata->capacity = newcapacity;
10821 (*nchgsides)++;
10822
10823 for( k = 0; k < nnewweights; ++k )
10824 {
10825 j = newweightidxs[k];
10826 assert(0 <= j && j < consdata->nvars);
10827 assert(consdata->cliquepartition[j] == i);
10828
10829 /* apply the weight change */
10830 SCIPdebugMsg(scip, " -> change weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10831 SCIPvarGetName(consdata->vars[j]), consdata->weights[j], newweightvals[k]);
10832 consdataChgWeight(consdata, j, newweightvals[k]);
10833 (*nchgcoefs)++;
10834 assert(!consdata->sorted);
10835 zeroweights = zeroweights || (newweightvals[k] == 0);
10836 }
10837 /* if before the weight update at least one pair of weights did not fit into the knapsack and now fits,
10838 * we have to make sure, the clique is enforced - the clique might have been constructed partially from
10839 * this constraint, and by reducing the weights, this clique information is not contained anymore in the
10840 * knapsack constraint
10841 */
10842 if( forceclique )
10843 {
10844 SCIP_CONS* cliquecons;
10845 char name[SCIP_MAXSTRLEN];
10846 SCIP_VAR** cliquevars;
10847
10848 SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nnewweights) );
10849 for( k = 0; k < nnewweights; ++k )
10850 cliquevars[k] = consdata->vars[newweightidxs[k]];
10851
10852 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, i);
10853 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nnewweights, cliquevars,
10857 SCIPconsIsStickingAtNode(cons)) );
10858
10859 /* add the special constraint to the problem */
10860 SCIPdebugMsg(scip, " -> adding clique constraint: ");
10861 SCIPdebugPrintCons(scip, cliquecons, NULL);
10862 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10863 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10864 ++(*naddconss);
10865
10866 /* free clique array */
10867 SCIPfreeBufferArray(scip, &cliquevars);
10868 }
10869 }
10870 }
10871 }
10872 if( zeroweights )
10873 {
10875 }
10876 }
10877 while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10878
10879 /* free temporary memory */
10880 SCIPfreeBufferArray(scip, &newweightidxs);
10881 SCIPfreeBufferArray(scip, &newweightvals);
10882 SCIPfreeBufferArray(scip, &maxcliqueweights);
10883
10884 /* check for redundancy */
10885 if( consdata->weightsum <= consdata->capacity )
10886 return SCIP_OKAY;
10887 }
10888 }
10889
10890 /* apply rule (3) */
10891 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
10892 {
10893 SCIP_CALL( tightenWeightsLift(scip, cons, nchgcoefs, cutoff) );
10894 }
10895
10896 /* check for redundancy */
10897 if( consdata->weightsum <= consdata->capacity )
10898 return SCIP_OKAY;
10899
10900 if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10901 {
10902 /* apply rule (4) (all but smallest weight) */
10903 assert(consdata->merged);
10904 sortItems(consdata);
10905 minweight = consdata->weights[consdata->nvars-1];
10906 for( i = 0; i < consdata->nvars-1; ++i )
10907 {
10908 SCIP_Longint weight;
10909
10910 weight = consdata->weights[i];
10911 assert(weight >= minweight);
10912 if( minweight + weight > consdata->capacity )
10913 {
10914 if( weight < consdata->capacity )
10915 {
10916 SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10917 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, consdata->capacity);
10918 assert(consdata->sorted);
10919 consdataChgWeight(consdata, i, consdata->capacity); /* this does not destroy the weight order! */
10920 assert(i == 0 || consdata->weights[i-1] >= consdata->weights[i]);
10921 consdata->sorted = TRUE;
10922 (*nchgcoefs)++;
10923 }
10924 }
10925 else
10926 break;
10927 }
10928
10929 /* apply rule (5) (smallest weight) */
10930 if( consdata->nvars >= 2 )
10931 {
10932 SCIP_Longint weight;
10933
10934 minweight = consdata->weights[consdata->nvars-2];
10935 weight = consdata->weights[consdata->nvars-1];
10936 assert(minweight >= weight);
10937 if( minweight + weight > consdata->capacity && weight < consdata->capacity )
10938 {
10939 SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10940 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[consdata->nvars-1]), weight, consdata->capacity);
10941 assert(consdata->sorted);
10942 consdataChgWeight(consdata, consdata->nvars-1, consdata->capacity); /* this does not destroy the weight order! */
10943 assert(minweight >= consdata->weights[consdata->nvars-1]);
10944 consdata->sorted = TRUE;
10945 (*nchgcoefs)++;
10946 }
10947 }
10948 }
10949
10950 return SCIP_OKAY;
10951}
10952
10953
10954#ifdef SCIP_DEBUG
10955static
10956void printClique(
10957 SCIP_VAR** cliquevars,
10958 int ncliquevars
10959 )
10960{
10961 int b;
10962 SCIPdebugMessage("adding new Clique: ");
10963 for( b = 0; b < ncliquevars; ++b )
10964 SCIPdebugPrintf("%s ", SCIPvarGetName(cliquevars[b]));
10965 SCIPdebugPrintf("\n");
10966}
10967#endif
10968
10969/** adds negated cliques of the knapsack constraint to the global clique table */
10970static
10972 SCIP*const scip, /**< SCIP data structure */
10973 SCIP_CONS*const cons, /**< knapsack constraint */
10974 SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
10975 int*const nbdchgs /**< pointer to count the number of performed bound changes */
10976 )
10977{
10978 SCIP_CONSDATA* consdata;
10979 SCIP_CONSHDLRDATA* conshdlrdata;
10980 SCIP_VAR** poscliquevars;
10981 SCIP_VAR** cliquevars;
10982 SCIP_Longint* maxweights;
10983 SCIP_Longint* gainweights;
10984 int* gaincliquepartition;
10985 SCIP_Bool* cliqueused;
10986 SCIP_Longint minactduetonegcliques;
10987 SCIP_Longint freecapacity;
10988 SCIP_Longint lastweight;
10989 SCIP_Longint beforelastweight;
10990 int nposcliquevars;
10991 int ncliquevars;
10992 int nvars;
10993 int nnegcliques;
10994 int lastcliqueused;
10995 int thisnbdchgs;
10996 int v;
10997 int w;
10998
10999 assert(scip != NULL);
11000 assert(cons != NULL);
11001 assert(cutoff != NULL);
11002 assert(nbdchgs != NULL);
11003
11004 *cutoff = FALSE;
11005
11006 consdata = SCIPconsGetData(cons);
11007 assert(consdata != NULL);
11008
11009 nvars = consdata->nvars;
11010
11011 /* check whether the cliques have already been added */
11012 if( consdata->cliquesadded || nvars == 0 )
11013 return SCIP_OKAY;
11014
11015 /* make sure, the items are merged */
11016 SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
11017 if( *cutoff )
11018 return SCIP_OKAY;
11019
11020 /* make sure, items are sorted by non-increasing weight */
11021 sortItems(consdata);
11022
11023 assert(consdata->merged);
11024
11025 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11026 assert(conshdlrdata != NULL);
11027
11028 /* calculate a clique partition */
11029 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
11030 nnegcliques = consdata->nnegcliques;
11031
11032 /* if we have no negated cliques, stop */
11033 if( nnegcliques == nvars )
11034 return SCIP_OKAY;
11035
11036 /* get temporary memory */
11037 SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
11038 SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
11039 SCIP_CALL( SCIPallocClearBufferArray(scip, &gainweights, nvars) );
11040 SCIP_CALL( SCIPallocBufferArray(scip, &gaincliquepartition, nvars) );
11041 SCIP_CALL( SCIPallocBufferArray(scip, &maxweights, nnegcliques) );
11042 SCIP_CALL( SCIPallocClearBufferArray(scip, &cliqueused, nnegcliques) );
11043
11044 nnegcliques = 0;
11045 minactduetonegcliques = 0;
11046
11047 /* determine maximal weights for all negated cliques and calculate minimal weightsum due to negated cliques */
11048 for( v = 0; v < nvars; ++v )
11049 {
11050 assert(0 <= consdata->negcliquepartition[v] && consdata->negcliquepartition[v] <= nnegcliques);
11051 assert(consdata->weights[v] > 0);
11052
11053 if( consdata->negcliquepartition[v] == nnegcliques )
11054 {
11055 nnegcliques++;
11056 maxweights[consdata->negcliquepartition[v]] = consdata->weights[v];
11057 }
11058 else
11059 minactduetonegcliques += consdata->weights[v];
11060 }
11061
11062 nposcliquevars = 0;
11063
11064 /* add cliques, using negated cliques information */
11065 if( minactduetonegcliques > 0 )
11066 {
11067 /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11068 freecapacity = consdata->capacity - minactduetonegcliques;
11069
11071 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",
11072 SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11073
11074 /* calculate possible gain by switching chosen items in negated cliques */
11075 for( v = 0; v < nvars; ++v )
11076 {
11077 if( !cliqueused[consdata->negcliquepartition[v]] )
11078 {
11079 cliqueused[consdata->negcliquepartition[v]] = TRUE;
11080 for( w = v + 1; w < nvars; ++w )
11081 {
11082 /* if we would take the biggest weight instead of another what would we gain, take weight[v] instead of
11083 * weight[w] (which are both in a negated clique) */
11084 if( consdata->negcliquepartition[v] == consdata->negcliquepartition[w]
11085 && consdata->weights[v] > consdata->weights[w] )
11086 {
11087 poscliquevars[nposcliquevars] = consdata->vars[w];
11088 gainweights[nposcliquevars] = maxweights[consdata->negcliquepartition[v]] - consdata->weights[w];
11089 gaincliquepartition[nposcliquevars] = consdata->negcliquepartition[v];
11090 ++nposcliquevars;
11091 }
11092 }
11093 }
11094 }
11095
11096 /* try to create negated cliques */
11097 if( nposcliquevars > 0 )
11098 {
11099 /* sort possible gain per substitution of the clique members */
11100 SCIPsortDownLongPtrInt(gainweights,(void**) poscliquevars, gaincliquepartition, nposcliquevars);
11101
11102 for( v = 0; v < nposcliquevars; ++v )
11103 {
11104 SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[v], &cliquevars[0]) );
11105 ncliquevars = 1;
11106 lastweight = gainweights[v];
11107 beforelastweight = -1;
11108 lastcliqueused = gaincliquepartition[v];
11109 /* clear cliqueused to get an unused array */
11110 BMSclearMemoryArray(cliqueused, nnegcliques);
11111 cliqueused[gaincliquepartition[v]] = TRUE;
11112
11113 /* taking bigger weights make the knapsack redundant so we will create cliques, only take items which are not
11114 * in the same negated clique and by taking two of them would exceed the free capacity */
11115 for( w = v + 1; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && gainweights[w] + lastweight > freecapacity; ++w )
11116 {
11117 beforelastweight = lastweight;
11118 lastweight = gainweights[w];
11119 lastcliqueused = gaincliquepartition[w];
11120 cliqueused[gaincliquepartition[w]] = TRUE;
11121 SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars]) );
11122 ++ncliquevars;
11123 }
11124
11125 if( ncliquevars > 1 )
11126 {
11127 SCIPdebug( printClique(cliquevars, ncliquevars) );
11128 assert(beforelastweight > 0);
11129 /* add the clique to the clique table */
11130 /* this really happens, e.g., on enigma.mps from the short test set */
11131 SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11132 if( *cutoff )
11133 goto TERMINATE;
11134 *nbdchgs += thisnbdchgs;
11135
11136 /* reset last used clique to get slightly different cliques */
11137 cliqueused[lastcliqueused] = FALSE;
11138
11139 /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11140 for( ++w; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && beforelastweight + gainweights[w] > freecapacity; ++w )
11141 {
11142 SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars - 1]) );
11143 SCIPdebug( printClique(cliquevars, ncliquevars) );
11144 SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11145 if( *cutoff )
11146 goto TERMINATE;
11147 *nbdchgs += thisnbdchgs;
11148 }
11149 }
11150 }
11151 }
11152 }
11153
11154 TERMINATE:
11155 /* free temporary memory */
11156 SCIPfreeBufferArray(scip, &cliqueused);
11157 SCIPfreeBufferArray(scip, &maxweights);
11158 SCIPfreeBufferArray(scip, &gaincliquepartition);
11159 SCIPfreeBufferArray(scip, &gainweights);
11160 SCIPfreeBufferArray(scip, &cliquevars);
11161 SCIPfreeBufferArray(scip, &poscliquevars);
11162
11163 return SCIP_OKAY;
11164}
11165
11166/** greedy clique detection by considering weights and capacity
11167 *
11168 * greedily detects cliques by first sorting the items by decreasing weights (optional) and then collecting greedily
11169 * 1) neighboring items which exceed the capacity together => one clique
11170 * 2) looping through the remaining items and finding the largest set of preceding items to build a clique => possibly many more cliques
11171 */
11172static
11174 SCIP*const scip, /**< SCIP data structure */
11175 SCIP_VAR** items, /**< array of variable items */
11176 SCIP_Longint* weights, /**< weights of the items */
11177 int nitems, /**< the number of items */
11178 SCIP_Longint capacity, /**< maximum free capacity of the knapsack */
11179 SCIP_Bool sorteditems, /**< are the items sorted by their weights nonincreasing? */
11180 SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11181 SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11182 int*const nbdchgs /**< pointer to count the number of performed bound changes */
11183 )
11184{
11185 SCIP_Longint lastweight;
11186 int ncliquevars;
11187 int i;
11188 int thisnbdchgs;
11189
11190 if( nitems <= 1 )
11191 return SCIP_OKAY;
11192
11193 /* sort possible gain per substitution of the clique members */
11194 if( ! sorteditems )
11195 SCIPsortDownLongPtr(weights,(void**) items, nitems);
11196
11197 ncliquevars = 1;
11198 lastweight = weights[0];
11199
11200 /* taking these two weights together violates the knapsack => include into clique */
11201 for( i = 1; i < nitems && weights[i] + lastweight > capacity; ++i )
11202 {
11203 lastweight = weights[i];
11204 ++ncliquevars;
11205 }
11206
11207 if( ncliquevars > 1 )
11208 {
11209 SCIP_Longint compareweight;
11210 SCIP_VAR** cliquevars;
11211 int compareweightidx;
11212 int minclqsize;
11213 int nnzadded;
11214
11215 /* add the clique to the clique table */
11216 SCIPdebug( printClique(items, ncliquevars) );
11217 SCIP_CALL( SCIPaddClique(scip, items, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11218
11219 if( *cutoff )
11220 return SCIP_OKAY;
11221
11222 *nbdchgs += thisnbdchgs;
11223 nnzadded = ncliquevars;
11224
11225 /* 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)*/
11226 if( ncliquevars == nitems )
11227 return SCIP_OKAY;
11228
11229 /* copy items in order into buffer array and deduce more cliques */
11230 SCIP_CALL( SCIPduplicateBufferArray(scip, &cliquevars, items, ncliquevars) );
11231
11232 /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11233 /* loop over remaining, smaller items and compare each item backwards against larger weights, starting with the second smallest weight */
11234 compareweightidx = ncliquevars - 2;
11235 assert(i == nitems || weights[i] + weights[ncliquevars - 1] <= capacity);
11236
11237 /* determine minimum clique size for the following loop */
11238 minclqsize = (int)(cliqueextractfactor * ncliquevars);
11239 minclqsize = MAX(minclqsize, 2);
11240
11241 /* loop over the remaining variables and the larger items of the first clique until we
11242 * find another clique or reach the size limit */
11243 while( compareweightidx >= 0 && i < nitems && ! (*cutoff)
11244 && ncliquevars >= minclqsize /* stop at a given minimum clique size */
11245 && nnzadded <= 2 * nitems /* stop if enough nonzeros were added to the cliquetable */
11246 )
11247 {
11248 compareweight = weights[compareweightidx];
11249 assert(compareweight > 0);
11250
11251 /* include this item together with all items that have a weight at least as large as the compare weight in a clique */
11252 if( compareweight + weights[i] > capacity )
11253 {
11254 assert(compareweightidx == ncliquevars -2);
11255 cliquevars[ncliquevars - 1] = items[i];
11256 SCIPdebug( printClique(cliquevars, ncliquevars) );
11257 SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11258
11259 nnzadded += ncliquevars;
11260
11261 /* stop when there is a cutoff */
11262 if( ! (*cutoff) )
11263 *nbdchgs += thisnbdchgs;
11264
11265 /* go to next smaller item */
11266 ++i;
11267 }
11268 else
11269 {
11270 /* choose a preceding, larger weight to compare small items against. Clique size is reduced by 1 simultaneously */
11271 compareweightidx--;
11272 ncliquevars --;
11273 }
11274 }
11275
11276 SCIPfreeBufferArray(scip, &cliquevars);
11277 }
11278
11279 return SCIP_OKAY;
11280}
11281
11282/** adds cliques of the knapsack constraint to the global clique table */
11283static
11285 SCIP*const scip, /**< SCIP data structure */
11286 SCIP_CONS*const cons, /**< knapsack constraint */
11287 SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11288 SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11289 int*const nbdchgs /**< pointer to count the number of performed bound changes */
11290 )
11291{
11292 SCIP_CONSDATA* consdata;
11293 SCIP_CONSHDLRDATA* conshdlrdata;
11294 int i;
11295 SCIP_Longint minactduetonegcliques;
11296 SCIP_Longint freecapacity;
11297 int nnegcliques;
11298 int cliquenum;
11299 SCIP_VAR** poscliquevars;
11300 SCIP_Longint* gainweights;
11301 int nposcliquevars;
11302 SCIP_Longint* secondmaxweights;
11303 int nvars;
11304
11305 assert(scip != NULL);
11306 assert(cons != NULL);
11307 assert(cutoff != NULL);
11308 assert(nbdchgs != NULL);
11309
11310 *cutoff = FALSE;
11311
11312 consdata = SCIPconsGetData(cons);
11313 assert(consdata != NULL);
11314
11315 nvars = consdata->nvars;
11316
11317 /* check whether the cliques have already been added */
11318 if( consdata->cliquesadded || nvars == 0 )
11319 return SCIP_OKAY;
11320
11321 /* make sure, the items are merged */
11322 SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
11323 if( *cutoff )
11324 return SCIP_OKAY;
11325
11326 /* make sure, the items are sorted by non-increasing weight */
11327 sortItems(consdata);
11328
11329 assert(consdata->merged);
11330
11331 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11332 assert(conshdlrdata != NULL);
11333
11334 /* calculate a clique partition */
11335 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
11336 nnegcliques = consdata->nnegcliques;
11337 assert(nnegcliques <= nvars);
11338
11339 /* get temporary memory */
11340 SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
11341 SCIP_CALL( SCIPallocBufferArray(scip, &gainweights, nvars) );
11342 BMSclearMemoryArray(gainweights, nvars);
11343 SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
11344 BMSclearMemoryArray(secondmaxweights, nnegcliques);
11345
11346 minactduetonegcliques = 0;
11347
11348 /* calculate minimal activity due to negated cliques, and determine second maximal weight in each clique */
11349 if( nnegcliques < nvars )
11350 {
11351 nnegcliques = 0;
11352
11353 for( i = 0; i < nvars; ++i )
11354 {
11355 SCIP_Longint weight;
11356
11357 cliquenum = consdata->negcliquepartition[i];
11358 assert(0 <= cliquenum && cliquenum <= nnegcliques);
11359
11360 weight = consdata->weights[i];
11361 assert(weight > 0);
11362
11363 if( cliquenum == nnegcliques )
11364 nnegcliques++;
11365 else
11366 {
11367 minactduetonegcliques += weight;
11368 if( secondmaxweights[cliquenum] == 0 )
11369 secondmaxweights[cliquenum] = weight;
11370 }
11371 }
11372 }
11373
11374 /* add cliques, using negated cliques information */
11375 if( minactduetonegcliques > 0 )
11376 {
11377 /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11378 freecapacity = consdata->capacity - minactduetonegcliques;
11379
11381 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",
11382 SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11383
11384 /* create negated cliques out of negated cliques, if we do not take the smallest weight of a cliques ... */
11385 SCIP_CALL( addNegatedCliques(scip, cons, cutoff, nbdchgs ) );
11386
11387 if( *cutoff )
11388 goto TERMINATE;
11389
11390 nposcliquevars = 0;
11391
11392 for( i = nvars - 1; i >= 0; --i )
11393 {
11394 /* if we would take the biggest weight instead of the second biggest */
11395 cliquenum = consdata->negcliquepartition[i];
11396 if( consdata->weights[i] > secondmaxweights[cliquenum] )
11397 {
11398 poscliquevars[nposcliquevars] = consdata->vars[i];
11399 gainweights[nposcliquevars] = consdata->weights[i] - secondmaxweights[cliquenum];
11400 ++nposcliquevars;
11401 }
11402 }
11403
11404 /* use the gain weights and free capacity to derive greedily cliques */
11405 if( nposcliquevars > 1 )
11406 {
11407 SCIP_CALL( greedyCliqueAlgorithm(scip, poscliquevars, gainweights, nposcliquevars, freecapacity, FALSE, cliqueextractfactor, cutoff, nbdchgs) );
11408
11409 if( *cutoff )
11410 goto TERMINATE;
11411 }
11412 }
11413
11414 /* build cliques by using the items with the maximal weights */
11415 SCIP_CALL( greedyCliqueAlgorithm(scip, consdata->vars, consdata->weights, nvars, consdata->capacity, TRUE, cliqueextractfactor, cutoff, nbdchgs) );
11416
11417 TERMINATE:
11418 /* free temporary memory and mark the constraint */
11419 SCIPfreeBufferArray(scip, &secondmaxweights);
11420 SCIPfreeBufferArray(scip, &gainweights);
11421 SCIPfreeBufferArray(scip, &poscliquevars);
11422 consdata->cliquesadded = TRUE;
11423
11424 return SCIP_OKAY;
11425}
11426
11427
11428/** gets the key of the given element */
11429static
11430SCIP_DECL_HASHGETKEY(hashGetKeyKnapsackcons)
11431{ /*lint --e{715}*/
11432 /* the key is the element itself */
11433 return elem;
11434}
11435
11436/** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables and the
11437 * same coefficients
11438 */
11439static
11440SCIP_DECL_HASHKEYEQ(hashKeyEqKnapsackcons)
11441{
11442#ifndef NDEBUG
11443 SCIP* scip;
11444#endif
11445 SCIP_CONSDATA* consdata1;
11446 SCIP_CONSDATA* consdata2;
11447 int i;
11448
11449 consdata1 = SCIPconsGetData((SCIP_CONS*)key1);
11450 consdata2 = SCIPconsGetData((SCIP_CONS*)key2);
11451 assert(consdata1->sorted);
11452 assert(consdata2->sorted);
11453#ifndef NDEBUG
11454 scip = (SCIP*)userptr;
11455 assert(scip != NULL);
11456#endif
11457
11458 /* checks trivial case */
11459 if( consdata1->nvars != consdata2->nvars )
11460 return FALSE;
11461
11462 for( i = consdata1->nvars - 1; i >= 0; --i )
11463 {
11464 /* tests if variables are equal */
11465 if( consdata1->vars[i] != consdata2->vars[i] )
11466 {
11467 assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 ||
11468 SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1);
11469 return FALSE;
11470 }
11471 assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 0);
11472
11473 /* tests if weights are equal too */
11474 if( consdata1->weights[i] != consdata2->weights[i] )
11475 return FALSE;
11476 }
11477
11478 return TRUE;
11479}
11480
11481/** returns the hash value of the key */
11482static
11483SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)
11484{
11485#ifndef NDEBUG
11486 SCIP* scip;
11487#endif
11488 SCIP_CONSDATA* consdata;
11489 uint64_t firstweight;
11490 int minidx;
11491 int mididx;
11492 int maxidx;
11493
11494 consdata = SCIPconsGetData((SCIP_CONS*)key);
11495 assert(consdata != NULL);
11496 assert(consdata->nvars > 0);
11497
11498#ifndef NDEBUG
11499 scip = (SCIP*)userptr;
11500 assert(scip != NULL);
11501#endif
11502
11503 /* sorts the constraints */
11504 sortItems(consdata);
11505
11506 minidx = SCIPvarGetIndex(consdata->vars[0]);
11507 mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]);
11508 maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]);
11509 assert(minidx >= 0 && mididx >= 0 && maxidx >= 0);
11510
11511 /* hash value depends on vectors of variable indices */
11512 firstweight = (uint64_t)consdata->weights[0];
11513 return SCIPhashSix(consdata->nvars, minidx, mididx, maxidx, firstweight>>32, firstweight);
11514}
11515
11516/** compares each constraint with all other constraints for possible redundancy and removes or changes constraint
11517 * accordingly; in contrast to preprocessConstraintPairs(), it uses a hash table
11518 */
11519static
11521 SCIP* scip, /**< SCIP data structure */
11522 BMS_BLKMEM* blkmem, /**< block memory */
11523 SCIP_CONS** conss, /**< constraint set */
11524 int nconss, /**< number of constraints in constraint set */
11525 SCIP_Bool* cutoff, /**< pointer to store whether the problem is infeasible */
11526 int* ndelconss /**< pointer to count number of deleted constraints */
11527 )
11528{
11529 SCIP_HASHTABLE* hashtable;
11530 int hashtablesize;
11531 int c;
11532
11533 assert(scip != NULL);
11534 assert(blkmem != NULL);
11535 assert(conss != NULL);
11536 assert(ndelconss != NULL);
11537
11538 /* create a hash table for the constraint set */
11539 hashtablesize = nconss;
11540 hashtablesize = MAX(hashtablesize, HASHSIZE_KNAPSACKCONS);
11541 SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize,
11542 hashGetKeyKnapsackcons, hashKeyEqKnapsackcons, hashKeyValKnapsackcons, (void*) scip) );
11543
11544 /* check all constraints in the given set for redundancy */
11545 for( c = nconss - 1; c >= 0; --c )
11546 {
11547 SCIP_CONS* cons0;
11548 SCIP_CONS* cons1;
11549 SCIP_CONSDATA* consdata0;
11550
11551 cons0 = conss[c];
11552
11553 if( !SCIPconsIsActive(cons0) || SCIPconsIsModifiable(cons0) )
11554 continue;
11555
11556 consdata0 = SCIPconsGetData(cons0);
11557 assert(consdata0 != NULL);
11558 if( consdata0->nvars == 0 )
11559 {
11560 if( consdata0->capacity < 0 )
11561 {
11562 *cutoff = TRUE;
11563 goto TERMINATE;
11564 }
11565 else
11566 {
11567 SCIP_CALL( SCIPdelCons(scip, cons0) );
11568 ++(*ndelconss);
11569 continue;
11570 }
11571 }
11572
11573 /* get constraint from current hash table with same variables and same weights as cons0 */
11574 cons1 = (SCIP_CONS*)(SCIPhashtableRetrieve(hashtable, (void*)cons0));
11575
11576 if( cons1 != NULL )
11577 {
11578 SCIP_CONS* consstay;
11579 SCIP_CONS* consdel;
11580 SCIP_CONSDATA* consdata1;
11581
11582 assert(SCIPconsIsActive(cons1));
11583 assert(!SCIPconsIsModifiable(cons1));
11584
11585 /* constraint found: create a new constraint with same coefficients and best left and right hand side;
11586 * delete old constraints afterwards
11587 */
11588 consdata1 = SCIPconsGetData(cons1);
11589
11590 assert(consdata1 != NULL);
11591 assert(consdata0->nvars > 0 && consdata0->nvars == consdata1->nvars);
11592
11593 assert(consdata0->sorted && consdata1->sorted);
11594 assert(consdata0->vars[0] == consdata1->vars[0]);
11595 assert(consdata0->weights[0] == consdata1->weights[0]);
11596
11597 SCIPdebugMsg(scip, "knapsack constraints <%s> and <%s> with equal coefficients\n",
11598 SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11599
11600 /* check which constraint has to stay; */
11601 if( consdata0->capacity < consdata1->capacity )
11602 {
11603 consstay = cons0;
11604 consdel = cons1;
11605
11606 /* exchange consdel with consstay in hashtable */
11607 SCIP_CALL( SCIPhashtableRemove(hashtable, (void*) consdel) );
11608 SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) consstay) );
11609 }
11610 else
11611 {
11612 consstay = cons1;
11613 consdel = cons0;
11614 }
11615
11616 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11617 SCIP_CALL( SCIPupdateConsFlags(scip, consstay, consdel) );
11618
11619 /* delete consdel */
11620 SCIP_CALL( SCIPdelCons(scip, consdel) );
11621 ++(*ndelconss);
11622
11623 assert(SCIPconsIsActive(consstay));
11624 }
11625 else
11626 {
11627 /* no such constraint in current hash table: insert cons0 into hash table */
11628 SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) cons0) );
11629 }
11630 }
11631
11632 TERMINATE:
11633 /* free hash table */
11634 SCIPhashtableFree(&hashtable);
11635
11636 return SCIP_OKAY;
11637}
11638
11639
11640/** compares constraint with all prior constraints for possible redundancy or aggregation,
11641 * and removes or changes constraint accordingly
11642 */
11643static
11645 SCIP* scip, /**< SCIP data structure */
11646 SCIP_CONS** conss, /**< constraint set */
11647 int firstchange, /**< first constraint that changed since last pair preprocessing round */
11648 int chkind, /**< index of constraint to check against all prior indices upto startind */
11649 int* ndelconss /**< pointer to count number of deleted constraints */
11650 )
11651{
11652 SCIP_CONS* cons0;
11653 SCIP_CONSDATA* consdata0;
11654 int c;
11655
11656 assert(scip != NULL);
11657 assert(conss != NULL);
11658 assert(firstchange <= chkind);
11659 assert(ndelconss != NULL);
11660
11661 /* get the constraint to be checked against all prior constraints */
11662 cons0 = conss[chkind];
11663 assert(cons0 != NULL);
11664 assert(SCIPconsIsActive(cons0));
11665 assert(!SCIPconsIsModifiable(cons0));
11666
11667 consdata0 = SCIPconsGetData(cons0);
11668 assert(consdata0 != NULL);
11669 assert(consdata0->nvars >= 1);
11670 assert(consdata0->merged);
11671
11672 /* sort the constraint */
11673 sortItems(consdata0);
11674
11675 /* see #2970 */
11676 if( consdata0->capacity == 0 )
11677 return SCIP_OKAY;
11678
11679 /* check constraint against all prior constraints */
11680 for( c = (consdata0->presolvedtiming == SCIP_PRESOLTIMING_EXHAUSTIVE ? firstchange : 0); c < chkind; ++c )
11681 {
11682 SCIP_CONS* cons1;
11683 SCIP_CONSDATA* consdata1;
11684 SCIP_Bool iscons0incons1contained;
11685 SCIP_Bool iscons1incons0contained;
11686 SCIP_Real quotient;
11687 int v;
11688 int v0;
11689 int v1;
11690
11691 cons1 = conss[c];
11692 assert(cons1 != NULL);
11693 if( !SCIPconsIsActive(cons1) || SCIPconsIsModifiable(cons1) )
11694 continue;
11695
11696 consdata1 = SCIPconsGetData(cons1);
11697 assert(consdata1 != NULL);
11698
11699 /* if both constraints didn't change since last pair processing, we can ignore the pair */
11700 if( consdata0->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE && consdata1->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE ) /*lint !e574*/
11701 continue;
11702
11703 assert(consdata1->nvars >= 1);
11704 assert(consdata1->merged);
11705
11706 /* sort the constraint */
11707 sortItems(consdata1);
11708
11709 /* see #2970 */
11710 if( consdata1->capacity == 0 )
11711 continue;
11712
11713 quotient = ((SCIP_Real) consdata0->capacity) / ((SCIP_Real) consdata1->capacity);
11714
11715 if( consdata0->nvars > consdata1->nvars )
11716 {
11717 iscons0incons1contained = FALSE;
11718 iscons1incons0contained = TRUE;
11719 v = consdata1->nvars - 1;
11720 }
11721 else if( consdata0->nvars < consdata1->nvars )
11722 {
11723 iscons0incons1contained = TRUE;
11724 iscons1incons0contained = FALSE;
11725 v = consdata0->nvars - 1;
11726 }
11727 else
11728 {
11729 iscons0incons1contained = TRUE;
11730 iscons1incons0contained = TRUE;
11731 v = consdata0->nvars - 1;
11732 }
11733
11734 SCIPdebugMsg(scip, "preprocess knapsack constraint pair <%s> and <%s>\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11735
11736 /* check consdata0 against consdata1:
11737 * 1. if all variables var_i of cons1 are in cons0 and for each of these variables
11738 * (consdata0->weights[i] / quotient) >= consdata1->weights[i] cons1 is redundant
11739 * 2. if all variables var_i of cons0 are in cons1 and for each of these variables
11740 * (consdata0->weights[i] / quotient) <= consdata1->weights[i] cons0 is redundant
11741 */
11742 v0 = consdata0->nvars - 1;
11743 v1 = consdata1->nvars - 1;
11744
11745 while( v >= 0 )
11746 {
11747 assert(iscons0incons1contained || iscons1incons0contained);
11748
11749 /* now there are more variables in cons1 left */
11750 if( v1 > v0 )
11751 {
11752 iscons1incons0contained = FALSE;
11753 if( !iscons0incons1contained )
11754 break;
11755 }
11756 /* now there are more variables in cons0 left */
11757 else if( v1 < v0 )
11758 {
11759 iscons0incons1contained = FALSE;
11760 if( !iscons1incons0contained )
11761 break;
11762 }
11763
11764 assert(v == v0 || v == v1);
11765 assert(v0 >= 0);
11766 assert(v1 >= 0);
11767
11768 /* both variables are the same */
11769 if( consdata0->vars[v0] == consdata1->vars[v1] )
11770 {
11771 /* if cons1 is possible contained in cons0 (consdata0->weights[v0] / quotient) must be greater equals consdata1->weights[v1] */
11772 if( iscons1incons0contained && SCIPisLT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11773 {
11774 iscons1incons0contained = FALSE;
11775 if( !iscons0incons1contained )
11776 break;
11777 }
11778 /* if cons0 is possible contained in cons1 (consdata0->weight[v0] / quotient) must be less equals consdata1->weight[v1] */
11779 else if( iscons0incons1contained && SCIPisGT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11780 {
11781 iscons0incons1contained = FALSE;
11782 if( !iscons1incons0contained )
11783 break;
11784 }
11785 --v0;
11786 --v1;
11787 --v;
11788 }
11789 else
11790 {
11791 /* both constraints have a variables which is not part of the other constraint, so stop */
11792 if( iscons0incons1contained && iscons1incons0contained )
11793 {
11794 iscons0incons1contained = FALSE;
11795 iscons1incons0contained = FALSE;
11796 break;
11797 }
11798 assert(iscons0incons1contained ? (v1 >= v0) : iscons1incons0contained);
11799 assert(iscons1incons0contained ? (v1 <= v0) : iscons0incons1contained);
11800 /* continue to the next variable */
11801 if( iscons0incons1contained )
11802 --v1;
11803 else
11804 --v0;
11805 }
11806 }
11807 /* neither one constraint was contained in another or we checked all variables of one constraint against the
11808 * other
11809 */
11810 assert(!iscons1incons0contained || !iscons0incons1contained || v0 == -1 || v1 == -1);
11811
11812 if( iscons1incons0contained )
11813 {
11814 SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons1));
11815 SCIPdebugPrintCons(scip, cons1, NULL);
11816
11817 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11818 SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
11819
11820 SCIP_CALL( SCIPdelCons(scip, cons1) );
11821 ++(*ndelconss);
11822 }
11823 else if( iscons0incons1contained )
11824 {
11825 SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons0));
11826 SCIPdebugPrintCons(scip, cons0, NULL);
11827
11828 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11829 SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
11830
11831 SCIP_CALL( SCIPdelCons(scip, cons0) );
11832 ++(*ndelconss);
11833 break;
11834 }
11835 }
11836
11837 return SCIP_OKAY;
11838}
11839
11840/** helper function to enforce constraints */
11841static
11843 SCIP* scip, /**< SCIP data structure */
11844 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11845 SCIP_CONS** conss, /**< constraints to process */
11846 int nconss, /**< number of constraints */
11847 int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
11848 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
11849 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
11850 )
11851{
11852 SCIP_CONSHDLRDATA* conshdlrdata;
11853 SCIP_Bool violated;
11854 SCIP_Bool cutoff = FALSE;
11855 int maxncuts;
11856 int ncuts = 0;
11857 int i;
11858
11859 *result = SCIP_FEASIBLE;
11860
11861 SCIPdebugMsg(scip, "knapsack enforcement of %d/%d constraints for %s solution\n", nusefulconss, nconss,
11862 sol == NULL ? "LP" : "relaxation");
11863
11864 /* get maximal number of cuts per round */
11865 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11866 assert(conshdlrdata != NULL);
11867 maxncuts = (SCIPgetDepth(scip) == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
11868
11869 /* search for violated useful knapsack constraints */
11870 for( i = 0; i < nusefulconss && ncuts < maxncuts && ! cutoff; i++ )
11871 {
11872 SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11873 if( violated )
11874 {
11875 /* add knapsack constraint as LP row to the relaxation */
11876 SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11877 ncuts++;
11878 }
11879 }
11880
11881 /* as long as no violations were found, search for violated obsolete knapsack constraints */
11882 for( i = nusefulconss; i < nconss && ncuts == 0 && ! cutoff; i++ )
11883 {
11884 SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11885 if( violated )
11886 {
11887 /* add knapsack constraint as LP row to the relaxation */
11888 SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11889 ncuts++;
11890 }
11891 }
11892
11893 /* adjust the result code */
11894 if ( cutoff )
11895 *result = SCIP_CUTOFF;
11896 else if ( ncuts > 0 )
11897 *result = SCIP_SEPARATED;
11898
11899 return SCIP_OKAY;
11900}
11901
11902/*
11903 * Linear constraint upgrading
11904 */
11905
11906/** creates and captures a knapsack constraint out of a linear inequality */
11907static
11909 SCIP* scip, /**< SCIP data structure */
11910 SCIP_CONS** cons, /**< pointer to hold the created constraint */
11911 const char* name, /**< name of constraint */
11912 int nvars, /**< number of variables in the constraint */
11913 SCIP_VAR** vars, /**< array with variables of constraint entries */
11914 SCIP_Real* vals, /**< array with inequality coefficients */
11915 SCIP_Real lhs, /**< left hand side of inequality */
11916 SCIP_Real rhs, /**< right hand side of inequality */
11917 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11918 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11919 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11920 * Usually set to TRUE. */
11921 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11922 * TRUE for model constraints, FALSE for additional, redundant constraints. */
11923 SCIP_Bool check, /**< should the constraint be checked for feasibility?
11924 * TRUE for model constraints, FALSE for additional, redundant constraints. */
11925 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11926 * Usually set to TRUE. */
11927 SCIP_Bool local, /**< is constraint only valid locally?
11928 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11929 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11930 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11931 * adds coefficients to this constraint. */
11932 SCIP_Bool dynamic, /**< is constraint subject to aging?
11933 * Usually set to FALSE. Set to TRUE for own cuts which
11934 * are separated as constraints. */
11935 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
11936 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11937 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
11938 * if it may be moved to a more global node?
11939 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
11940 )
11941{
11942 SCIP_VAR** transvars;
11943 SCIP_Longint* weights;
11944 SCIP_Longint capacity;
11945 SCIP_Longint weight;
11946 int mult;
11947 int v;
11948
11949 assert(nvars == 0 || vars != NULL);
11950 assert(nvars == 0 || vals != NULL);
11951 assert(SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11952
11953 /* get temporary memory */
11954 SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );
11956
11957 /* if the right hand side is non-infinite, we have to negate all variables with negative coefficient;
11958 * otherwise, we have to negate all variables with positive coefficient and multiply the row with -1
11959 */
11960 if( SCIPisInfinity(scip, rhs) )
11961 {
11962 mult = -1;
11963 capacity = (SCIP_Longint)SCIPfeasFloor(scip, -lhs);
11964 }
11965 else
11966 {
11967 mult = +1;
11968 capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
11969 }
11970
11971 /* negate positive or negative variables */
11972 for( v = 0; v < nvars; ++v )
11973 {
11974 assert(SCIPisFeasIntegral(scip, vals[v]));
11975 weight = mult * (SCIP_Longint)SCIPfeasFloor(scip, vals[v]);
11976 if( weight > 0 )
11977 {
11978 transvars[v] = vars[v];
11979 weights[v] = weight;
11980 }
11981 else
11982 {
11983 SCIP_CALL( SCIPgetNegatedVar(scip, vars[v], &transvars[v]) );
11984 weights[v] = -weight; /*lint !e2704*/
11985 capacity -= weight;
11986 }
11987 assert(transvars[v] != NULL);
11988 }
11989
11990 /* create the constraint */
11991 SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, transvars, weights, capacity,
11992 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
11993
11994 /* free temporary memory */
11995 SCIPfreeBufferArray(scip, &weights);
11996 SCIPfreeBufferArray(scip, &transvars);
11997
11998 return SCIP_OKAY;
11999}
12000
12001/** tries to upgrade a linear constraint into a knapsack constraint */
12002static
12003SCIP_DECL_LINCONSUPGD(linconsUpgdKnapsack)
12004{ /*lint --e{715}*/
12005 SCIP_Bool upgrade;
12006
12007 assert(upgdcons != NULL);
12008
12009 /* check, if linear constraint can be upgraded to a knapsack constraint
12010 * - all variables must be binary
12011 * - all coefficients must be integral
12012 * - exactly one of the sides must be infinite
12013 * note that this includes the case of negative capacity, which has been
12014 * observed to occur, e.g., when upgrading a conflict constraint
12015 */
12016 upgrade = (nposbin + nnegbin + nposimplbin + nnegimplbin == nvars)
12017 && (ncoeffspone + ncoeffsnone + ncoeffspint + ncoeffsnint == nvars)
12018 && (SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
12019
12020 if( upgrade )
12021 {
12022 SCIPdebugMsg(scip, "upgrading constraint <%s> to knapsack constraint\n", SCIPconsGetName(cons));
12023
12024 /* create the knapsack constraint (an automatically upgraded constraint is always unmodifiable) */
12025 assert(!SCIPconsIsModifiable(cons));
12026 SCIP_CALL( createNormalizedKnapsack(scip, upgdcons, SCIPconsGetName(cons), nvars, vars, vals, lhs, rhs,
12031 }
12032
12033 return SCIP_OKAY;
12034}
12035
12036/** adds symmetry information of constraint to a symmetry detection graph */
12037static
12039 SCIP* scip, /**< SCIP pointer */
12040 SYM_SYMTYPE symtype, /**< type of symmetries that need to be added */
12041 SCIP_CONS* cons, /**< constraint */
12042 SYM_GRAPH* graph, /**< symmetry detection graph */
12043 SCIP_Bool* success /**< pointer to store whether symmetry information could be added */
12044 )
12045{
12046 SCIP_CONSDATA* consdata;
12047 SCIP_VAR** vars;
12048 SCIP_Real* vals;
12049 SCIP_Real constant = 0.0;
12050 SCIP_Real rhs;
12051 int nlocvars;
12052 int nvars;
12053 int i;
12054
12055 assert(scip != NULL);
12056 assert(cons != NULL);
12057 assert(graph != NULL);
12058 assert(success != NULL);
12059
12060 consdata = SCIPconsGetData(cons);
12061 assert(consdata != NULL);
12062 assert(graph != NULL);
12063
12064 /* get active variables of the constraint */
12066 nlocvars = consdata->nvars;
12067
12070
12071 for( i = 0; i < consdata->nvars; ++i )
12072 {
12073 vars[i] = consdata->vars[i];
12074 vals[i] = (SCIP_Real) consdata->weights[i];
12075 }
12076
12077 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &vars, &vals, &nlocvars, &constant, SCIPisTransformed(scip)) );
12078 rhs = (SCIP_Real) SCIPgetCapacityKnapsack(scip, cons) - constant;
12079
12080 SCIP_CALL( SCIPextendPermsymDetectionGraphLinear(scip, graph, vars, vals, nlocvars,
12081 cons, -SCIPinfinity(scip), rhs, success) );
12082
12083 SCIPfreeBufferArray(scip, &vals);
12084 SCIPfreeBufferArray(scip, &vars);
12085
12086 return SCIP_OKAY;
12087}
12088
12089/*
12090 * Callback methods of constraint handler
12091 */
12092
12093/** copy method for constraint handler plugins (called when SCIP copies plugins) */
12094/**! [SnippetConsCopyKnapsack] */
12095static
12096SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack)
12097{ /*lint --e{715}*/
12098 assert(scip != NULL);
12099 assert(conshdlr != NULL);
12100 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12101
12102 /* call inclusion method of constraint handler */
12104
12105 *valid = TRUE;
12106
12107 return SCIP_OKAY;
12108}
12109/**! [SnippetConsCopyKnapsack] */
12110
12111/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12112/**! [SnippetConsFreeKnapsack] */
12113static
12114SCIP_DECL_CONSFREE(consFreeKnapsack)
12115{ /*lint --e{715}*/
12116 SCIP_CONSHDLRDATA* conshdlrdata;
12117
12118 /* free constraint handler data */
12119 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12120 assert(conshdlrdata != NULL);
12121
12122 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->probtoidxmap, conshdlrdata->probtoidxmapsize);
12123 SCIPfreeBlockMemory(scip, &conshdlrdata);
12124
12125 SCIPconshdlrSetData(conshdlr, NULL);
12126
12127 return SCIP_OKAY;
12128}
12129/**! [SnippetConsFreeKnapsack] */
12130
12131
12132/** initialization method of constraint handler (called after problem was transformed) */
12133static
12134SCIP_DECL_CONSINIT(consInitKnapsack)
12135{ /*lint --e{715}*/
12136 SCIP_CONSHDLRDATA* conshdlrdata;
12137 int nvars;
12138
12139 assert( scip != NULL );
12140 assert( conshdlr != NULL );
12141
12142 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12143 assert(conshdlrdata != NULL);
12144
12145 /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12147
12148 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->reals1, nvars) );
12149 conshdlrdata->reals1size = nvars;
12150
12151 return SCIP_OKAY;
12152}
12153
12154/** deinitialization method of constraint handler (called before transformed problem is freed) */
12155static
12156SCIP_DECL_CONSEXIT(consExitKnapsack)
12157{ /*lint --e{715}*/
12158 SCIP_CONSHDLRDATA* conshdlrdata;
12159
12160 assert( scip != NULL );
12161 assert( conshdlr != NULL );
12162
12163 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12164 assert(conshdlrdata != NULL);
12165
12166 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->reals1, conshdlrdata->reals1size);
12167 conshdlrdata->reals1size = 0;
12168
12169 return SCIP_OKAY;
12170}
12171
12172
12173/** presolving initialization method of constraint handler (called when presolving is about to begin) */
12174static
12175SCIP_DECL_CONSINITPRE(consInitpreKnapsack)
12176{ /*lint --e{715}*/
12177 SCIP_CONSHDLRDATA* conshdlrdata;
12178 int nvars;
12179
12180 assert(scip != NULL);
12181 assert(conshdlr != NULL);
12182 assert(nconss == 0 || conss != NULL);
12183
12184 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12185 assert(conshdlrdata != NULL);
12186
12187 /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12189
12190 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints1, nvars) );
12191 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints2, nvars) );
12192 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints1, nvars) );
12193 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints2, nvars) );
12194 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools1, nvars) );
12195 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools2, nvars) );
12196 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools3, nvars) );
12197 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools4, nvars) );
12198
12199 conshdlrdata->ints1size = nvars;
12200 conshdlrdata->ints2size = nvars;
12201 conshdlrdata->longints1size = nvars;
12202 conshdlrdata->longints2size = nvars;
12203 conshdlrdata->bools1size = nvars;
12204 conshdlrdata->bools2size = nvars;
12205 conshdlrdata->bools3size = nvars;
12206 conshdlrdata->bools4size = nvars;
12207
12208#ifdef WITH_CARDINALITY_UPGRADE
12209 conshdlrdata->upgradedcard = FALSE;
12210#endif
12211
12212 return SCIP_OKAY;
12213}
12214
12215
12216/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12217static
12218SCIP_DECL_CONSEXITPRE(consExitpreKnapsack)
12219{ /*lint --e{715}*/
12220 SCIP_CONSHDLRDATA* conshdlrdata;
12221 int c;
12222
12223 assert(scip != NULL);
12224 assert(conshdlr != NULL);
12225
12226 for( c = 0; c < nconss; ++c )
12227 {
12228 if( !SCIPconsIsDeleted(conss[c]) )
12229 {
12230 /* since we are not allowed to detect infeasibility in the exitpre stage, we dont give an infeasible pointer */
12231 SCIP_CALL( applyFixings(scip, conss[c], NULL) );
12232 }
12233 }
12234
12235 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12236 assert(conshdlrdata != NULL);
12237
12238 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints1, conshdlrdata->ints1size);
12239 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints2, conshdlrdata->ints2size);
12240 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints1, conshdlrdata->longints1size);
12241 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints2, conshdlrdata->longints2size);
12242 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools1, conshdlrdata->bools1size);
12243 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools2, conshdlrdata->bools2size);
12244 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools3, conshdlrdata->bools3size);
12245 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools4, conshdlrdata->bools4size);
12246
12247 conshdlrdata->ints1size = 0;
12248 conshdlrdata->ints2size = 0;
12249 conshdlrdata->longints1size = 0;
12250 conshdlrdata->longints2size = 0;
12251 conshdlrdata->bools1size = 0;
12252 conshdlrdata->bools2size = 0;
12253 conshdlrdata->bools3size = 0;
12254 conshdlrdata->bools4size = 0;
12255
12256 return SCIP_OKAY;
12257}
12258
12259/** solving process initialization method of constraint handler */
12260static
12261SCIP_DECL_CONSINITSOL(consInitsolKnapsack)
12262{ /*lint --e{715}*/
12263 /* add nlrow representation to NLP, if NLP had been constructed */
12265 {
12266 int c;
12267 for( c = 0; c < nconss; ++c )
12268 {
12269 SCIP_CALL( addNlrow(scip, conss[c]) );
12270 }
12271 }
12272
12273 return SCIP_OKAY;
12274}
12275
12276/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12277static
12278SCIP_DECL_CONSEXITSOL(consExitsolKnapsack)
12279{ /*lint --e{715}*/
12280 SCIP_CONSDATA* consdata;
12281 int c;
12282
12283 assert( scip != NULL );
12284
12285 /* release the rows and nlrows of all constraints */
12286 for( c = 0; c < nconss; ++c )
12287 {
12288 consdata = SCIPconsGetData(conss[c]);
12289 assert(consdata != NULL);
12290
12291 if( consdata->row != NULL )
12292 {
12293 SCIP_CALL( SCIPreleaseRow(scip, &consdata->row) );
12294 }
12295
12296 if( consdata->nlrow != NULL )
12297 {
12298 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
12299 }
12300 }
12301
12302 return SCIP_OKAY;
12303}
12304
12305/** frees specific constraint data */
12306static
12307SCIP_DECL_CONSDELETE(consDeleteKnapsack)
12308{ /*lint --e{715}*/
12309 SCIP_CONSHDLRDATA* conshdlrdata;
12310
12311 assert(conshdlr != NULL);
12312 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12313
12314 /* get event handler */
12315 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12316 assert(conshdlrdata != NULL);
12317 assert(conshdlrdata->eventhdlr != NULL);
12318
12319 /* free knapsack constraint */
12320 SCIP_CALL( consdataFree(scip, consdata, conshdlrdata->eventhdlr) );
12321
12322 return SCIP_OKAY;
12323}
12324
12325/** transforms constraint data into data belonging to the transformed problem */
12326/**! [SnippetConsTransKnapsack]*/
12327static
12328SCIP_DECL_CONSTRANS(consTransKnapsack)
12329{ /*lint --e{715}*/
12330 SCIP_CONSHDLRDATA* conshdlrdata;
12331 SCIP_CONSDATA* sourcedata;
12332 SCIP_CONSDATA* targetdata;
12333
12334 assert(conshdlr != NULL);
12335 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12337 assert(sourcecons != NULL);
12338 assert(targetcons != NULL);
12339
12340 sourcedata = SCIPconsGetData(sourcecons);
12341 assert(sourcedata != NULL);
12342 assert(sourcedata->row == NULL); /* in original problem, there cannot be LP rows */
12343
12344 /* get event handler */
12345 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12346 assert(conshdlrdata != NULL);
12347 assert(conshdlrdata->eventhdlr != NULL);
12348
12349 /* create target constraint data */
12350 SCIP_CALL( consdataCreate(scip, &targetdata,
12351 sourcedata->nvars, sourcedata->vars, sourcedata->weights, sourcedata->capacity) );
12352
12353 /* create target constraint */
12354 SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12355 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12356 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12357 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12358 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12359
12360 /* catch events for variables */
12361 SCIP_CALL( catchEvents(scip, *targetcons, targetdata, conshdlrdata->eventhdlr) );
12362
12363 return SCIP_OKAY;
12364}
12365/**! [SnippetConsTransKnapsack]*/
12366
12367/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
12368static
12369SCIP_DECL_CONSINITLP(consInitlpKnapsack)
12370{ /*lint --e{715}*/
12371 int i;
12372
12373 *infeasible = FALSE;
12374
12375 for( i = 0; i < nconss && !(*infeasible); i++ )
12376 {
12377 assert(SCIPconsIsInitial(conss[i]));
12378 SCIP_CALL( addRelaxation(scip, conss[i], infeasible) );
12379 }
12380
12381 return SCIP_OKAY;
12382}
12383
12384/** separation method of constraint handler for LP solutions */
12385static
12386SCIP_DECL_CONSSEPALP(consSepalpKnapsack)
12387{ /*lint --e{715}*/
12388 SCIP_CONSHDLRDATA* conshdlrdata;
12389 SCIP_Bool sepacardinality;
12390 SCIP_Bool cutoff;
12391
12392 SCIP_Real loclowerbound;
12393 SCIP_Real glblowerbound;
12394 SCIP_Real cutoffbound;
12395 SCIP_Real maxbound;
12396
12397 int depth;
12398 int nrounds;
12399 int sepafreq;
12400 int sepacardfreq;
12401 int ncuts;
12402 int maxsepacuts;
12403 int i;
12404
12405 *result = SCIP_DIDNOTRUN;
12406
12407 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12408 assert(conshdlrdata != NULL);
12409
12410 depth = SCIPgetDepth(scip);
12411 nrounds = SCIPgetNSepaRounds(scip);
12412
12413 SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12414 nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12415
12416 /* only call the separator a given number of times at each node */
12417 if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12418 || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12419 return SCIP_OKAY;
12420
12421 /* check, if we should additionally separate knapsack cuts */
12422 sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12423 sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12424 sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12425 && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12426
12427 /* check dual bound to see if we want to produce knapsack cuts at this node */
12428 loclowerbound = SCIPgetLocalLowerbound(scip);
12429 glblowerbound = SCIPgetLowerbound(scip);
12430 cutoffbound = SCIPgetCutoffbound(scip);
12431 maxbound = glblowerbound + conshdlrdata->maxcardbounddist * (cutoffbound - glblowerbound);
12432 sepacardinality = sepacardinality && SCIPisLE(scip, loclowerbound, maxbound);
12433 sepacardinality = sepacardinality && (SCIPgetNLPBranchCands(scip) > 0);
12434
12435 /* get the maximal number of cuts allowed in a separation round */
12436 maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12437
12438 *result = SCIP_DIDNOTFIND;
12439 ncuts = 0;
12440 cutoff = FALSE;
12441
12442 /* separate useful constraints */
12443 for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12444 {
12445 SCIP_CALL( separateCons(scip, conss[i], NULL, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12446 }
12447
12448 /* adjust return value */
12449 if ( cutoff )
12450 *result = SCIP_CUTOFF;
12451 else if ( ncuts > 0 )
12452 *result = SCIP_SEPARATED;
12453
12454 return SCIP_OKAY;
12455}
12456
12457
12458/** separation method of constraint handler for arbitrary primal solutions */
12459static
12460SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
12461{ /*lint --e{715}*/
12462 SCIP_CONSHDLRDATA* conshdlrdata;
12463 SCIP_Bool sepacardinality;
12464 SCIP_Bool cutoff;
12465
12466 int depth;
12467 int nrounds;
12468 int sepafreq;
12469 int sepacardfreq;
12470 int ncuts;
12471 int maxsepacuts;
12472 int i;
12473
12474 *result = SCIP_DIDNOTRUN;
12475
12476 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12477 assert(conshdlrdata != NULL);
12478
12479 depth = SCIPgetDepth(scip);
12480 nrounds = SCIPgetNSepaRounds(scip);
12481
12482 SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12483 nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12484
12485 /* only call the separator a given number of times at each node */
12486 if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12487 || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12488 return SCIP_OKAY;
12489
12490 /* check, if we should additionally separate knapsack cuts */
12491 sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12492 sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12493 sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12494 && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12495
12496 /* get the maximal number of cuts allowed in a separation round */
12497 maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12498
12499 *result = SCIP_DIDNOTFIND;
12500 ncuts = 0;
12501 cutoff = FALSE;
12502
12503 /* separate useful constraints */
12504 for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12505 {
12506 SCIP_CALL( separateCons(scip, conss[i], sol, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12507 }
12508
12509 /* adjust return value */
12510 if ( cutoff )
12511 *result = SCIP_CUTOFF;
12512 else if( ncuts > 0 )
12513 *result = SCIP_SEPARATED;
12514
12515 return SCIP_OKAY;
12516}
12517
12518/** constraint enforcing method of constraint handler for LP solutions */
12519static
12520SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
12521{ /*lint --e{715}*/
12522 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, result) );
12523
12524 return SCIP_OKAY;
12525}
12526
12527/** constraint enforcing method of constraint handler for relaxation solutions */
12528static
12529SCIP_DECL_CONSENFORELAX(consEnforelaxKnapsack)
12530{ /*lint --e{715}*/
12531 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, result) );
12532
12533 return SCIP_OKAY;
12534}
12535
12536/** constraint enforcing method of constraint handler for pseudo solutions */
12537static
12538SCIP_DECL_CONSENFOPS(consEnfopsKnapsack)
12539{ /*lint --e{715}*/
12540 SCIP_Bool violated;
12541 int i;
12542
12543 for( i = 0; i < nconss; i++ )
12544 {
12545 SCIP_CALL( checkCons(scip, conss[i], NULL, TRUE, FALSE, &violated) );
12546 if( violated )
12547 {
12548 *result = SCIP_INFEASIBLE;
12549 return SCIP_OKAY;
12550 }
12551 }
12552 *result = SCIP_FEASIBLE;
12553
12554 return SCIP_OKAY;
12555}
12556
12557/** feasibility check method of constraint handler for integral solutions */
12558static
12559SCIP_DECL_CONSCHECK(consCheckKnapsack)
12560{ /*lint --e{715}*/
12561 SCIP_Bool violated;
12562 int i;
12563
12564 *result = SCIP_FEASIBLE;
12565
12566 for( i = 0; i < nconss && (*result == SCIP_FEASIBLE || completely); i++ )
12567 {
12568 SCIP_CALL( checkCons(scip, conss[i], sol, checklprows, printreason, &violated) );
12569 if( violated )
12570 *result = SCIP_INFEASIBLE;
12571 }
12572
12573 return SCIP_OKAY;
12574}
12575
12576/** domain propagation method of constraint handler */
12577static
12578SCIP_DECL_CONSPROP(consPropKnapsack)
12579{ /*lint --e{715}*/
12580 SCIP_CONSHDLRDATA* conshdlrdata;
12581 SCIP_Bool cutoff;
12582 SCIP_Bool redundant;
12583 SCIP_Bool inpresolve;
12584 int nfixedvars;
12585 int i;
12586
12587 cutoff = FALSE;
12588 nfixedvars = 0;
12589
12590 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12591 assert(conshdlrdata != NULL);
12592
12593 inpresolve = (SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE);
12594 assert(!inpresolve || SCIPinProbing(scip));
12595
12596 /* process useful constraints */
12597 for( i = 0; i < nmarkedconss && !cutoff; i++ )
12598 {
12599 /* do not propagate constraints with multi-aggregated variables, which should only happen in probing mode,
12600 * otherwise the multi-aggregation should be resolved
12601 */
12602 if( inpresolve && SCIPconsGetData(conss[i])->existmultaggr )
12603 continue;
12604#ifndef NDEBUG
12605 else
12606 assert(!(SCIPconsGetData(conss[i])->existmultaggr));
12607#endif
12608
12609 SCIP_CALL( propagateCons(scip, conss[i], &cutoff, &redundant, &nfixedvars, conshdlrdata->negatedclique) );
12610
12611 /* unmark the constraint to be propagated */
12613 }
12614
12615 /* adjust result code */
12616 if( cutoff )
12617 *result = SCIP_CUTOFF;
12618 else if( nfixedvars > 0 )
12619 *result = SCIP_REDUCEDDOM;
12620 else
12621 *result = SCIP_DIDNOTFIND;
12622
12623 return SCIP_OKAY; /*lint !e438*/
12624}
12625
12626/** presolving method of constraint handler */
12627static
12628SCIP_DECL_CONSPRESOL(consPresolKnapsack)
12629{ /*lint --e{574,715}*/
12630 SCIP_CONSHDLRDATA* conshdlrdata;
12631 SCIP_CONSDATA* consdata;
12632 SCIP_CONS* cons;
12633 SCIP_Bool cutoff;
12634 SCIP_Bool redundant;
12635 SCIP_Bool success;
12636 int oldnfixedvars;
12637 int oldnchgbds;
12638 int oldndelconss;
12639 int oldnaddconss;
12640 int oldnchgcoefs;
12641 int oldnchgsides;
12642 int firstchange;
12643 int c;
12644 SCIP_Bool newchanges;
12645
12646 /* remember old preprocessing counters */
12647 cutoff = FALSE;
12648 oldnfixedvars = *nfixedvars;
12649 oldnchgbds = *nchgbds;
12650 oldndelconss = *ndelconss;
12651 oldnaddconss = *naddconss;
12652 oldnchgcoefs = *nchgcoefs;
12653 oldnchgsides = *nchgsides;
12654 firstchange = INT_MAX;
12655
12656 newchanges = (nrounds == 0 || nnewfixedvars > 0 || nnewaggrvars > 0 || nnewchgbds > 0 || nnewupgdconss > 0);
12657
12658 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12659 assert(conshdlrdata != NULL);
12660
12661 for( c = 0; c < nconss && !SCIPisStopped(scip); c++ )
12662 {
12663 int thisnfixedvars;
12664 int thisnchgbds;
12665
12666 cons = conss[c];
12667 consdata = SCIPconsGetData(cons);
12668 assert(consdata != NULL);
12669
12670 /* update data structures */
12671 /* todo if UBTIGHTENED events were caught, we could move this block after the continue */
12672 if( newchanges || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12673 {
12674 SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12675 if( cutoff )
12676 break;
12677 }
12678
12679 /* force presolving the constraint in the initial round */
12680 if( nrounds == 0 )
12681 consdata->presolvedtiming = 0;
12682 else if( consdata->presolvedtiming >= presoltiming )
12683 continue;
12684
12685 SCIPdebugMsg(scip, "presolving knapsack constraint <%s>\n", SCIPconsGetName(cons));
12687 consdata->presolvedtiming = presoltiming;
12688
12689 thisnfixedvars = *nfixedvars;
12690 thisnchgbds = *nchgbds;
12691
12692 /* merge constraint, so propagation works better */
12693 SCIP_CALL( mergeMultiples(scip, cons, &cutoff) );
12694 if( cutoff )
12695 break;
12696
12697 /* add cliques in the knapsack to the clique table */
12698 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12699 {
12700 SCIP_CALL( addCliques(scip, cons, conshdlrdata->cliqueextractfactor, &cutoff, nchgbds) );
12701 if( cutoff )
12702 break;
12703 }
12704
12705 /* propagate constraint */
12706 if( presoltiming < SCIP_PRESOLTIMING_EXHAUSTIVE )
12707 {
12708 SCIP_CALL( propagateCons(scip, cons, &cutoff, &redundant, nfixedvars, (presoltiming & SCIP_PRESOLTIMING_MEDIUM)) );
12709
12710 if( cutoff )
12711 break;
12712 if( redundant )
12713 {
12714 (*ndelconss)++;
12715 continue;
12716 }
12717 }
12718
12719 /* remove again all fixed variables, if further fixings were found */
12720 if( *nfixedvars > thisnfixedvars || *nchgbds > thisnchgbds )
12721 {
12722 SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12723 if( cutoff )
12724 break;
12725
12726 thisnfixedvars = *nfixedvars;
12727 }
12728
12729 if( !SCIPconsIsModifiable(cons) )
12730 {
12731 /* check again for redundancy (applyFixings() might have decreased weightsum due to fixed-to-zero vars) */
12732 if( consdata->weightsum <= consdata->capacity )
12733 {
12734 SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
12735 SCIPconsGetName(cons), consdata->weightsum, consdata->capacity);
12737 continue;
12738 }
12739
12740 /* divide weights by their greatest common divisor */
12741 normalizeWeights(cons, nchgcoefs, nchgsides);
12742
12743 /* try to simplify inequalities */
12744 if( conshdlrdata->simplifyinequalities && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
12745 {
12746 SCIP_CALL( simplifyInequalities(scip, cons, nfixedvars, ndelconss, nchgcoefs, nchgsides, naddconss, &cutoff) );
12747 if( cutoff )
12748 break;
12749
12750 if( SCIPconsIsDeleted(cons) )
12751 continue;
12752
12753 /* remove again all fixed variables, if further fixings were found */
12754 if( *nfixedvars > thisnfixedvars )
12755 {
12756 SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12757 if( cutoff )
12758 break;
12759 }
12760 }
12761
12762 /* tighten capacity and weights */
12763 SCIP_CALL( tightenWeights(scip, cons, presoltiming, nchgcoefs, nchgsides, naddconss, ndelconss, &cutoff) );
12764 if( cutoff )
12765 break;
12766
12767 if( SCIPconsIsActive(cons) )
12768 {
12769 if( conshdlrdata->dualpresolving && SCIPallowStrongDualReds(scip) && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12770 {
12771 /* in case the knapsack constraints is independent of everything else, solve the knapsack and apply the
12772 * dual reduction
12773 */
12774 SCIP_CALL( dualPresolving(scip, cons, nchgbds, ndelconss, &redundant) );
12775 if( redundant )
12776 continue;
12777 }
12778
12779 /* check if knapsack constraint is parallel to objective function */
12780 SCIP_CALL( checkParallelObjective(scip, cons, conshdlrdata) );
12781 }
12782 }
12783 /* remember the first changed constraint to begin the next aggregation round with */
12784 if( firstchange == INT_MAX && consdata->presolvedtiming != SCIP_PRESOLTIMING_EXHAUSTIVE )
12785 firstchange = c;
12786 }
12787
12788 /* preprocess pairs of knapsack constraints */
12789 if( !cutoff && conshdlrdata->presolusehashing && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12790 {
12791 /* detect redundant constraints; fast version with hash table instead of pairwise comparison */
12792 SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &cutoff, ndelconss) );
12793 }
12794
12795 if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) || (*naddconss != oldnaddconss) )
12796 success = TRUE;
12797 else
12798 success = FALSE;
12799
12800 if( !cutoff && firstchange < nconss && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
12801 {
12802 SCIP_Longint npaircomparisons;
12803
12804 npaircomparisons = 0;
12805 oldndelconss = *ndelconss;
12806 oldnchgsides = *nchgsides;
12807 oldnchgcoefs = *nchgcoefs;
12808
12809 for( c = firstchange; c < nconss && !SCIPisStopped(scip); ++c )
12810 {
12811 cons = conss[c];
12812 if( !SCIPconsIsActive(cons) || SCIPconsIsModifiable(cons) )
12813 continue;
12814
12815 npaircomparisons += ((SCIPconsGetData(cons)->presolvedtiming < SCIP_PRESOLTIMING_EXHAUSTIVE) ? (SCIP_Longint) c : ((SCIP_Longint) c - (SCIP_Longint) firstchange));
12816
12817 SCIP_CALL( preprocessConstraintPairs(scip, conss, firstchange, c, ndelconss) );
12818
12819 if( npaircomparisons > NMINCOMPARISONS )
12820 {
12821 if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) )
12822 success = TRUE;
12823 if( ((SCIP_Real) (*ndelconss - oldndelconss) + ((SCIP_Real) (*nchgsides - oldnchgsides))/2.0 +
12824 ((SCIP_Real) (*nchgcoefs - oldnchgcoefs))/10.0) / ((SCIP_Real) npaircomparisons) < MINGAINPERNMINCOMPARISONS )
12825 break;
12826 oldndelconss = *ndelconss;
12827 oldnchgsides = *nchgsides;
12828 oldnchgcoefs = *nchgcoefs;
12829 npaircomparisons = 0;
12830 }
12831 }
12832 }
12833#ifdef WITH_CARDINALITY_UPGRADE
12834 /* @todo upgrade to cardinality constraints: the code below relies on disabling the checking of the knapsack
12835 * constraint in the original problem, because the upgrade ensures that at most the given number of continuous
12836 * variables has a nonzero value, but not that the binary variables corresponding to the continuous variables with
12837 * value zero are set to zero as well. This can cause problems if the user accesses the values of the binary
12838 * variables (as the MIPLIB solution checker does), or the transformed problem is freed and the original problem
12839 * (possibly with some user modifications) is re-optimized. Until there is a way to force the binary variables to 0
12840 * as well, we better keep this code disabled. */
12841 /* upgrade to cardinality constraints - only try to upgrade towards the end of presolving, since the process below is quite expensive */
12842 if ( ! cutoff && conshdlrdata->upgdcardinality && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 && SCIPisPresolveFinished(scip) && ! conshdlrdata->upgradedcard )
12843 {
12844 SCIP_HASHMAP* varhash;
12845 SCIP_VAR** cardvars;
12846 SCIP_Real* cardweights;
12847 int noldupgdconss;
12848 int nscipvars;
12849 int makeupgrade;
12850
12851 noldupgdconss = *nupgdconss;
12852 nscipvars = SCIPgetNVars(scip);
12853 SCIP_CALL( SCIPallocClearBufferArray(scip, &cardvars, nscipvars) );
12854 SCIP_CALL( SCIPallocClearBufferArray(scip, &cardweights, nscipvars) );
12855
12856 /* set up hash map */
12857 SCIP_CALL( SCIPhashmapCreate(&varhash, SCIPblkmem(scip), nscipvars) );
12858
12859 /* We loop through all cardinality constraints twice:
12860 * - First, determine for each binary variable the number of cardinality constraints that can be upgraded to a
12861 * knapsack constraint and contain this variable; this number has to coincide with the number of variable up
12862 * locks; otherwise it would be infeasible to delete the knapsack constraints after the constraint update.
12863 * - Second, upgrade knapsack constraints to cardinality constraints. */
12864 for (makeupgrade = 0; makeupgrade < 2; ++makeupgrade)
12865 {
12866 for (c = nconss-1; c >= 0 && ! SCIPisStopped(scip); --c)
12867 {
12868 SCIP_CONS* cardcons;
12869 SCIP_VAR** vars;
12870 SCIP_Longint* weights;
12871 int nvars;
12872 int v;
12873
12874 cons = conss[c];
12875 assert( cons != NULL );
12876
12877 if( SCIPconsGetNUpgradeLocks(cons) >= 1 )
12878 continue;
12879
12880 consdata = SCIPconsGetData(cons);
12881 assert( consdata != NULL );
12882
12883 nvars = consdata->nvars;
12884 vars = consdata->vars;
12885 weights = consdata->weights;
12886
12887 /* Check, whether linear knapsack can be upgraded to a cardinality constraint:
12888 * - all variables must be binary (always true)
12889 * - all coefficients must be 1.0
12890 * - the right hand side must be smaller than nvars
12891 */
12892 if ( consdata->capacity >= nvars )
12893 continue;
12894
12895 /* the weights are sorted: check first and last weight */
12896 assert( consdata->sorted );
12897 if ( weights[0] != 1 || weights[nvars-1] != 1 )
12898 continue;
12899
12900 /* check whether all variables are of the form 0 <= x_v <= u_v y_v for y_v \in \{0,1\} and zero objective */
12901 for (v = 0; v < nvars; ++v)
12902 {
12903 SCIP_BOUNDTYPE* impltypes;
12904 SCIP_Real* implbounds;
12905 SCIP_VAR** implvars;
12906 SCIP_VAR* var;
12907 int nimpls;
12908 int j;
12909
12910 var = consdata->vars[v];
12911 assert( var != NULL );
12912 assert( SCIPvarIsBinary(var) );
12913
12914 /* ignore non-active variables */
12915 if ( ! SCIPvarIsActive(var) )
12916 break;
12917
12918 /* be sure that implication variable has zero objective */
12919 if ( ! SCIPisZero(scip, SCIPvarGetObj(var)) )
12920 break;
12921
12922 nimpls = SCIPvarGetNImpls(var, FALSE);
12923 implvars = SCIPvarGetImplVars(var, FALSE);
12924 implbounds = SCIPvarGetImplBounds(var, FALSE);
12925 impltypes = SCIPvarGetImplTypes(var, FALSE);
12926
12927 for (j = 0; j < nimpls; ++j)
12928 {
12929 /* be sure that continuous variable is fixed to 0 */
12930 if ( impltypes[j] != SCIP_BOUNDTYPE_UPPER )
12931 continue;
12932
12933 /* cannot currently deal with nonzero fixings */
12934 if ( ! SCIPisZero(scip, implbounds[j]) )
12935 continue;
12936
12937 /* number of down locks should be one */
12938 if ( SCIPvarGetNLocksDownType(vars[v], SCIP_LOCKTYPE_MODEL) != 1 )
12939 continue;
12940
12941 cardvars[v] = implvars[j];
12942 cardweights[v] = (SCIP_Real) v;
12943
12944 break;
12945 }
12946
12947 /* found no variable upper bound candidate -> exit */
12948 if ( j >= nimpls )
12949 break;
12950 }
12951
12952 /* did not find fitting variable upper bound for some variable -> exit */
12953 if ( v < nvars )
12954 break;
12955
12956 /* save number of knapsack constraints that can be upgraded to a cardinality constraint,
12957 * in which the binary variable is involved in */
12958 if ( makeupgrade == 0 )
12959 {
12960 for (v = 0; v < nvars; ++v)
12961 {
12962 if ( SCIPhashmapExists(varhash, vars[v]) )
12963 {
12964 int image;
12965
12966 image = SCIPhashmapGetImageInt(varhash, vars[v]);
12967 SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image + 1) );
12968 assert( image + 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12969 }
12970 else
12971 {
12972 SCIP_CALL( SCIPhashmapInsertInt(varhash, vars[v], 1) );
12973 assert( 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12974 assert( SCIPhashmapExists(varhash, vars[v]) );
12975 }
12976 }
12977 }
12978 else
12979 {
12980 SCIP_CONS* origcons;
12981
12982 /* for each variable: check whether the number of cardinality constraints that can be upgraded to a
12983 * knapsack constraint coincides with the number of variable up locks */
12984 for (v = 0; v < nvars; ++v)
12985 {
12986 assert( SCIPhashmapExists(varhash, vars[v]) );
12987 if ( SCIPvarGetNLocksUpType(vars[v], SCIP_LOCKTYPE_MODEL) != SCIPhashmapGetImageInt(varhash, vars[v]) )
12988 break;
12989 }
12990 if ( v < nvars )
12991 break;
12992
12993 /* store that we have upgraded */
12994 conshdlrdata->upgradedcard = TRUE;
12995
12996 /* at this point we found suitable variable upper bounds */
12997 SCIPdebugMessage("Upgrading knapsack constraint <%s> to cardinality constraint ...\n", SCIPconsGetName(cons));
12998
12999 /* create cardinality constraint */
13000 assert( ! SCIPconsIsModifiable(cons) );
13001 SCIP_CALL( SCIPcreateConsCardinality(scip, &cardcons, SCIPconsGetName(cons), nvars, cardvars, (int) consdata->capacity, vars, cardweights,
13005#ifdef SCIP_DEBUG
13006 SCIPprintCons(scip, cons, NULL);
13007 SCIPinfoMessage(scip, NULL, "\n");
13008 SCIPprintCons(scip, cardcons, NULL);
13009 SCIPinfoMessage(scip, NULL, "\n");
13010#endif
13011 /* add the upgraded constraint to the problem */
13012 SCIP_CALL( SCIPaddConsUpgrade(scip, cons, &cardcons) );
13013 ++(*nupgdconss);
13014
13015 /* delete oknapsack constraint */
13016 SCIP_CALL( SCIPdelCons(scip, cons) );
13017 ++(*ndelconss);
13018
13019 /* We need to disable the original knapsack constraint, since it might happen that the binary variables
13020 * are 1 although the continuous variables are 0. Thus, the knapsack constraint might be violated,
13021 * although the cardinality constraint is satisfied. */
13022 origcons = SCIPfindOrigCons(scip, SCIPconsGetName(cons));
13023 assert( origcons != NULL );
13024 SCIP_CALL( SCIPsetConsChecked(scip, origcons, FALSE) );
13025
13026 for (v = 0; v < nvars; ++v)
13027 {
13028 int image;
13029
13030 assert ( SCIPhashmapExists(varhash, vars[v]) );
13031 image = SCIPhashmapGetImageInt(varhash, vars[v]);
13032 SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image - 1) );
13033 assert( image - 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
13034 }
13035 }
13036 }
13037 }
13038 SCIPhashmapFree(&varhash);
13039 SCIPfreeBufferArray(scip, &cardweights);
13040 SCIPfreeBufferArray(scip, &cardvars);
13041
13042 if ( *nupgdconss > noldupgdconss )
13043 success = TRUE;
13044 }
13045#endif
13046
13047 if( cutoff )
13048 *result = SCIP_CUTOFF;
13049 else if( success || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
13050 *result = SCIP_SUCCESS;
13051 else
13052 *result = SCIP_DIDNOTFIND;
13053
13054 return SCIP_OKAY;
13055}
13056
13057/** propagation conflict resolving method of constraint handler */
13058static
13059SCIP_DECL_CONSRESPROP(consRespropKnapsack)
13060{ /*lint --e{715}*/
13061 SCIP_CONSDATA* consdata;
13062 SCIP_Longint capsum;
13063 int i;
13064
13065 assert(result != NULL);
13066
13067 consdata = SCIPconsGetData(cons);
13068 assert(consdata != NULL);
13069
13070 /* check if we fixed a binary variable to one (due to negated clique) */
13071 if( inferinfo >= 0 && SCIPvarGetLbLocal(infervar) > 0.5 )
13072 {
13073 for( i = 0; i < consdata->nvars; ++i )
13074 {
13075 if( SCIPvarGetIndex(consdata->vars[i]) == inferinfo )
13076 {
13077 assert( SCIPgetVarUbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) < 0.5 );
13078 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
13079 break;
13080 }
13081 }
13082 assert(i < consdata->nvars);
13083 }
13084 else
13085 {
13086 /* according to negated cliques the minweightsum and all variables which are fixed to one which led to a fixing of
13087 * another negated clique variable to one, the inferinfo was chosen to be the negative of the position in the
13088 * knapsack constraint, see one above call of SCIPinferBinvarCons
13089 */
13090 if( inferinfo < 0 )
13091 capsum = 0;
13092 else
13093 {
13094 /* locate the inference variable and calculate the capacity that has to be used up to conclude infervar == 0;
13095 * inferinfo stores the position of the inference variable (but maybe the variables were re-sorted)
13096 */
13097 if( inferinfo < consdata->nvars && consdata->vars[inferinfo] == infervar )
13098 capsum = consdata->weights[inferinfo];
13099 else
13100 {
13101 for( i = 0; i < consdata->nvars && consdata->vars[i] != infervar; ++i )
13102 {}
13103 assert(i < consdata->nvars);
13104 capsum = consdata->weights[i];
13105 }
13106 }
13107
13108 /* add fixed-to-one variables up to the point, that their weight plus the weight of the conflict variable exceeds
13109 * the capacity
13110 */
13111 if( capsum <= consdata->capacity )
13112 {
13113 for( i = 0; i < consdata->nvars; i++ )
13114 {
13115 if( SCIPgetVarLbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) > 0.5 )
13116 {
13117 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
13118 capsum += consdata->weights[i];
13119 if( capsum > consdata->capacity )
13120 break;
13121 }
13122 }
13123 }
13124 }
13125
13126 /* NOTE: It might be the case that capsum < consdata->capacity. This is due the fact that the fixing of the variable
13127 * to zero can included negated clique information. A negated clique means, that at most one of the clique
13128 * variables can be zero. These information can be used to compute a minimum activity of the constraint and
13129 * used to fix variables to zero.
13130 *
13131 * Even if capsum < consdata->capacity we still reported a complete reason since the minimum activity is based
13132 * on global variable bounds. It might even be the case that we reported to many variables which are fixed to
13133 * one.
13134 */
13135 *result = SCIP_SUCCESS;
13136
13137 return SCIP_OKAY;
13138}
13139
13140/** variable rounding lock method of constraint handler */
13141/**! [SnippetConsLockKnapsack] */
13142static
13143SCIP_DECL_CONSLOCK(consLockKnapsack)
13144{ /*lint --e{715}*/
13145 SCIP_CONSDATA* consdata;
13146 int i;
13147
13148 consdata = SCIPconsGetData(cons);
13149 assert(consdata != NULL);
13150
13151 for( i = 0; i < consdata->nvars; i++)
13152 {
13153 SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlocksneg, nlockspos) );
13154 }
13155
13156 return SCIP_OKAY;
13157}
13158/**! [SnippetConsLockKnapsack] */
13159
13160/** constraint activation notification method of constraint handler */
13161static
13162SCIP_DECL_CONSACTIVE(consActiveKnapsack)
13163{ /*lint --e{715}*/
13165 {
13166 SCIP_CALL( addNlrow(scip, cons) );
13167 }
13168
13169 return SCIP_OKAY;
13170}
13171
13172/** constraint deactivation notification method of constraint handler */
13173static
13174SCIP_DECL_CONSDEACTIVE(consDeactiveKnapsack)
13175{ /*lint --e{715}*/
13176 SCIP_CONSDATA* consdata;
13177
13178 assert(cons != NULL);
13179
13180 consdata = SCIPconsGetData(cons);
13181 assert(consdata != NULL);
13182
13183 /* remove row from NLP, if still in solving
13184 * if we are in exitsolve, the whole NLP will be freed anyway
13185 */
13186 if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && consdata->nlrow != NULL )
13187 {
13188 SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
13189 }
13190
13191 return SCIP_OKAY;
13192}
13193
13194/** variable deletion method of constraint handler */
13195static
13196SCIP_DECL_CONSDELVARS(consDelvarsKnapsack)
13197{
13198 assert(scip != NULL);
13199 assert(conshdlr != NULL);
13200 assert(conss != NULL || nconss == 0);
13201
13202 if( nconss > 0 )
13203 {
13204 SCIP_CALL( performVarDeletions(scip, conshdlr, conss, nconss) );
13205 }
13206
13207 return SCIP_OKAY;
13208}
13209
13210/** constraint display method of constraint handler */
13211static
13212SCIP_DECL_CONSPRINT(consPrintKnapsack)
13213{ /*lint --e{715}*/
13214 SCIP_CONSDATA* consdata;
13215 int i;
13216
13217 assert( scip != NULL );
13218 assert( conshdlr != NULL );
13219 assert( cons != NULL );
13220
13221 consdata = SCIPconsGetData(cons);
13222 assert(consdata != NULL);
13223
13224 for( i = 0; i < consdata->nvars; ++i )
13225 {
13226 if( i > 0 )
13227 SCIPinfoMessage(scip, file, " ");
13228 SCIPinfoMessage(scip, file, "%+" SCIP_LONGINT_FORMAT, consdata->weights[i]);
13229 SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[i], TRUE) );
13230 }
13231 SCIPinfoMessage(scip, file, " <= %" SCIP_LONGINT_FORMAT "", consdata->capacity);
13232
13233 return SCIP_OKAY;
13234}
13235
13236/** constraint copying method of constraint handler */
13237static
13238SCIP_DECL_CONSCOPY(consCopyKnapsack)
13239{ /*lint --e{715}*/
13240 SCIP_VAR** sourcevars;
13241 SCIP_Longint* weights;
13242 SCIP_Real* coefs;
13243 const char* consname;
13244 int nvars;
13245 int v;
13246
13247 /* get variables and coefficients of the source constraint */
13248 sourcevars = SCIPgetVarsKnapsack(sourcescip, sourcecons);
13249 nvars = SCIPgetNVarsKnapsack(sourcescip, sourcecons);
13250 weights = SCIPgetWeightsKnapsack(sourcescip, sourcecons);
13251
13253 for( v = 0; v < nvars; ++v )
13254 coefs[v] = (SCIP_Real) weights[v];
13255
13256 if( name != NULL )
13257 consname = name;
13258 else
13259 consname = SCIPconsGetName(sourcecons);
13260
13261 /* copy the logic using the linear constraint copy method */
13262 SCIP_CALL( SCIPcopyConsLinear(scip, cons, sourcescip, consname, nvars, sourcevars, coefs,
13263 -SCIPinfinity(scip), (SCIP_Real) SCIPgetCapacityKnapsack(sourcescip, sourcecons), varmap, consmap,
13264 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, global, valid) );
13265 assert(cons != NULL);
13266
13267 SCIPfreeBufferArray(scip, &coefs);
13268
13269 return SCIP_OKAY;
13270}
13271
13272/** constraint parsing method of constraint handler */
13273static
13274SCIP_DECL_CONSPARSE(consParseKnapsack)
13275{ /*lint --e{715}*/
13276 SCIP_VAR* var;
13277 SCIP_Longint weight;
13278 SCIP_VAR** vars;
13279 SCIP_Longint* weights;
13280 SCIP_Longint capacity;
13281 char* endptr;
13282 int nread;
13283 int nvars;
13284 int varssize;
13285
13286 assert(scip != NULL);
13287 assert(success != NULL);
13288 assert(str != NULL);
13289 assert(name != NULL);
13290 assert(cons != NULL);
13291
13292 *success = TRUE;
13293
13294 nvars = 0;
13295 varssize = 5;
13296 SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13297 SCIP_CALL( SCIPallocBufferArray(scip, &weights, varssize) );
13298
13299 while( *str != '\0' )
13300 {
13301 /* try to parse coefficient, and use 1 if not successful */
13302 weight = 1;
13303 nread = 0;
13304 (void) sscanf(str, "%" SCIP_LONGINT_FORMAT "%n", &weight, &nread);
13305 str += nread;
13306
13307 /* parse variable name */
13308 SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13309
13310 if( var == NULL )
13311 {
13312 endptr = strchr(endptr, '<');
13313
13314 if( endptr == NULL )
13315 {
13316 SCIPerrorMessage("no capacity found\n");
13317 *success = FALSE;
13318 }
13319 else
13320 str = endptr;
13321
13322 break;
13323 }
13324
13325 str = endptr;
13326
13327 /* store weight and variable */
13328 if( varssize <= nvars )
13329 {
13330 varssize = SCIPcalcMemGrowSize(scip, varssize+1);
13331 SCIP_CALL( SCIPreallocBufferArray(scip, &vars, varssize) );
13332 SCIP_CALL( SCIPreallocBufferArray(scip, &weights, varssize) );
13333 }
13334
13335 vars[nvars] = var;
13336 weights[nvars] = weight;
13337 ++nvars;
13338
13339 /* skip whitespace */
13340 SCIP_CALL( SCIPskipSpace((char**)&str) );
13341 }
13342
13343 if( *success )
13344 {
13345 if( strncmp(str, "<=", 2) != 0 )
13346 {
13347 SCIPerrorMessage("expected '<=' at begin of '%s'\n", str);
13348 *success = FALSE;
13349 }
13350 else
13351 {
13352 str += 2;
13353 }
13354 }
13355
13356 if( *success )
13357 {
13358 /* skip whitespace */
13359 SCIP_CALL( SCIPskipSpace((char**)&str) );
13360
13361 /* coverity[secure_coding] */
13362 if( sscanf(str, "%" SCIP_LONGINT_FORMAT, &capacity) != 1 )
13363 {
13364 SCIPerrorMessage("error parsing capacity from '%s'\n", str);
13365 *success = FALSE;
13366 }
13367 else
13368 {
13369 SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13370 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13371 }
13372 }
13373
13374 SCIPfreeBufferArray(scip, &vars);
13375 SCIPfreeBufferArray(scip, &weights);
13376
13377 return SCIP_OKAY;
13378}
13379
13380/** constraint method of constraint handler which returns the variables (if possible) */
13381static
13382SCIP_DECL_CONSGETVARS(consGetVarsKnapsack)
13383{ /*lint --e{715}*/
13384 SCIP_CONSDATA* consdata;
13385
13386 consdata = SCIPconsGetData(cons);
13387 assert(consdata != NULL);
13388
13389 if( varssize < consdata->nvars )
13390 (*success) = FALSE;
13391 else
13392 {
13393 assert(vars != NULL);
13394
13395 BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13396 (*success) = TRUE;
13397 }
13398
13399 return SCIP_OKAY;
13400}
13401
13402/** constraint method of constraint handler which returns the number of variables (if possible) */
13403static
13404SCIP_DECL_CONSGETNVARS(consGetNVarsKnapsack)
13405{ /*lint --e{715}*/
13406 SCIP_CONSDATA* consdata;
13407
13408 consdata = SCIPconsGetData(cons);
13409 assert(consdata != NULL);
13410
13411 (*nvars) = consdata->nvars;
13412 (*success) = TRUE;
13413
13414 return SCIP_OKAY;
13415}
13416
13417/** constraint handler method which returns the permutation symmetry detection graph of a constraint */
13418static
13419SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphKnapsack)
13420{ /*lint --e{715}*/
13421 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) );
13422
13423 return SCIP_OKAY;
13424}
13425
13426/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint */
13427static
13428SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphKnapsack)
13429{ /*lint --e{715}*/
13430 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) );
13431
13432 return SCIP_OKAY;
13433}
13434
13435/*
13436 * Event handler
13437 */
13438
13439/** execution method of bound change event handler */
13440static
13441SCIP_DECL_EVENTEXEC(eventExecKnapsack)
13442{ /*lint --e{715}*/
13443 SCIP_CONSDATA* consdata;
13444
13445 assert(eventdata != NULL);
13446 assert(eventdata->cons != NULL);
13447
13448 consdata = SCIPconsGetData(eventdata->cons);
13449 assert(consdata != NULL);
13450
13451 switch( SCIPeventGetType(event) )
13452 {
13454 consdata->onesweightsum += eventdata->weight;
13455 consdata->presolvedtiming = 0;
13456 SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13457 break;
13459 consdata->onesweightsum -= eventdata->weight;
13460 break;
13462 consdata->presolvedtiming = 0;
13463 SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13464 break;
13465 case SCIP_EVENTTYPE_VARFIXED: /* the variable should be removed from the constraint in presolving */
13466 if( !consdata->existmultaggr )
13467 {
13468 SCIP_VAR* var;
13469 var = SCIPeventGetVar(event);
13470 assert(var != NULL);
13471
13472 /* if the variable was aggregated or multiaggregated, we must signal to propagation that we are no longer merged */
13474 {
13475 consdata->existmultaggr = TRUE;
13476 consdata->merged = FALSE;
13477 }
13480 consdata->merged = FALSE;
13481 }
13482 /*lint -fallthrough*/
13483 case SCIP_EVENTTYPE_IMPLADDED: /* further preprocessing might be possible due to additional implications */
13484 consdata->presolvedtiming = 0;
13485 break;
13487 consdata->varsdeleted = TRUE;
13488 break;
13489 default:
13490 SCIPerrorMessage("invalid event type %" SCIP_EVENTTYPE_FORMAT "\n", SCIPeventGetType(event));
13491 return SCIP_INVALIDDATA;
13492 }
13493
13494 return SCIP_OKAY;
13495}
13496
13497
13498/*
13499 * constraint specific interface methods
13500 */
13501
13502/** creates the handler for knapsack constraints and includes it in SCIP */
13504 SCIP* scip /**< SCIP data structure */
13505 )
13506{
13507 SCIP_EVENTHDLRDATA* eventhdlrdata;
13508 SCIP_CONSHDLRDATA* conshdlrdata;
13509 SCIP_CONSHDLR* conshdlr;
13510
13511 /* create knapsack constraint handler data */
13512 SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
13513
13514 /* include event handler for bound change events */
13515 eventhdlrdata = NULL;
13516 conshdlrdata->eventhdlr = NULL;
13518 eventExecKnapsack, eventhdlrdata) );
13519 conshdlrdata->probtoidxmap = NULL;
13520 conshdlrdata->probtoidxmapsize = 0;
13521
13522 /* get event handler for bound change events */
13523 if( conshdlrdata->eventhdlr == NULL )
13524 {
13525 SCIPerrorMessage("event handler for knapsack constraints not found\n");
13526 return SCIP_PLUGINNOTFOUND;
13527 }
13528
13529 /* include constraint handler */
13532 consEnfolpKnapsack, consEnfopsKnapsack, consCheckKnapsack, consLockKnapsack,
13533 conshdlrdata) );
13534
13535 assert(conshdlr != NULL);
13536
13537 /* set non-fundamental callbacks via specific setter functions */
13538 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyKnapsack, consCopyKnapsack) );
13539 SCIP_CALL( SCIPsetConshdlrActive(scip, conshdlr, consActiveKnapsack) );
13540 SCIP_CALL( SCIPsetConshdlrDeactive(scip, conshdlr, consDeactiveKnapsack) );
13541 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteKnapsack) );
13542 SCIP_CALL( SCIPsetConshdlrDelvars(scip, conshdlr, consDelvarsKnapsack) );
13543 SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitKnapsack) );
13544 SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreKnapsack) );
13545 SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolKnapsack) );
13546 SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolKnapsack) );
13547 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeKnapsack) );
13548 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsKnapsack) );
13549 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsKnapsack) );
13550 SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitKnapsack) );
13551 SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreKnapsack) );
13552 SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpKnapsack) );
13553 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseKnapsack) );
13555 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintKnapsack) );
13558 SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropKnapsack) );
13559 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpKnapsack, consSepasolKnapsack, CONSHDLR_SEPAFREQ,
13561 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransKnapsack) );
13562 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxKnapsack) );
13563 SCIP_CALL( SCIPsetConshdlrGetPermsymGraph(scip, conshdlr, consGetPermsymGraphKnapsack) );
13564 SCIP_CALL( SCIPsetConshdlrGetSignedPermsymGraph(scip, conshdlr, consGetSignedPermsymGraphKnapsack) );
13565
13566 if( SCIPfindConshdlr(scip,"linear") != NULL )
13567 {
13568 /* include the linear constraint to knapsack constraint upgrade in the linear constraint handler */
13570 }
13571
13572 /* add knapsack constraint handler parameters */
13574 "constraints/" CONSHDLR_NAME "/sepacardfreq",
13575 "multiplier on separation frequency, how often knapsack cuts are separated (-1: never, 0: only at root)",
13576 &conshdlrdata->sepacardfreq, TRUE, DEFAULT_SEPACARDFREQ, -1, SCIP_MAXTREEDEPTH, NULL, NULL) );
13578 "constraints/" CONSHDLR_NAME "/maxcardbounddist",
13579 "maximal relative distance from current node's dual bound to primal bound compared to best node's dual bound for separating knapsack cuts",
13580 &conshdlrdata->maxcardbounddist, TRUE, DEFAULT_MAXCARDBOUNDDIST, 0.0, 1.0, NULL, NULL) );
13582 "constraints/" CONSHDLR_NAME "/cliqueextractfactor",
13583 "lower clique size limit for greedy clique extraction algorithm (relative to largest clique)",
13584 &conshdlrdata->cliqueextractfactor, TRUE, DEFAULT_CLIQUEEXTRACTFACTOR, 0.0, 1.0, NULL, NULL) );
13586 "constraints/" CONSHDLR_NAME "/maxrounds",
13587 "maximal number of separation rounds per node (-1: unlimited)",
13588 &conshdlrdata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
13590 "constraints/" CONSHDLR_NAME "/maxroundsroot",
13591 "maximal number of separation rounds per node in the root node (-1: unlimited)",
13592 &conshdlrdata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
13594 "constraints/" CONSHDLR_NAME "/maxsepacuts",
13595 "maximal number of cuts separated per separation round",
13596 &conshdlrdata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
13598 "constraints/" CONSHDLR_NAME "/maxsepacutsroot",
13599 "maximal number of cuts separated per separation round in the root node",
13600 &conshdlrdata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
13602 "constraints/" CONSHDLR_NAME "/disaggregation",
13603 "should disaggregation of knapsack constraints be allowed in preprocessing?",
13604 &conshdlrdata->disaggregation, TRUE, DEFAULT_DISAGGREGATION, NULL, NULL) );
13606 "constraints/" CONSHDLR_NAME "/simplifyinequalities",
13607 "should presolving try to simplify knapsacks",
13608 &conshdlrdata->simplifyinequalities, TRUE, DEFAULT_SIMPLIFYINEQUALITIES, NULL, NULL) );
13610 "constraints/" CONSHDLR_NAME "/negatedclique",
13611 "should negated clique information be used in solving process",
13612 &conshdlrdata->negatedclique, TRUE, DEFAULT_NEGATEDCLIQUE, NULL, NULL) );
13614 "constraints/" CONSHDLR_NAME "/presolpairwise",
13615 "should pairwise constraint comparison be performed in presolving?",
13616 &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13618 "constraints/" CONSHDLR_NAME "/presolusehashing",
13619 "should hash table be used for detecting redundant constraints in advance",
13620 &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) );
13622 "constraints/" CONSHDLR_NAME "/dualpresolving",
13623 "should dual presolving steps be performed?",
13624 &conshdlrdata->dualpresolving, TRUE, DEFAULT_DUALPRESOLVING, NULL, NULL) );
13626 "constraints/" CONSHDLR_NAME "/usegubs",
13627 "should GUB information be used for separation?",
13628 &conshdlrdata->usegubs, TRUE, DEFAULT_USEGUBS, NULL, NULL) );
13630 "constraints/" CONSHDLR_NAME "/detectcutoffbound",
13631 "should presolving try to detect constraints parallel to the objective function defining an upper bound and prevent these constraints from entering the LP?",
13632 &conshdlrdata->detectcutoffbound, TRUE, DEFAULT_DETECTCUTOFFBOUND, NULL, NULL) );
13634 "constraints/" CONSHDLR_NAME "/detectlowerbound",
13635 "should presolving try to detect constraints parallel to the objective function defining a lower bound and prevent these constraints from entering the LP?",
13636 &conshdlrdata->detectlowerbound, TRUE, DEFAULT_DETECTLOWERBOUND, NULL, NULL) );
13638 "constraints/" CONSHDLR_NAME "/updatecliquepartitions",
13639 "should clique partition information be updated when old partition seems outdated?",
13640 &conshdlrdata->updatecliquepartitions, TRUE, DEFAULT_UPDATECLIQUEPARTITIONS, NULL, NULL) );
13642 "constraints/" CONSHDLR_NAME "/clqpartupdatefac",
13643 "factor on the growth of global cliques to decide when to update a previous "
13644 "(negated) clique partition (used only if updatecliquepartitions is set to TRUE)",
13645 &conshdlrdata->clqpartupdatefac, TRUE, DEFAULT_CLQPARTUPDATEFAC, 1.0, 10.0, NULL, NULL) );
13646#ifdef WITH_CARDINALITY_UPGRADE
13648 "constraints/" CONSHDLR_NAME "/upgdcardinality",
13649 "if TRUE then try to update knapsack constraints to cardinality constraints",
13650 &conshdlrdata->upgdcardinality, TRUE, DEFAULT_UPGDCARDINALITY, NULL, NULL) );
13651#endif
13652 return SCIP_OKAY;
13653}
13654
13655/** creates and captures a knapsack constraint
13656 *
13657 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13658 */
13659/**! [SnippetConsCreationKnapsack] */
13661 SCIP* scip, /**< SCIP data structure */
13662 SCIP_CONS** cons, /**< pointer to hold the created constraint */
13663 const char* name, /**< name of constraint */
13664 int nvars, /**< number of items in the knapsack */
13665 SCIP_VAR** vars, /**< array with item variables */
13666 SCIP_Longint* weights, /**< array with item weights */
13667 SCIP_Longint capacity, /**< capacity of knapsack (right hand side of inequality) */
13668 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13669 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13670 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13671 * Usually set to TRUE. */
13672 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13673 * TRUE for model constraints, FALSE for additional, redundant constraints. */
13674 SCIP_Bool check, /**< should the constraint be checked for feasibility?
13675 * TRUE for model constraints, FALSE for additional, redundant constraints. */
13676 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13677 * Usually set to TRUE. */
13678 SCIP_Bool local, /**< is constraint only valid locally?
13679 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13680 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13681 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13682 * adds coefficients to this constraint. */
13683 SCIP_Bool dynamic, /**< is constraint subject to aging?
13684 * Usually set to FALSE. Set to TRUE for own cuts which
13685 * are separated as constraints. */
13686 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13687 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13688 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13689 * if it may be moved to a more global node?
13690 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13691 )
13692{
13693 SCIP_CONSHDLRDATA* conshdlrdata;
13694 SCIP_CONSHDLR* conshdlr;
13695 SCIP_CONSDATA* consdata;
13696 int i;
13697
13698 /* find the knapsack constraint handler */
13699 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13700 if( conshdlr == NULL )
13701 {
13702 SCIPerrorMessage("knapsack constraint handler not found\n");
13703 return SCIP_PLUGINNOTFOUND;
13704 }
13705
13706 /* check whether all variables are binary */
13707 assert(vars != NULL || nvars == 0);
13708 for( i = 0; i < nvars; ++i )
13709 {
13710 if( !SCIPvarIsBinary(vars[i]) )
13711 {
13712 SCIPerrorMessage("item <%s> is not binary\n", SCIPvarGetName(vars[i]));
13713 return SCIP_INVALIDDATA;
13714 }
13715 }
13716
13717 /* get event handler */
13718 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13719 assert(conshdlrdata != NULL);
13720 assert(conshdlrdata->eventhdlr != NULL);
13721
13722 /* create constraint data */
13723 SCIP_CALL( consdataCreate(scip, &consdata, nvars, vars, weights, capacity) );
13724
13725 /* create constraint */
13726 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
13727 local, modifiable, dynamic, removable, stickingatnode) );
13728
13729 /* catch events for variables */
13730 if( SCIPisTransformed(scip) )
13731 {
13732 SCIP_CALL( catchEvents(scip, *cons, consdata, conshdlrdata->eventhdlr) );
13733 }
13734
13735 return SCIP_OKAY;
13736}
13737/**! [SnippetConsCreationKnapsack] */
13738
13739/** creates and captures a knapsack constraint
13740 * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13741 * method SCIPcreateConsKnapsack(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13742 *
13743 * @see SCIPcreateConsKnapsack() for information about the basic constraint flag configuration
13744 *
13745 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13746 */
13748 SCIP* scip, /**< SCIP data structure */
13749 SCIP_CONS** cons, /**< pointer to hold the created constraint */
13750 const char* name, /**< name of constraint */
13751 int nvars, /**< number of items in the knapsack */
13752 SCIP_VAR** vars, /**< array with item variables */
13753 SCIP_Longint* weights, /**< array with item weights */
13754 SCIP_Longint capacity /**< capacity of knapsack */
13755 )
13756{
13757 assert(scip != NULL);
13758
13759 SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13761
13762 return SCIP_OKAY;
13763}
13764
13765/** adds new item to knapsack constraint */
13767 SCIP* scip, /**< SCIP data structure */
13768 SCIP_CONS* cons, /**< constraint data */
13769 SCIP_VAR* var, /**< item variable */
13770 SCIP_Longint weight /**< item weight */
13771 )
13772{
13773 assert(var != NULL);
13774 assert(scip != NULL);
13775
13776 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13777 {
13778 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13779 return SCIP_INVALIDDATA;
13780 }
13781
13782 SCIP_CALL( addCoef(scip, cons, var, weight) );
13783
13784 return SCIP_OKAY;
13785}
13786
13787/** gets the capacity of the knapsack constraint */
13789 SCIP* scip, /**< SCIP data structure */
13790 SCIP_CONS* cons /**< constraint data */
13791 )
13792{
13793 SCIP_CONSDATA* consdata;
13794
13795 assert(scip != NULL);
13796
13797 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13798 {
13799 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13800 SCIPABORT();
13801 return 0; /*lint !e527*/
13802 }
13803
13804 consdata = SCIPconsGetData(cons);
13805 assert(consdata != NULL);
13806
13807 return consdata->capacity;
13808}
13809
13810/** changes capacity of the knapsack constraint
13811 *
13812 * @note This method can only be called during problem creation stage (SCIP_STAGE_PROBLEM)
13813 */
13815 SCIP* scip, /**< SCIP data structure */
13816 SCIP_CONS* cons, /**< constraint data */
13817 SCIP_Longint capacity /**< new capacity of knapsack */
13818 )
13819{
13820 SCIP_CONSDATA* consdata;
13821
13822 assert(scip != NULL);
13823
13824 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13825 {
13826 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13827 return SCIP_INVALIDDATA;
13828 }
13829
13831 {
13832 SCIPerrorMessage("method can only be called during problem creation stage\n");
13833 return SCIP_INVALIDDATA;
13834 }
13835
13836 consdata = SCIPconsGetData(cons);
13837 assert(consdata != NULL);
13838
13839 consdata->capacity = capacity;
13840
13841 return SCIP_OKAY;
13842}
13843
13844/** gets the number of items in the knapsack constraint */
13846 SCIP* scip, /**< SCIP data structure */
13847 SCIP_CONS* cons /**< constraint data */
13848 )
13849{
13850 SCIP_CONSDATA* consdata;
13851
13852 assert(scip != NULL);
13853
13854 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13855 {
13856 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13857 SCIPABORT();
13858 return -1; /*lint !e527*/
13859 }
13860
13861 consdata = SCIPconsGetData(cons);
13862 assert(consdata != NULL);
13863
13864 return consdata->nvars;
13865}
13866
13867/** gets the array of variables in the knapsack constraint; the user must not modify this array! */
13869 SCIP* scip, /**< SCIP data structure */
13870 SCIP_CONS* cons /**< constraint data */
13871 )
13872{
13873 SCIP_CONSDATA* consdata;
13874
13875 assert(scip != NULL);
13876
13877 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13878 {
13879 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13880 SCIPABORT();
13881 return NULL; /*lint !e527*/
13882 }
13883
13884 consdata = SCIPconsGetData(cons);
13885 assert(consdata != NULL);
13886
13887 return consdata->vars;
13888}
13889
13890/** gets the array of weights in the knapsack constraint; the user must not modify this array! */
13892 SCIP* scip, /**< SCIP data structure */
13893 SCIP_CONS* cons /**< constraint data */
13894 )
13895{
13896 SCIP_CONSDATA* consdata;
13897
13898 assert(scip != NULL);
13899
13900 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13901 {
13902 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13903 SCIPABORT();
13904 return NULL; /*lint !e527*/
13905 }
13906
13907 consdata = SCIPconsGetData(cons);
13908 assert(consdata != NULL);
13909
13910 return consdata->weights;
13911}
13912
13913/** gets the dual solution of the knapsack constraint in the current LP */
13915 SCIP* scip, /**< SCIP data structure */
13916 SCIP_CONS* cons /**< constraint data */
13917 )
13918{
13919 SCIP_CONSDATA* consdata;
13920
13921 assert(scip != NULL);
13922
13923 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13924 {
13925 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13926 SCIPABORT();
13927 return SCIP_INVALID; /*lint !e527*/
13928 }
13929
13930 consdata = SCIPconsGetData(cons);
13931 assert(consdata != NULL);
13932
13933 if( consdata->row != NULL )
13934 return SCIProwGetDualsol(consdata->row);
13935 else
13936 return 0.0;
13937}
13938
13939/** gets the dual Farkas value of the knapsack constraint in the current infeasible LP */
13941 SCIP* scip, /**< SCIP data structure */
13942 SCIP_CONS* cons /**< constraint data */
13943 )
13944{
13945 SCIP_CONSDATA* consdata;
13946
13947 assert(scip != NULL);
13948
13949 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13950 {
13951 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13952 SCIPABORT();
13953 return SCIP_INVALID; /*lint !e527*/
13954 }
13955
13956 consdata = SCIPconsGetData(cons);
13957 assert(consdata != NULL);
13958
13959 if( consdata->row != NULL )
13960 return SCIProwGetDualfarkas(consdata->row);
13961 else
13962 return 0.0;
13963}
13964
13965/** returns the linear relaxation of the given knapsack constraint; may return NULL if no LP row was yet created;
13966 * the user must not modify the row!
13967 */
13969 SCIP* scip, /**< SCIP data structure */
13970 SCIP_CONS* cons /**< constraint data */
13971 )
13972{
13973 SCIP_CONSDATA* consdata;
13974
13975 assert(scip != NULL);
13976
13977 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13978 {
13979 SCIPerrorMessage("constraint is not a knapsack\n");
13980 SCIPABORT();
13981 return NULL; /*lint !e527*/
13982 }
13983
13984 consdata = SCIPconsGetData(cons);
13985 assert(consdata != NULL);
13986
13987 return consdata->row;
13988}
13989
13990/** creates and returns the row of the given knapsack constraint */
13992 SCIP* scip, /**< SCIP data structure */
13993 SCIP_CONS* cons /**< constraint data */
13994 )
13995{
13996 SCIP_CONSDATA* consdata;
13997 int i;
13998
13999 assert(scip != NULL);
14000
14001 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14002 {
14003 SCIPerrorMessage("constraint is not a knapsack\n");
14004 SCIPABORT();
14005 return SCIP_ERROR; /*lint !e527*/
14006 }
14007
14008 consdata = SCIPconsGetData(cons);
14009 assert(consdata != NULL);
14010 assert(consdata->row == NULL);
14011
14012 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, cons, SCIPconsGetName(cons),
14013 -SCIPinfinity(scip), (SCIP_Real)consdata->capacity,
14015
14016 SCIP_CALL( SCIPcacheRowExtensions(scip, consdata->row) );
14017 for( i = 0; i < consdata->nvars; ++i )
14018 {
14019 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, consdata->vars[i], (SCIP_Real)consdata->weights[i]) );
14020 }
14021 SCIP_CALL( SCIPflushRowExtensions(scip, consdata->row) );
14022
14023 return SCIP_OKAY;
14024}
14025
14026/** cleans up (multi-)aggregations and fixings from knapsack constraints */
14028 SCIP* scip, /**< SCIP data structure */
14029 SCIP_Bool onlychecked, /**< should only checked constraints be cleaned up? */
14030 SCIP_Bool* infeasible, /**< pointer to return whether the problem was detected to be infeasible */
14031 int* ndelconss /**< pointer to count number of deleted constraints */
14032 )
14033{
14034 SCIP_CONSHDLR* conshdlr;
14035 SCIP_CONS** conss;
14036 int nconss;
14037 int i;
14038
14039 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14040 if( conshdlr == NULL )
14041 return SCIP_OKAY;
14042
14043 assert(infeasible != NULL);
14044 *infeasible = FALSE;
14045
14046 nconss = onlychecked ? SCIPconshdlrGetNCheckConss(conshdlr) : SCIPconshdlrGetNActiveConss(conshdlr);
14047 conss = onlychecked ? SCIPconshdlrGetCheckConss(conshdlr) : SCIPconshdlrGetConss(conshdlr);
14048
14049 /* loop backwards since then deleted constraints do not interfere with the loop */
14050 for( i = nconss - 1; i >= 0; --i )
14051 {
14052 SCIP_CALL( applyFixings(scip, conss[i], infeasible) );
14053
14054 if( *infeasible )
14055 break;
14056
14057 if( SCIPconsGetData(conss[i])->nvars >= 1 )
14058 continue;
14059
14060 SCIP_CALL( SCIPdelCons(scip, conss[i]) );
14061 ++(*ndelconss);
14062 }
14063
14064 return SCIP_OKAY;
14065}
SCIP_VAR * h
Definition: circlepacking.c:68
SCIP_VAR * w
Definition: circlepacking.c:67
SCIP_VAR ** b
Definition: circlepacking.c:65
constraint handler for cardinality constraints
static SCIP_Longint safeAddMinweightsGUB(SCIP_Longint val1, SCIP_Longint val2)
static SCIP_RETCODE separateCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool sepacuts, SCIP_Bool usegubs, SCIP_Bool *cutoff, int *ncuts)
static SCIP_DECL_CONSCOPY(consCopyKnapsack)
static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSDATA **consdata, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack)
static SCIP_RETCODE getLiftingSequenceGUB(SCIP *scip, SCIP_GUBSET *gubset, SCIP_Real *solvals, SCIP_Longint *weights, int *varsC1, int *varsC2, int *varsF, int *varsR, int nvarsC1, int nvarsC2, int nvarsF, int nvarsR, int *gubconsGC1, int *gubconsGC2, int *gubconsGFC1, int *gubconsGR, int *ngubconsGC1, int *ngubconsGC2, int *ngubconsGFC1, int *ngubconsGR, int *ngubconscapexceed, int *maxgubvarssize)
GUBConsstatus
@ GUBCONSSTATUS_BELONGSTOSET_GF
@ GUBCONSSTATUS_UNINITIAL
@ GUBCONSSTATUS_BELONGSTOSET_GR
@ GUBCONSSTATUS_BELONGSTOSET_GOC1
@ GUBCONSSTATUS_BELONGSTOSET_GNC1
@ GUBCONSSTATUS_BELONGSTOSET_GC2
#define DEFAULT_DUALPRESOLVING
static SCIP_RETCODE deleteRedundantVars(SCIP *scip, SCIP_CONS *cons, SCIP_Longint frontsum, int splitpos, int *nchgcoefs, int *nchgsides, int *naddconss)
#define CONSHDLR_NEEDSCONS
Definition: cons_knapsack.c:93
#define DEFAULT_SEPACARDFREQ
#define CONSHDLR_SEPAFREQ
Definition: cons_knapsack.c:86
static SCIP_RETCODE insertZerolist(SCIP *scip, int **liftcands, int *nliftcands, int **firstidxs, SCIP_Longint **zeroweightsums, int **zeroitems, int **nextidxs, int *zeroitemssize, int *nzeroitems, int probindex, SCIP_Bool value, int knapsackidx, SCIP_Longint knapsackweight, SCIP_Bool *memlimitreached)
static SCIP_RETCODE addRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff)
#define KNAPSACKRELAX_MAXDELTA
static SCIP_DECL_CONSENFOPS(consEnfopsKnapsack)
static SCIP_RETCODE eventdataCreate(SCIP *scip, SCIP_EVENTDATA **eventdata, SCIP_CONS *cons, SCIP_Longint weight)
static SCIP_RETCODE prepareCons(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *ndelconss, int *nchgcoefs)
static SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphKnapsack)
#define DEFAULT_USEGUBS
#define CONSHDLR_CHECKPRIORITY
Definition: cons_knapsack.c:85
static SCIP_RETCODE enlargeMinweights(SCIP *scip, SCIP_Longint **minweightsptr, int *minweightslen, int *minweightssize, int newlen)
#define CONSHDLR_DESC
Definition: cons_knapsack.c:82
static SCIP_DECL_CONSGETVARS(consGetVarsKnapsack)
static SCIP_RETCODE separateSequLiftedExtendedWeightInequality(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *feassetvars, int *nonfeassetvars, int nfeassetvars, int nnonfeassetvars, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
static SCIP_DECL_CONSEXIT(consExitKnapsack)
static SCIP_RETCODE GUBconsCreate(SCIP *scip, SCIP_GUBCONS **gubcons)
static SCIP_DECL_CONSPRINT(consPrintKnapsack)
#define KNAPSACKRELAX_MAXSCALE
static void normalizeWeights(SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
static SCIP_RETCODE separateSupLiftedMinimalCoverInequality(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *mincovervars, int *nonmincovervars, int nmincovervars, int nnonmincovervars, SCIP_Longint mincoverweight, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
#define DEFAULT_DETECTCUTOFFBOUND
static SCIP_RETCODE addCliques(SCIP *const scip, SCIP_CONS *const cons, SCIP_Real cliqueextractfactor, SCIP_Bool *const cutoff, int *const nbdchgs)
static SCIP_RETCODE upgradeCons(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *naddconss)
static SCIP_RETCODE createRelaxation(SCIP *scip, SCIP_CONS *cons)
static void updateWeightSums(SCIP_CONSDATA *consdata, SCIP_VAR *var, SCIP_Longint weightdelta)
static void GUBconsFree(SCIP *scip, SCIP_GUBCONS **gubcons)
#define CONSHDLR_PROP_TIMING
Definition: cons_knapsack.c:96
static SCIP_DECL_CONSSEPALP(consSepalpKnapsack)
static void getPartitionCovervars(SCIP *scip, SCIP_Real *solvals, int *covervars, int ncovervars, int *varsC1, int *varsC2, int *nvarsC1, int *nvarsC2)
static void GUBsetSwapVars(SCIP *scip, SCIP_GUBSET *gubset, int var1, int var2)
static SCIP_RETCODE unlockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
static SCIP_DECL_CONSTRANS(consTransKnapsack)
static SCIP_RETCODE getCover(SCIP *scip, SCIP_VAR **vars, int nvars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int *ncovervars, int *nnoncovervars, SCIP_Longint *coverweight, SCIP_Bool *found, SCIP_Bool modtransused, int *ntightened, SCIP_Bool *fractional)
static SCIP_DECL_CONSPROP(consPropKnapsack)
static SCIP_RETCODE consdataEnsureVarsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num, SCIP_Bool transformed)
static SCIP_DECL_CONSRESPROP(consRespropKnapsack)
static void GUBsetFree(SCIP *scip, SCIP_GUBSET **gubset)
static SCIP_RETCODE createNormalizedKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
#define CONSHDLR_MAXPREROUNDS
Definition: cons_knapsack.c:90
static SCIP_RETCODE calcCliquepartition(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONSDATA *consdata, SCIP_Bool normalclique, SCIP_Bool negatedclique)
static SCIP_DECL_CONSEXITPRE(consExitpreKnapsack)
#define DEFAULT_PRESOLPAIRWISE
static SCIP_RETCODE performVarDeletions(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
#define CONSHDLR_SEPAPRIORITY
Definition: cons_knapsack.c:83
static SCIP_DECL_CONSINITSOL(consInitsolKnapsack)
#define DEFAULT_MAXROUNDSROOT
struct sortkeypair SORTKEYPAIR
#define DEFAULT_NEGATEDCLIQUE
enum GUBVarstatus GUBVARSTATUS
static SCIP_RETCODE changePartitionCovervars(SCIP *scip, SCIP_Longint *weights, int *varsC1, int *varsC2, int *nvarsC1, int *nvarsC2)
#define DEFAULT_MAXCARDBOUNDDIST
static SCIP_DECL_SORTPTRCOMP(compSortkeypairs)
#define MAXCOVERSIZEITERLEWI
static SCIP_RETCODE mergeMultiples(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff)
static SCIP_RETCODE GUBsetCheck(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars)
static SCIP_RETCODE GUBsetMoveVar(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, int var, int oldgubcons, int newgubcons)
static SCIP_DECL_CONSCHECK(consCheckKnapsack)
static void sortItems(SCIP_CONSDATA *consdata)
static SCIP_DECL_CONSGETNVARS(consGetNVarsKnapsack)
static SCIP_RETCODE addNegatedCliques(SCIP *const scip, SCIP_CONS *const cons, SCIP_Bool *const cutoff, int *const nbdchgs)
static SCIP_DECL_CONSINIT(consInitKnapsack)
static SCIP_RETCODE detectRedundantVars(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *nchgcoefs, int *nchgsides, int *naddconss)
static SCIP_RETCODE GUBsetGetCliquePartition(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, SCIP_Real *solvals)
static SCIP_DECL_EVENTEXEC(eventExecKnapsack)
static SCIP_RETCODE addSymmetryInformation(SCIP *scip, SYM_SYMTYPE symtype, SCIP_CONS *cons, SYM_GRAPH *graph, SCIP_Bool *success)
static SCIP_RETCODE applyFixings(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff)
static SCIP_RETCODE lockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
static void computeMinweightsGUB(SCIP_Longint *minweights, SCIP_Longint *finished, SCIP_Longint *unfinished, int minweightslen)
static SCIP_DECL_CONSINITLP(consInitlpKnapsack)
static SCIP_RETCODE sequentialUpAndDownLiftingGUB(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, int ngubconscapexceed, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *gubconsGC1, int *gubconsGC2, int *gubconsGFC1, int *gubconsGR, int ngubconsGC1, int ngubconsGC2, int ngubconsGFC1, int ngubconsGR, int alpha0, int *liftcoefs, SCIP_Real *cutact, int *liftrhs, int maxgubvarssize)
#define HASHSIZE_KNAPSACKCONS
static SCIP_RETCODE GUBsetCalcCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques, SCIP_Real *solvals)
#define DEFAULT_MAXSEPACUTSROOT
static SCIP_RETCODE checkCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool checklprows, SCIP_Bool printreason, SCIP_Bool *violated)
static SCIP_DECL_CONSEXITSOL(consExitsolKnapsack)
static SCIP_RETCODE dualWeightsTightening(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *nchgcoefs, int *nchgsides, int *naddconss)
static SCIP_DECL_CONSPRESOL(consPresolKnapsack)
#define DEFAULT_PRESOLUSEHASHING
#define MAX_CLIQUELENGTH
static SCIP_DECL_HASHGETKEY(hashGetKeyKnapsackcons)
#define DEFAULT_CLQPARTUPDATEFAC
static SCIP_DECL_CONSDELVARS(consDelvarsKnapsack)
static SCIP_RETCODE addCoef(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
static SCIP_RETCODE dropEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata, SCIP_EVENTHDLR *eventhdlr)
#define IDX(j, d)
static SCIP_Bool checkMinweightidx(SCIP_Longint *weights, SCIP_Longint capacity, int *covervars, int ncovervars, SCIP_Longint coverweight, int minweightidx, int j)
static SCIP_DECL_CONSDEACTIVE(consDeactiveKnapsack)
static SCIP_RETCODE sequentialUpAndDownLifting(SCIP *scip, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *varsM1, int *varsM2, int *varsF, int *varsR, int nvarsM1, int nvarsM2, int nvarsF, int nvarsR, int alpha0, int *liftcoefs, SCIP_Real *cutact, int *liftrhs)
static SCIP_RETCODE separateSequLiftedMinimalCoverInequality(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *mincovervars, int *nonmincovervars, int nmincovervars, int nnonmincovervars, SCIP_SOL *sol, SCIP_GUBSET *gubset, SCIP_Bool *cutoff, int *ncuts)
#define GUBCONSGROWVALUE
static SCIP_RETCODE makeCoverMinimal(SCIP *scip, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int *ncovervars, int *nnoncovervars, SCIP_Longint *coverweight, SCIP_Bool modtransused)
static SCIP_RETCODE delCoefPos(SCIP *scip, SCIP_CONS *cons, int pos)
#define MINGAINPERNMINCOMPARISONS
static SCIP_RETCODE greedyCliqueAlgorithm(SCIP *const scip, SCIP_VAR **items, SCIP_Longint *weights, int nitems, SCIP_Longint capacity, SCIP_Bool sorteditems, SCIP_Real cliqueextractfactor, SCIP_Bool *const cutoff, int *const nbdchgs)
#define DEFAULT_CLIQUEEXTRACTFACTOR
#define DEFAULT_SIMPLIFYINEQUALITIES
static SCIP_RETCODE eventdataFree(SCIP *scip, SCIP_EVENTDATA **eventdata)
static SCIP_RETCODE detectRedundantConstraints(SCIP *scip, BMS_BLKMEM *blkmem, SCIP_CONS **conss, int nconss, SCIP_Bool *cutoff, int *ndelconss)
static SCIP_RETCODE GUBsetCreate(SCIP *scip, SCIP_GUBSET **gubset, int nvars, SCIP_Longint *weights, SCIP_Longint capacity)
static SCIP_RETCODE getLiftingSequence(SCIP *scip, SCIP_Real *solvals, SCIP_Longint *weights, int *varsF, int *varsC2, int *varsR, int nvarsF, int nvarsC2, int nvarsR)
#define CONSHDLR_PROPFREQ
Definition: cons_knapsack.c:87
#define MAXNCLIQUEVARSCOMP
static SCIP_RETCODE tightenWeightsLift(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, SCIP_Bool *cutoff)
static SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphKnapsack)
static SCIP_RETCODE getFeasibleSet(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int *ncovervars, int *nnoncovervars, SCIP_Longint *coverweight, SCIP_Bool modtransused, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
static SCIP_DECL_CONSACTIVE(consActiveKnapsack)
#define NMINCOMPARISONS
static SCIP_RETCODE simplifyInequalities(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *ndelconss, int *nchgcoefs, int *nchgsides, int *naddconss, SCIP_Bool *cutoff)
enum GUBConsstatus GUBCONSSTATUS
static SCIP_RETCODE removeZeroWeights(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE catchEvents(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
#define CONSHDLR_PRESOLTIMING
Definition: cons_knapsack.c:95
static SCIP_RETCODE enforceConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_RESULT *result)
#define DEFAULT_MAXSEPACUTS
static SCIP_RETCODE superadditiveUpLifting(SCIP *scip, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int ncovervars, int nnoncovervars, SCIP_Longint coverweight, SCIP_Real *liftcoefs, SCIP_Real *cutact)
static SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
static SCIP_RETCODE addNlrow(SCIP *scip, SCIP_CONS *cons)
static void getPartitionNoncovervars(SCIP *scip, SCIP_Real *solvals, int *noncovervars, int nnoncovervars, int *varsF, int *varsR, int *nvarsF, int *nvarsR)
static SCIP_DECL_CONSFREE(consFreeKnapsack)
static SCIP_RETCODE stableSort(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR **vars, SCIP_Longint *weights, int *cliquestartposs, SCIP_Bool usenegatedclique)
static SCIP_RETCODE tightenWeights(SCIP *scip, SCIP_CONS *cons, SCIP_PRESOLTIMING presoltiming, int *nchgcoefs, int *nchgsides, int *naddconss, int *ndelconss, SCIP_Bool *cutoff)
#define CONSHDLR_EAGERFREQ
Definition: cons_knapsack.c:88
static void consdataChgWeight(SCIP_CONSDATA *consdata, int item, SCIP_Longint newweight)
static SCIP_RETCODE propagateCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff, SCIP_Bool *redundant, int *nfixedvars, SCIP_Bool usenegatedclique)
#define EVENTHDLR_DESC
Definition: cons_knapsack.c:99
#define KNAPSACKRELAX_MAXDNOM
#define USESUPADDLIFT
#define DEFAULT_MAXROUNDS
static SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
static SCIP_DECL_CONSLOCK(consLockKnapsack)
#define CONSHDLR_ENFOPRIORITY
Definition: cons_knapsack.c:84
#define MAXABSVBCOEF
static SCIP_DECL_CONSPARSE(consParseKnapsack)
#define LINCONSUPGD_PRIORITY
#define CONSHDLR_DELAYSEPA
Definition: cons_knapsack.c:91
#define MAX_USECLIQUES_SIZE
#define DEFAULT_UPDATECLIQUEPARTITIONS
GUBVarstatus
@ GUBVARSTATUS_BELONGSTOSET_F
@ GUBVARSTATUS_BELONGSTOSET_C1
@ GUBVARSTATUS_BELONGSTOSET_R
@ GUBVARSTATUS_BELONGSTOSET_C2
@ GUBVARSTATUS_CAPACITYEXCEEDED
@ GUBVARSTATUS_UNINITIAL
static SCIP_DECL_CONSINITPRE(consInitpreKnapsack)
#define CONSHDLR_NAME
Definition: cons_knapsack.c:81
#define EVENTHDLR_NAME
Definition: cons_knapsack.c:98
static SCIP_DECL_CONSDELETE(consDeleteKnapsack)
static SCIP_DECL_LINCONSUPGD(linconsUpgdKnapsack)
static SCIP_DECL_CONSENFORELAX(consEnforelaxKnapsack)
static SCIP_RETCODE checkParallelObjective(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata)
static SCIP_RETCODE GUBconsAddVar(SCIP *scip, SCIP_GUBCONS *gubcons, int var)
static SCIP_RETCODE changePartitionFeasiblesetvars(SCIP *scip, SCIP_Longint *weights, int *varsC1, int *varsC2, int *nvarsC1, int *nvarsC2)
#define DEFAULT_DISAGGREGATION
static SCIP_RETCODE preprocessConstraintPairs(SCIP *scip, SCIP_CONS **conss, int firstchange, int chkind, int *ndelconss)
static SCIP_RETCODE GUBconsDelVar(SCIP *scip, SCIP_GUBCONS *gubcons, int var, int gubvarsidx)
#define DEFAULT_DETECTLOWERBOUND
static SCIP_RETCODE dualPresolving(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *ndelconss, SCIP_Bool *deleted)
static SCIP_DECL_HASHKEYEQ(hashKeyEqKnapsackcons)
#define CONSHDLR_DELAYPROP
Definition: cons_knapsack.c:92
static SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)
#define EVENTTYPE_KNAPSACK
#define MAX_ZEROITEMS_SIZE
Constraint handler for knapsack constraints of the form , x binary and .
Constraint handler for linear constraints in their most general form, .
Constraint handler for logicor constraints (equivalent to set covering, but algorithms are suited fo...
Constraint handler for the set partitioning / packing / covering constraints .
#define NULL
Definition: def.h:248
#define SCIP_MAXSTRLEN
Definition: def.h:269
#define SCIP_Longint
Definition: def.h:141
#define SCIP_MAXTREEDEPTH
Definition: def.h:297
#define SCIP_INVALID
Definition: def.h:178
#define SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:224
#define SCIP_Real
Definition: def.h:156
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:220
#define SCIP_LONGINT_FORMAT
Definition: def.h:148
#define SCIPABORT()
Definition: def.h:327
#define REALABS(x)
Definition: def.h:182
#define SCIP_LONGINT_MAX
Definition: def.h:142
#define SCIP_CALL(x)
Definition: def.h:355
SCIP_RETCODE SCIPincludeLinconsUpgrade(SCIP *scip, SCIP_DECL_LINCONSUPGD((*linconsupgd)), int priority, const char *conshdlrname)
int SCIPgetNVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcreateRowKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcreateConsCardinality(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, int cardval, SCIP_VAR **indvars, SCIP_Real *weights, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPaddCoefKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
SCIP_RETCODE SCIPsolveKnapsackApproximately(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval)
SCIP_RETCODE SCIPcleanupConssKnapsack(SCIP *scip, SCIP_Bool onlychecked, SCIP_Bool *infeasible, int *ndelconss)
SCIP_RETCODE SCIPseparateKnapsackCuts(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_SOL *sol, SCIP_Bool usegubs, SCIP_Bool *cutoff, int *ncuts)
SCIP_RETCODE SCIPcreateConsSetpack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: cons_setppc.c:9460
SCIP_RETCODE SCIPcreateConsBasicKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
SCIP_RETCODE SCIPchgCapacityKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_Longint capacity)
SCIP_RETCODE SCIPseparateRelaxedKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, int nknapvars, SCIP_VAR **knapvars, SCIP_Real *knapvals, SCIP_Real valscale, SCIP_Real rhs, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
SCIP_RETCODE SCIPsolveKnapsackExactly(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval, SCIP_Bool *success)
SCIP_RETCODE SCIPcreateConsKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPcopyConsLinear(SCIP *scip, SCIP_CONS **cons, SCIP *sourcescip, const char *name, int nvars, SCIP_VAR **sourcevars, SCIP_Real *sourcecoefs, SCIP_Real lhs, SCIP_Real rhs, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode, SCIP_Bool global, SCIP_Bool *valid)
SCIP_Longint * SCIPgetWeightsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_Longint SCIPgetCapacityKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_VAR ** SCIPgetVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcreateConsLogicor(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_Real SCIPgetDualfarkasKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_ROW * SCIPgetRowKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPgetDualsolKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPincludeConshdlrKnapsack(SCIP *scip)
SCIP_Bool SCIPisConsCompressionEnabled(SCIP *scip)
Definition: scip_copy.c:662
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip_general.c:647
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
Definition: scip_general.c:668
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:759
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:444
int SCIPgetNObjVars(SCIP *scip)
Definition: scip_prob.c:2616
SCIP_RETCODE SCIPaddConsUpgrade(SCIP *scip, SCIP_CONS *oldcons, SCIP_CONS **newcons)
Definition: scip_prob.c:3368
int SCIPgetNContVars(SCIP *scip)
Definition: scip_prob.c:2569
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:2246
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3274
SCIP_CONS * SCIPfindOrigCons(SCIP *scip, const char *name)
Definition: scip_prob.c:3476
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3420
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:2201
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:3095
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3304
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3061
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3466
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3179
SCIP_RETCODE SCIPhashmapSetImageInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3400
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2348
#define SCIPhashSix(a, b, c, d, e, f)
Definition: pub_misc.h:580
SCIP_RETCODE SCIPhashtableCreate(SCIP_HASHTABLE **hashtable, BMS_BLKMEM *blkmem, int tablesize, SCIP_DECL_HASHGETKEY((*hashgetkey)), SCIP_DECL_HASHKEYEQ((*hashkeyeq)), SCIP_DECL_HASHKEYVAL((*hashkeyval)), void *userptr)
Definition: misc.c:2298
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition: misc.c:2596
SCIP_RETCODE SCIPhashtableRemove(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2665
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2535
SCIP_RETCODE SCIPupdateLocalLowerbound(SCIP *scip, SCIP_Real newbound)
Definition: scip_prob.c:4289
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:4067
SCIP_Real SCIPgetLocalLowerbound(SCIP *scip)
Definition: scip_prob.c:4178
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:208
#define SCIPdebugMsgPrint
Definition: scip_message.h:79
#define SCIPdebugMsg
Definition: scip_message.h:78
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition: misc.c:9197
SCIP_RETCODE SCIPcalcIntegralScalar(SCIP_Real *vals, int nvals, SCIP_Real mindelta, SCIP_Real maxdelta, SCIP_Longint maxdnom, SCIP_Real maxscale, SCIP_Real *intscalar, SCIP_Bool *success)
Definition: misc.c:9641
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:11162
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:83
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:139
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:57
int SCIPgetNLPBranchCands(SCIP *scip)
Definition: scip_branch.c:436
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
SCIP_RETCODE SCIPaddConflictBinvar(SCIP *scip, SCIP_VAR *var)
SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
int SCIPconshdlrGetNCheckConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4798
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip_cons.c:808
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons.c:4346
SCIP_CONS ** SCIPconshdlrGetCheckConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4755
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip_cons.c:540
SCIP_RETCODE SCIPsetConshdlrInit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINIT((*consinit)))
Definition: scip_cons.c:396
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip_cons.c:831
SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITPRE((*consinitpre)))
Definition: scip_cons.c:492
SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
Definition: scip_cons.c:235
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip_cons.c:281
SCIP_RETCODE SCIPincludeConshdlrBasic(SCIP *scip, SCIP_CONSHDLR **conshdlrptr, const char *name, const char *desc, int enfopriority, int chckpriority, int eagerfreq, SCIP_Bool needscons, SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition: scip_cons.c:181
SCIP_RETCODE SCIPsetConshdlrDeactive(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDEACTIVE((*consdeactive)))
Definition: scip_cons.c:693
SCIP_Longint SCIPconshdlrGetNCutsFound(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:5042
SCIP_RETCODE SCIPsetConshdlrGetPermsymGraph(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETPERMSYMGRAPH((*consgetpermsymgraph)))
Definition: scip_cons.c:900
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip_cons.c:578
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip_cons.c:372
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip_cons.c:323
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4316
SCIP_RETCODE SCIPsetConshdlrExit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXIT((*consexit)))
Definition: scip_cons.c:420
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip_cons.c:516
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip_cons.c:347
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:940
SCIP_RETCODE SCIPsetConshdlrGetSignedPermsymGraph(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH((*consgetsignedpermsymgraph)))
Definition: scip_cons.c:924
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip_cons.c:468
SCIP_RETCODE SCIPsetConshdlrDelvars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELVARS((*consdelvars)))
Definition: scip_cons.c:762
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip_cons.c:624
SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITSOL((*consinitsol)))
Definition: scip_cons.c:444
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4336
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip_cons.c:601
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
Definition: scip_cons.c:647
int SCIPconshdlrGetNActiveConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4812
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip_cons.c:854
int SCIPconshdlrGetSepaFreq(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:5272
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4735
SCIP_RETCODE SCIPsetConshdlrActive(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSACTIVE((*consactive)))
Definition: scip_cons.c:670
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip_cons.c:785
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8419
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8648
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8409
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8558
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip_cons.c:2536
int SCIPconsGetNUpgradeLocks(SCIP_CONS *cons)
Definition: cons.c:8841
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:8588
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:8518
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8698
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:8578
SCIP_RETCODE SCIPunmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:2042
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8450
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:8608
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8628
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8389
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:8638
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:8668
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:8568
SCIP_RETCODE SCIPincConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1784
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8658
SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition: scip_cut.c:117
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition: scip_cut.c:135
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:225
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip_event.c:111
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:1194
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:367
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:413
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:1217
#define SCIPfreeBuffer(scip, ptr)
Definition: scip_mem.h:134
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:110
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:57
#define SCIPallocClearBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:97
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition: scip_mem.h:126
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:139
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:128
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:136
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip_mem.h:132
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:93
#define SCIPallocBuffer(scip, ptr)
Definition: scip_mem.h:122
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:99
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:111
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip_mem.h:105
SCIP_RETCODE SCIPdelNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition: scip_nlp.c:424
SCIP_RETCODE SCIPaddNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition: scip_nlp.c:396
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition: scip_nlp.c:110
SCIP_RETCODE SCIPreleaseNlRow(SCIP *scip, SCIP_NLROW **nlrow)
Definition: scip_nlp.c:1058
SCIP_Bool SCIPnlrowIsInNLP(SCIP_NLROW *nlrow)
Definition: nlp.c:1953
SCIP_RETCODE SCIPcreateNlRow(SCIP *scip, SCIP_NLROW **nlrow, const char *name, SCIP_Real constant, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, SCIP_EXPR *expr, SCIP_Real lhs, SCIP_Real rhs, SCIP_EXPRCURV curvature)
Definition: scip_nlp.c:954
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:98
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1581
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONS *cons, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1398
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1604
SCIP_RETCODE SCIPcreateEmptyRowConshdlr(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1367
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1646
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2176
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1508
SCIP_RETCODE SCIPcreateEmptyRowSepa(SCIP *scip, SCIP_ROW **row, SCIP_SEPA *sepa, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1429
SCIP_RETCODE SCIPcreateEmptyRowUnspec(SCIP *scip, SCIP_ROW **row, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1458
SCIP_Real SCIProwGetDualfarkas(SCIP_ROW *row)
Definition: lp.c:17719
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:17917
SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
Definition: lp.c:17706
const char * SCIPsepaGetName(SCIP_SEPA *sepa)
Definition: sepa.c:746
SCIP_Longint SCIPsepaGetNCutsFound(SCIP_SEPA *sepa)
Definition: sepa.c:913
SCIP_RETCODE SCIPgetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip_sol.c:1846
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1765
void SCIPupdateSolLPConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition: scip_sol.c:469
SCIP_RETCODE SCIPupdateCutoffbound(SCIP *scip, SCIP_Real cutoffbound)
int SCIPgetNSepaRounds(SCIP *scip)
SCIP_Real SCIPgetLowerbound(SCIP *scip)
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPcutoffbounddelta(SCIP *scip)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPepsilon(SCIP *scip)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition: scip_tree.c:146
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:672
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:6401
int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition: var.c:24482
SCIP_Bool SCIPvarIsDeleted(SCIP_VAR *var)
Definition: var.c:23534
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:23843
SCIP_VAR * SCIPvarGetNegatedVar(SCIP_VAR *var)
Definition: var.c:23868
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition: var.c:24504
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:23642
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:23478
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:24568
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:23386
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:24268
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:23430
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:23900
SCIP_VAR * SCIPvarGetProbvar(SCIP_VAR *var)
Definition: var.c:17550
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:24142
SCIP_VAR ** SCIPvarGetImplVars(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:24585
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:23652
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:23662
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:23267
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:24514
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:24524
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:23490
SCIP_Real * SCIPvarGetImplBounds(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:24614
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:23806
int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition: var.c:23794
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:24642
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:24234
SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
Definition: var.c:23443
int SCIPgetNCliques(SCIP *scip)
Definition: scip_var.c:9512
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:24494
SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:24653
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:24120
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:17274
SCIP_RETCODE SCIPvarGetProbvarBinary(SCIP_VAR **var, SCIP_Bool *negated)
Definition: var.c:17642
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:24556
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:24536
SCIP_Bool SCIPvarsHaveCommonClique(SCIP_VAR *var1, SCIP_Bool value1, SCIP_VAR *var2, SCIP_Bool value2, SCIP_Bool regardimplics)
Definition: var.c:16807
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:24546
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:24600
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:17610
SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition: var.c:23818
void SCIPselectWeightedDownRealLongRealInt(SCIP_Real *realarray1, SCIP_Longint *longarray, SCIP_Real *realarray3, int *intarray, SCIP_Real *weights, SCIP_Real capacity, int len, int *medianpos)
void SCIPsortDownLongPtr(SCIP_Longint *longarray, void **ptrarray, int len)
void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
void SCIPsortPtrPtrIntInt(void **ptrarray1, void **ptrarray2, int *intarray1, int *intarray2, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
void SCIPsortPtrPtrLongIntInt(void **ptrarray1, void **ptrarray2, SCIP_Longint *longarray, int *intarray1, int *intarray2, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
void SCIPsortDownPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
void SCIPsortDownLongPtrPtrIntInt(SCIP_Longint *longarray, void **ptrarray1, void **ptrarray2, int *intarray1, int *intarray2, int len)
void SCIPsortRealInt(SCIP_Real *realarray, int *intarray, int len)
void SCIPsortDownRealIntLong(SCIP_Real *realarray, int *intarray, SCIP_Longint *longarray, int len)
void SCIPsortPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
void SCIPsortDownRealInt(SCIP_Real *realarray, int *intarray, int len)
void SCIPsortDownLongPtrInt(SCIP_Longint *longarray, void **ptrarray, int *intarray, int len)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10827
SCIP_RETCODE SCIPskipSpace(char **s)
Definition: misc.c:10816
SCIP_RETCODE SCIPgetSymActiveVariables(SCIP *scip, SYM_SYMTYPE symtype, SCIP_VAR ***vars, SCIP_Real **scalars, int *nvars, SCIP_Real *constant, SCIP_Bool transformed)
SCIP_RETCODE SCIPextendPermsymDetectionGraphLinear(SCIP *scip, SYM_GRAPH *graph, SCIP_VAR **vars, SCIP_Real *vals, int nvars, SCIP_CONS *cons, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool *success)
SCIP_VAR ** SCIPcliqueGetVars(SCIP_CLIQUE *clique)
Definition: implics.c:3384
int SCIPcliqueGetNVars(SCIP_CLIQUE *clique)
Definition: implics.c:3374
SCIP_Bool * SCIPcliqueGetValues(SCIP_CLIQUE *clique)
Definition: implics.c:3396
memory allocation routines
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:134
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:130
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:437
Rational & min(Rational &r1, Rational &r2)
public methods for managing constraints
public methods for managing events
public methods for implications, variable bounds, and cliques
public methods for LP management
public methods for message output
#define SCIPerrorMessage
Definition: pub_message.h:64
#define SCIPdebug(x)
Definition: pub_message.h:93
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:102
#define SCIPdebugMessage
Definition: pub_message.h:96
#define SCIPdebugPrintf
Definition: pub_message.h:99
public data structures and miscellaneous methods
methods for selecting (weighted) k-medians
methods for sorting joint arrays of various types
public methods for separators
public methods for problem variables
public methods for branching rule plugins and branching
public methods for conflict handler plugins and conflict analysis
public methods for constraint handler plugins and constraints
public methods for problem copies
public methods for cuts and aggregation rows
public methods for event handler plugins and event handlers
general public methods
public methods for the LP relaxation, rows and columns
public methods for memory management
public methods for message handling
public methods for nonlinear relaxation
public methods for numerical tolerances
public methods for SCIP parameter handling
public methods for global and local (sub)problems
public methods for the probing mode
public methods for solutions
public methods for querying solving statistics
public methods for the branch-and-bound tree
public methods for SCIP variables
static SCIP_RETCODE separate(SCIP *scip, SCIP_SEPA *sepa, SCIP_SOL *sol, SCIP_RESULT *result)
Main separation function.
Definition: sepa_flower.c:1221
GUBVARSTATUS * gubvarsstatus
GUBCONSSTATUS * gubconsstatus
int * gubvarsidx
int * gubconssidx
SCIP_GUBCONS ** gubconss
structs for symmetry computations
methods for dealing with symmetry detection graphs
@ SCIP_CONFTYPE_PROPAGATION
Definition: type_conflict.h:62
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:64
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:65
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:179
#define SCIP_EVENTTYPE_UBTIGHTENED
Definition: type_event.h:79
#define SCIP_EVENTTYPE_VARFIXED
Definition: type_event.h:72
#define SCIP_EVENTTYPE_VARDELETED
Definition: type_event.h:71
struct SCIP_EventhdlrData SCIP_EVENTHDLRDATA
Definition: type_event.h:160
#define SCIP_EVENTTYPE_LBRELAXED
Definition: type_event.h:78
#define SCIP_EVENTTYPE_FORMAT
Definition: type_event.h:157
#define SCIP_EVENTTYPE_IMPLADDED
Definition: type_event.h:85
#define SCIP_EVENTTYPE_LBTIGHTENED
Definition: type_event.h:77
@ SCIP_EXPRCURV_LINEAR
Definition: type_expr.h:65
@ SCIP_BOUNDTYPE_UPPER
Definition: type_lp.h:58
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:60
@ SCIP_DIDNOTRUN
Definition: type_result.h:42
@ SCIP_CUTOFF
Definition: type_result.h:48
@ SCIP_FEASIBLE
Definition: type_result.h:45
@ SCIP_REDUCEDDOM
Definition: type_result.h:51
@ SCIP_DIDNOTFIND
Definition: type_result.h:44
@ SCIP_SEPARATED
Definition: type_result.h:49
@ SCIP_SUCCESS
Definition: type_result.h:58
@ SCIP_INFEASIBLE
Definition: type_result.h:46
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:61
@ SCIP_INVALIDDATA
Definition: type_retcode.h:52
@ SCIP_PLUGINNOTFOUND
Definition: type_retcode.h:54
@ SCIP_NOMEMORY
Definition: type_retcode.h:44
@ SCIP_OKAY
Definition: type_retcode.h:42
@ SCIP_ERROR
Definition: type_retcode.h:43
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
@ SCIP_STAGE_PROBLEM
Definition: type_set.h:45
@ SCIP_STAGE_INITSOLVE
Definition: type_set.h:52
@ SCIP_STAGE_SOLVING
Definition: type_set.h:53
@ SCIP_STAGE_TRANSFORMING
Definition: type_set.h:46
enum SYM_Symtype SYM_SYMTYPE
Definition: type_symmetry.h:64
@ SYM_SYMTYPE_SIGNPERM
Definition: type_symmetry.h:62
@ SYM_SYMTYPE_PERM
Definition: type_symmetry.h:61
#define SCIP_PRESOLTIMING_MEDIUM
Definition: type_timing.h:53
unsigned int SCIP_PRESOLTIMING
Definition: type_timing.h:61
#define SCIP_PRESOLTIMING_FAST
Definition: type_timing.h:52
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition: type_timing.h:54
@ SCIP_VARSTATUS_FIXED
Definition: type_var.h:54
@ SCIP_VARSTATUS_MULTAGGR
Definition: type_var.h:56
@ SCIP_VARSTATUS_NEGATED
Definition: type_var.h:57
@ SCIP_VARSTATUS_AGGREGATED
Definition: type_var.h:55
@ SCIP_LOCKTYPE_MODEL
Definition: type_var.h:141