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-2024 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 SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
194 SCIP_Real maxcardbounddist; /**< maximal relative distance from current node's dual bound to primal bound compared
195 * to best node's dual bound for separating knapsack cuts */
196 int sepacardfreq; /**< multiplier on separation frequency, how often knapsack cuts are separated */
197 int maxrounds; /**< maximal number of separation rounds per node (-1: unlimited) */
198 int maxroundsroot; /**< maximal number of separation rounds in the root node (-1: unlimited) */
199 int maxsepacuts; /**< maximal number of cuts separated per separation round */
200 int maxsepacutsroot; /**< maximal number of cuts separated per separation round in the root node */
201 SCIP_Bool disaggregation; /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
202 SCIP_Bool simplifyinequalities;/**< should presolving try to cancel down or delete coefficients in inequalities */
203 SCIP_Bool negatedclique; /**< should negated clique information be used in solving process */
204 SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
205 SCIP_Bool presolusehashing; /**< should hash table be used for detecting redundant constraints in advance */
206 SCIP_Bool dualpresolving; /**< should dual presolving steps be performed? */
207 SCIP_Bool usegubs; /**< should GUB information be used for separation? */
208 SCIP_Bool detectcutoffbound; /**< should presolving try to detect constraints parallel to the objective
209 * function defining an upper bound and prevent these constraints from
210 * entering the LP */
211 SCIP_Bool detectlowerbound; /**< should presolving try to detect constraints parallel to the objective
212 * function defining a lower bound and prevent these constraints from
213 * entering the LP */
214 SCIP_Bool updatecliquepartitions; /**< should clique partition information be updated when old partition seems outdated? */
215 SCIP_Real cliqueextractfactor;/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
216 SCIP_Real clqpartupdatefac; /**< factor on the growth of global cliques to decide when to update a previous
217 * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
218#ifdef WITH_CARDINALITY_UPGRADE
219 SCIP_Bool upgdcardinality; /**< if TRUE then try to update knapsack constraints to cardinality constraints */
220 SCIP_Bool upgradedcard; /**< whether we have already upgraded knapsack constraints to cardinality constraints */
221#endif
222};
223
224
225/** constraint data for knapsack constraints */
226struct SCIP_ConsData
227{
228 SCIP_VAR** vars; /**< variables in knapsack constraint */
229 SCIP_Longint* weights; /**< weights of variables in knapsack constraint */
230 SCIP_EVENTDATA** eventdata; /**< event data for bound change events of the variables */
231 int* cliquepartition; /**< clique indices of the clique partition */
232 int* negcliquepartition; /**< clique indices of the negated clique partition */
233 SCIP_ROW* row; /**< corresponding LP row */
234 SCIP_NLROW* nlrow; /**< corresponding NLP row */
235 int nvars; /**< number of variables in knapsack constraint */
236 int varssize; /**< size of vars, weights, and eventdata arrays */
237 int ncliques; /**< number of cliques in the clique partition */
238 int nnegcliques; /**< number of cliques in the negated clique partition */
239 int ncliqueslastnegpart;/**< number of global cliques the last time a negated clique partition was computed */
240 int ncliqueslastpart; /**< number of global cliques the last time a clique partition was computed */
241 SCIP_Longint capacity; /**< capacity of knapsack */
242 SCIP_Longint weightsum; /**< sum of all weights */
243 SCIP_Longint onesweightsum; /**< sum of weights of variables fixed to one */
244 unsigned int presolvedtiming:5; /**< max level in which the knapsack constraint is already presolved */
245 unsigned int sorted:1; /**< are the knapsack items sorted by weight? */
246 unsigned int cliquepartitioned:1;/**< is the clique partition valid? */
247 unsigned int negcliquepartitioned:1;/**< is the negated clique partition valid? */
248 unsigned int merged:1; /**< are the constraint's equal variables already merged? */
249 unsigned int cliquesadded:1; /**< were the cliques of the knapsack already added to clique table? */
250 unsigned int varsdeleted:1; /**< were variables deleted after last cleanup? */
251 unsigned int existmultaggr:1; /**< does this constraint contain multi-aggregations */
252};
253
254/** event data for bound changes events */
255struct SCIP_EventData
256{
257 SCIP_CONS* cons; /**< knapsack constraint to process the bound change for */
258 SCIP_Longint weight; /**< weight of variable */
259 int filterpos; /**< position of event in variable's event filter */
260};
261
262
263/** data structure to combine two sorting key values */
264struct sortkeypair
265{
266 SCIP_Real key1; /**< first sort key value */
267 SCIP_Real key2; /**< second sort key value */
268};
269typedef struct sortkeypair SORTKEYPAIR;
270
271/** status of GUB constraint */
273{
274 GUBVARSTATUS_UNINITIAL = -1, /** unintitialized variable status */
275 GUBVARSTATUS_CAPACITYEXCEEDED = 0, /** variable with weight exceeding the knapsack capacity */
276 GUBVARSTATUS_BELONGSTOSET_R = 1, /** variable in noncovervars R */
277 GUBVARSTATUS_BELONGSTOSET_F = 2, /** variable in noncovervars F */
278 GUBVARSTATUS_BELONGSTOSET_C2 = 3, /** variable in covervars C2 */
279 GUBVARSTATUS_BELONGSTOSET_C1 = 4 /** variable in covervars C1 */
282
283/** status of variable in GUB constraint */
285{
286 GUBCONSSTATUS_UNINITIAL = -1, /** unintitialized GUB constraint status */
287 GUBCONSSTATUS_BELONGSTOSET_GR = 0, /** all GUB variables are in noncovervars R */
288 GUBCONSSTATUS_BELONGSTOSET_GF = 1, /** all GUB variables are in noncovervars F (and noncovervars R) */
289 GUBCONSSTATUS_BELONGSTOSET_GC2 = 2, /** all GUB variables are in covervars C2 */
290 GUBCONSSTATUS_BELONGSTOSET_GNC1 = 3, /** some GUB variables are in covervars C1, others in noncovervars R or F */
291 GUBCONSSTATUS_BELONGSTOSET_GOC1 = 4 /** all GUB variables are in covervars C1 */
294
295/** data structure of GUB constraints */
297{
298 int* gubvars; /**< indices of GUB variables in knapsack constraint */
299 GUBVARSTATUS* gubvarsstatus; /**< status of GUB variables */
300 int ngubvars; /**< number of GUB variables */
301 int gubvarssize; /**< size of gubvars array */
302};
304
305/** data structure of a set of GUB constraints */
307{
308 SCIP_GUBCONS** gubconss; /**< GUB constraints in GUB set */
309 GUBCONSSTATUS* gubconsstatus; /**< status of GUB constraints */
310 int ngubconss; /**< number of GUB constraints */
311 int nvars; /**< number of variables in knapsack constraint */
312 int* gubconssidx; /**< index of GUB constraint (in gubconss array) of each knapsack variable */
313 int* gubvarsidx; /**< index in GUB constraint (in gubvars array) of each knapsack variable */
314};
316
317/*
318 * Local methods
319 */
320
321/** comparison method for two sorting key pairs */
322static
323SCIP_DECL_SORTPTRCOMP(compSortkeypairs)
324{
325 SORTKEYPAIR* sortkeypair1 = (SORTKEYPAIR*)elem1;
326 SORTKEYPAIR* sortkeypair2 = (SORTKEYPAIR*)elem2;
327
328 if( sortkeypair1->key1 < sortkeypair2->key1 )
329 return -1;
330 else if( sortkeypair1->key1 > sortkeypair2->key1 )
331 return +1;
332 else if( sortkeypair1->key2 < sortkeypair2->key2 )
333 return -1;
334 else if( sortkeypair1->key2 > sortkeypair2->key2 )
335 return +1;
336 else
337 return 0;
338}
339
340/** creates event data */
341static
343 SCIP* scip, /**< SCIP data structure */
344 SCIP_EVENTDATA** eventdata, /**< pointer to store event data */
345 SCIP_CONS* cons, /**< constraint */
346 SCIP_Longint weight /**< weight of variable */
347 )
348{
349 assert(eventdata != NULL);
350
351 SCIP_CALL( SCIPallocBlockMemory(scip, eventdata) );
352 (*eventdata)->cons = cons;
353 (*eventdata)->weight = weight;
354
355 return SCIP_OKAY;
356}
357
358/** frees event data */
359static
361 SCIP* scip, /**< SCIP data structure */
362 SCIP_EVENTDATA** eventdata /**< pointer to event data */
363 )
364{
365 assert(eventdata != NULL);
366
367 SCIPfreeBlockMemory(scip, eventdata);
368
369 return SCIP_OKAY;
370}
371
372/** sorts items in knapsack with nonincreasing weights */
373static
375 SCIP_CONSDATA* consdata /**< constraint data */
376 )
377{
378 assert(consdata != NULL);
379 assert(consdata->nvars == 0 || consdata->vars != NULL);
380 assert(consdata->nvars == 0 || consdata->weights != NULL);
381 assert(consdata->nvars == 0 || consdata->eventdata != NULL);
382 assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
383
384 if( !consdata->sorted )
385 {
386 int pos;
387 int lastcliquenum;
388 int v;
389
390 /* sort of five joint arrays of Long/pointer/pointer/ints/ints,
391 * sorted by first array in non-increasing order via sort template */
393 consdata->weights,
394 (void**)consdata->vars,
395 (void**)consdata->eventdata,
396 consdata->cliquepartition,
397 consdata->negcliquepartition,
398 consdata->nvars);
399
400 v = consdata->nvars - 1;
401 /* sort all items with same weight according to their variable index, used for hash value for fast pairwise comparison of all constraints */
402 while( v >= 0 )
403 {
404 int w = v - 1;
405
406 while( w >= 0 && consdata->weights[v] == consdata->weights[w] )
407 --w;
408
409 if( v - w > 1 )
410 {
411 /* sort all corresponding parts of arrays for which the weights are equal by using the variable index */
413 (void**)(&(consdata->vars[w+1])),
414 (void**)(&(consdata->eventdata[w+1])),
415 &(consdata->cliquepartition[w+1]),
416 &(consdata->negcliquepartition[w+1]),
417 SCIPvarComp,
418 v - w);
419 }
420 v = w;
421 }
422
423 /* we need to make sure that our clique numbers of our normal clique will be in increasing order without gaps */
424 if( consdata->cliquepartitioned )
425 {
426 lastcliquenum = 0;
427
428 for( pos = 0; pos < consdata->nvars; ++pos )
429 {
430 /* if the clique number in the normal clique at position pos is greater than the last found clique number the
431 * partition is invalid */
432 if( consdata->cliquepartition[pos] > lastcliquenum )
433 {
434 consdata->cliquepartitioned = FALSE;
435 break;
436 }
437 else if( consdata->cliquepartition[pos] == lastcliquenum )
438 ++lastcliquenum;
439 }
440 }
441 /* we need to make sure that our clique numbers of our negated clique will be in increasing order without gaps */
442 if( consdata->negcliquepartitioned )
443 {
444 lastcliquenum = 0;
445
446 for( pos = 0; pos < consdata->nvars; ++pos )
447 {
448 /* if the clique number in the negated clique at position pos is greater than the last found clique number the
449 * partition is invalid */
450 if( consdata->negcliquepartition[pos] > lastcliquenum )
451 {
452 consdata->negcliquepartitioned = FALSE;
453 break;
454 }
455 else if( consdata->negcliquepartition[pos] == lastcliquenum )
456 ++lastcliquenum;
457 }
458 }
459
460 consdata->sorted = TRUE;
461 }
462#ifndef NDEBUG
463 {
464 /* check if the weight array is sorted in a non-increasing way */
465 int i;
466 for( i = 0; i < consdata->nvars-1; ++i )
467 assert(consdata->weights[i] >= consdata->weights[i+1]);
468 }
469#endif
470}
471
472/** calculates a partition of the variables into cliques */
473static
475 SCIP* scip, /**< SCIP data structure */
476 SCIP_CONSHDLRDATA* conshdlrdata, /**< knapsack constraint handler data */
477 SCIP_CONSDATA* consdata, /**< constraint data */
478 SCIP_Bool normalclique, /**< Should normal cliquepartition be created? */
479 SCIP_Bool negatedclique /**< Should negated cliquepartition be created? */
480 )
481{
482 SCIP_Bool ispartitionoutdated;
483 SCIP_Bool isnegpartitionoutdated;
484 assert(consdata != NULL);
485 assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
486
487 /* rerun eventually if number of global cliques increased considerably since last partition */
488 ispartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->ncliques > 1
489 && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastpart));
490
491 if( normalclique && ( !consdata->cliquepartitioned || ispartitionoutdated ) )
492 {
493 SCIP_CALL( SCIPcalcCliquePartition(scip, consdata->vars, consdata->nvars, consdata->cliquepartition, &consdata->ncliques) );
494 consdata->cliquepartitioned = TRUE;
495 consdata->ncliqueslastpart = SCIPgetNCliques(scip);
496 }
497
498 /* rerun eventually if number of global cliques increased considerably since last negated partition */
499 isnegpartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->nnegcliques > 1
500 && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastnegpart));
501
502 if( negatedclique && (!consdata->negcliquepartitioned || isnegpartitionoutdated) )
503 {
504 SCIP_CALL( SCIPcalcNegatedCliquePartition(scip, consdata->vars, consdata->nvars, consdata->negcliquepartition, &consdata->nnegcliques) );
505 consdata->negcliquepartitioned = TRUE;
506 consdata->ncliqueslastnegpart = SCIPgetNCliques(scip);
507 }
508 assert(!consdata->cliquepartitioned || consdata->ncliques <= consdata->nvars);
509 assert(!consdata->negcliquepartitioned || consdata->nnegcliques <= consdata->nvars);
510
511 return SCIP_OKAY;
512}
513
514/** installs rounding locks for the given variable in the given knapsack constraint */
515static
517 SCIP* scip, /**< SCIP data structure */
518 SCIP_CONS* cons, /**< knapsack constraint */
519 SCIP_VAR* var /**< variable of constraint entry */
520 )
521{
522 SCIP_CALL( SCIPlockVarCons(scip, var, cons, FALSE, TRUE) );
523
524 return SCIP_OKAY;
525}
526
527/** removes rounding locks for the given variable in the given knapsack constraint */
528static
530 SCIP* scip, /**< SCIP data structure */
531 SCIP_CONS* cons, /**< knapsack constraint */
532 SCIP_VAR* var /**< variable of constraint entry */
533 )
534{
535 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
536
537 return SCIP_OKAY;
538}
539
540/** catches bound change events for variables in knapsack */
541static
543 SCIP* scip, /**< SCIP data structure */
544 SCIP_CONS* cons, /**< constraint */
545 SCIP_CONSDATA* consdata, /**< constraint data */
546 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
547 )
548{
549 int i;
550
551 assert(cons != NULL);
552 assert(consdata != NULL);
553 assert(consdata->nvars == 0 || consdata->vars != NULL);
554 assert(consdata->nvars == 0 || consdata->weights != NULL);
555 assert(consdata->nvars == 0 || consdata->eventdata != NULL);
556
557 for( i = 0; i < consdata->nvars; i++)
558 {
559 SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[i], cons, consdata->weights[i]) );
561 eventhdlr, consdata->eventdata[i], &consdata->eventdata[i]->filterpos) );
562 }
563
564 return SCIP_OKAY;
565}
566
567/** drops bound change events for variables in knapsack */
568static
570 SCIP* scip, /**< SCIP data structure */
571 SCIP_CONSDATA* consdata, /**< constraint data */
572 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
573 )
574{
575 int i;
576
577 assert(consdata != NULL);
578 assert(consdata->nvars == 0 || consdata->vars != NULL);
579 assert(consdata->nvars == 0 || consdata->weights != NULL);
580 assert(consdata->nvars == 0 || consdata->eventdata != NULL);
581
582 for( i = 0; i < consdata->nvars; i++)
583 {
585 eventhdlr, consdata->eventdata[i], consdata->eventdata[i]->filterpos) );
586 SCIP_CALL( eventdataFree(scip, &consdata->eventdata[i]) );
587 }
588
589 return SCIP_OKAY;
590}
591
592/** ensures, that vars and vals arrays can store at least num entries */
593static
595 SCIP* scip, /**< SCIP data structure */
596 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
597 int num, /**< minimum number of entries to store */
598 SCIP_Bool transformed /**< is constraint from transformed problem? */
599 )
600{
601 assert(consdata != NULL);
602 assert(consdata->nvars <= consdata->varssize);
603
604 if( num > consdata->varssize )
605 {
606 int newsize;
607
608 newsize = SCIPcalcMemGrowSize(scip, num);
609 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) );
610 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->weights, consdata->varssize, newsize) );
611 if( transformed )
612 {
613 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->eventdata, consdata->varssize, newsize) );
614 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->cliquepartition, consdata->varssize, newsize) );
615 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->negcliquepartition, consdata->varssize, newsize) );
616 }
617 else
618 {
619 assert(consdata->eventdata == NULL);
620 assert(consdata->cliquepartition == NULL);
621 assert(consdata->negcliquepartition == NULL);
622 }
623 consdata->varssize = newsize;
624 }
625 assert(num <= consdata->varssize);
626
627 return SCIP_OKAY;
628}
629
630/** updates all weight sums for fixed and unfixed variables */
631static
633 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
634 SCIP_VAR* var, /**< variable for this weight */
635 SCIP_Longint weightdelta /**< difference between the old and the new weight of the variable */
636 )
637{
638 assert(consdata != NULL);
639 assert(var != NULL);
640
641 consdata->weightsum += weightdelta;
642
643 if( SCIPvarGetLbLocal(var) > 0.5 )
644 consdata->onesweightsum += weightdelta;
645
646 assert(consdata->weightsum >= 0);
647 assert(consdata->onesweightsum >= 0);
648}
649
650/** creates knapsack constraint data */
651static
653 SCIP* scip, /**< SCIP data structure */
654 SCIP_CONSDATA** consdata, /**< pointer to store constraint data */
655 int nvars, /**< number of variables in knapsack */
656 SCIP_VAR** vars, /**< variables of knapsack */
657 SCIP_Longint* weights, /**< weights of knapsack items */
658 SCIP_Longint capacity /**< capacity of knapsack */
659 )
660{
661 int v;
662 SCIP_Longint constant;
663
664 assert(consdata != NULL);
665
666 SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
667
668 constant = 0L;
669 (*consdata)->vars = NULL;
670 (*consdata)->weights = NULL;
671 (*consdata)->nvars = 0;
672 if( nvars > 0 )
673 {
674 SCIP_VAR** varsbuffer;
675 SCIP_Longint* weightsbuffer;
676 int k;
677
678 SCIP_CALL( SCIPallocBufferArray(scip, &varsbuffer, nvars) );
679 SCIP_CALL( SCIPallocBufferArray(scip, &weightsbuffer, nvars) );
680
681 k = 0;
682 for( v = 0; v < nvars; ++v )
683 {
684 assert(vars[v] != NULL);
685 assert(SCIPvarIsBinary(vars[v]));
686
687 /* all weight have to be non negative */
688 assert( weights[v] >= 0 );
689
690 if( weights[v] > 0 )
691 {
692 /* treat fixed variables as constants if problem compression is enabled */
694 {
695 /* only if the variable is fixed to 1, we add its weight to the constant */
696 if( SCIPvarGetUbGlobal(vars[v]) > 0.5 )
697 constant += weights[v];
698 }
699 else
700 {
701 varsbuffer[k] = vars[v];
702 weightsbuffer[k] = weights[v];
703 ++k;
704 }
705 }
706 }
707 assert(k >= 0);
708 assert(constant >= 0);
709
710 (*consdata)->nvars = k;
711
712 /* copy the active variables and weights into the constraint data structure */
713 if( k > 0 )
714 {
715 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, varsbuffer, k) );
716 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->weights, weightsbuffer, k) );
717 }
718
719 /* free buffer storage */
720 SCIPfreeBufferArray(scip, &weightsbuffer);
721 SCIPfreeBufferArray(scip, &varsbuffer);
722 }
723
724 (*consdata)->varssize = (*consdata)->nvars;
725 (*consdata)->capacity = capacity - constant;
726 (*consdata)->eventdata = NULL;
727 (*consdata)->cliquepartition = NULL;
728 (*consdata)->negcliquepartition = NULL;
729 (*consdata)->row = NULL;
730 (*consdata)->nlrow = NULL;
731 (*consdata)->weightsum = 0;
732 (*consdata)->onesweightsum = 0;
733 (*consdata)->ncliques = 0;
734 (*consdata)->nnegcliques = 0;
735 (*consdata)->presolvedtiming = 0;
736 (*consdata)->sorted = FALSE;
737 (*consdata)->cliquepartitioned = FALSE;
738 (*consdata)->negcliquepartitioned = FALSE;
739 (*consdata)->ncliqueslastpart = -1;
740 (*consdata)->ncliqueslastnegpart = -1;
741 (*consdata)->merged = FALSE;
742 (*consdata)->cliquesadded = FALSE;
743 (*consdata)->varsdeleted = FALSE;
744 (*consdata)->existmultaggr = FALSE;
745
746 /* get transformed variables, if we are in the transformed problem */
748 {
749 SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
750
751 for( v = 0; v < (*consdata)->nvars; v++ )
752 {
753 SCIP_VAR* var = SCIPvarGetProbvar((*consdata)->vars[v]);
754 assert(var != NULL);
755 (*consdata)->existmultaggr = (*consdata)->existmultaggr || (SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
756 }
757
758 /* allocate memory for additional data structures */
759 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->nvars) );
760 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->nvars) );
761 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->nvars) );
762 }
763
764 /* calculate sum of weights and capture variables */
765 for( v = 0; v < (*consdata)->nvars; ++v )
766 {
767 /* calculate sum of weights */
768 updateWeightSums(*consdata, (*consdata)->vars[v], (*consdata)->weights[v]);
769
770 /* capture variables */
771 SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) );
772 }
773 return SCIP_OKAY;
774}
775
776/** frees knapsack constraint data */
777static
779 SCIP* scip, /**< SCIP data structure */
780 SCIP_CONSDATA** consdata, /**< pointer to the constraint data */
781 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
782 )
783{
784 assert(consdata != NULL);
785 assert(*consdata != NULL);
786
787 if( (*consdata)->row != NULL )
788 {
789 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->row) );
790 }
791 if( (*consdata)->nlrow != NULL )
792 {
793 SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
794 }
795 if( (*consdata)->eventdata != NULL )
796 {
797 SCIP_CALL( dropEvents(scip, *consdata, eventhdlr) );
798 SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->varssize);
799 }
800 if( (*consdata)->negcliquepartition != NULL )
801 {
802 SCIPfreeBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->varssize);
803 }
804 if( (*consdata)->cliquepartition != NULL )
805 {
806 SCIPfreeBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->varssize);
807 }
808 if( (*consdata)->vars != NULL )
809 {
810 int v;
811
812 /* release variables */
813 for( v = 0; v < (*consdata)->nvars; v++ )
814 {
815 assert((*consdata)->vars[v] != NULL);
816 SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->vars[v])) );
817 }
818
819 assert( (*consdata)->weights != NULL );
820 assert( (*consdata)->varssize > 0 );
821 SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->varssize);
822 SCIPfreeBlockMemoryArray(scip, &(*consdata)->weights, (*consdata)->varssize);
823 }
824
825 SCIPfreeBlockMemory(scip, consdata);
826
827 return SCIP_OKAY;
828}
829
830/** changes a single weight in knapsack constraint data */
831static
833 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
834 int item, /**< item number */
835 SCIP_Longint newweight /**< new weight of item */
836 )
837{
838 SCIP_Longint oldweight;
839 SCIP_Longint weightdiff;
840
841 assert(consdata != NULL);
842 assert(0 <= item && item < consdata->nvars);
843
844 oldweight = consdata->weights[item];
845 weightdiff = newweight - oldweight;
846 consdata->weights[item] = newweight;
847
848 /* update weight sums for all and fixed variables */
849 updateWeightSums(consdata, consdata->vars[item], weightdiff);
850
851 if( consdata->eventdata != NULL )
852 {
853 assert(consdata->eventdata[item] != NULL);
854 assert(consdata->eventdata[item]->weight == oldweight);
855 consdata->eventdata[item]->weight = newweight;
856 }
857
858 consdata->presolvedtiming = 0;
859 consdata->sorted = FALSE;
860
861 /* recalculate cliques extraction after a weight was increased */
862 if( oldweight < newweight )
863 {
864 consdata->cliquesadded = FALSE;
865 }
866}
867
868/** creates LP row corresponding to knapsack constraint */
869static
871 SCIP* scip, /**< SCIP data structure */
872 SCIP_CONS* cons /**< knapsack constraint */
873 )
874{
875 SCIP_CONSDATA* consdata;
876 int i;
877
878 consdata = SCIPconsGetData(cons);
879 assert(consdata != NULL);
880 assert(consdata->row == NULL);
881
882 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, cons, SCIPconsGetName(cons),
883 -SCIPinfinity(scip), (SCIP_Real)consdata->capacity,
885
886 SCIP_CALL( SCIPcacheRowExtensions(scip, consdata->row) );
887 for( i = 0; i < consdata->nvars; ++i )
888 {
889 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, consdata->vars[i], (SCIP_Real)consdata->weights[i]) );
890 }
891 SCIP_CALL( SCIPflushRowExtensions(scip, consdata->row) );
892
893 return SCIP_OKAY;
894}
895
896/** adds linear relaxation of knapsack constraint to the LP */
897static
899 SCIP* scip, /**< SCIP data structure */
900 SCIP_CONS* cons, /**< knapsack constraint */
901 SCIP_Bool* cutoff /**< whether a cutoff has been detected */
902 )
903{
904 SCIP_CONSDATA* consdata;
905
906 assert( cutoff != NULL );
907 *cutoff = FALSE;
908
909 consdata = SCIPconsGetData(cons);
910 assert(consdata != NULL);
911
912 if( consdata->row == NULL )
913 {
915 }
916 assert(consdata->row != NULL);
917
918 /* insert LP row as cut */
919 if( !SCIProwIsInLP(consdata->row) )
920 {
921 SCIPdebugMsg(scip, "adding relaxation of knapsack constraint <%s> (capacity %" SCIP_LONGINT_FORMAT "): ",
922 SCIPconsGetName(cons), consdata->capacity);
923 SCIPdebug( SCIP_CALL(SCIPprintRow(scip, consdata->row, NULL)) );
924 SCIP_CALL( SCIPaddRow(scip, consdata->row, FALSE, cutoff) );
925 }
926
927 return SCIP_OKAY;
928}
929
930/** adds knapsack constraint as row to the NLP, if not added yet */
931static
933 SCIP* scip, /**< SCIP data structure */
934 SCIP_CONS* cons /**< knapsack constraint */
935 )
936{
937 SCIP_CONSDATA* consdata;
938
939 assert(SCIPisNLPConstructed(scip));
940
941 /* skip deactivated, redundant, or local linear constraints (the NLP does not allow for local rows at the moment) */
942 if( !SCIPconsIsActive(cons) || !SCIPconsIsChecked(cons) || SCIPconsIsLocal(cons) )
943 return SCIP_OKAY;
944
945 consdata = SCIPconsGetData(cons);
946 assert(consdata != NULL);
947
948 if( consdata->nlrow == NULL )
949 {
950 SCIP_Real* coefs;
951 int i;
952
953 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, consdata->nvars) );
954 for( i = 0; i < consdata->nvars; ++i )
955 coefs[i] = (SCIP_Real)consdata->weights[i]; /*lint !e613*/
956
957 SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
958 consdata->nvars, consdata->vars, coefs, NULL,
959 -SCIPinfinity(scip), (SCIP_Real)consdata->capacity, SCIP_EXPRCURV_LINEAR) );
960
961 assert(consdata->nlrow != NULL);
962
963 SCIPfreeBufferArray(scip, &coefs);
964 }
965
966 if( !SCIPnlrowIsInNLP(consdata->nlrow) )
967 {
968 SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
969 }
970
971 return SCIP_OKAY;
972}
973
974/** checks knapsack constraint for feasibility of given solution: returns TRUE iff constraint is feasible */
975static
977 SCIP* scip, /**< SCIP data structure */
978 SCIP_CONS* cons, /**< constraint to check */
979 SCIP_SOL* sol, /**< solution to check, NULL for current solution */
980 SCIP_Bool checklprows, /**< Do constraints represented by rows in the current LP have to be checked? */
981 SCIP_Bool printreason, /**< Should the reason for the violation be printed? */
982 SCIP_Bool* violated /**< pointer to store whether the constraint is violated */
983 )
984{
985 SCIP_CONSDATA* consdata;
986
987 assert(violated != NULL);
988
989 consdata = SCIPconsGetData(cons);
990 assert(consdata != NULL);
991
992 SCIPdebugMsg(scip, "checking knapsack constraint <%s> for feasibility of solution %p (lprows=%u)\n",
993 SCIPconsGetName(cons), (void*)sol, checklprows);
994
995 *violated = FALSE;
996
997 if( checklprows || consdata->row == NULL || !SCIProwIsInLP(consdata->row) )
998 {
999 SCIP_Real normsum = 0.0;
1000 SCIP_Real hugesum = 0.0;
1001 SCIP_Real absviol;
1002 SCIP_Real relviol;
1003 int v;
1004
1005 /* increase age of constraint; age is reset to zero, if a violation was found only in case we are in
1006 * enforcement
1007 */
1008 if( sol == NULL )
1009 {
1010 SCIP_CALL( SCIPincConsAge(scip, cons) );
1011 }
1012
1013 /* sum separately over normal and huge weight contributions in order to reduce numerical cancellation */
1014 for( v = consdata->nvars - 1; v >= 0; --v )
1015 {
1016 assert(SCIPvarIsBinary(consdata->vars[v]));
1017
1018 if( SCIPisHugeValue(scip, (SCIP_Real)consdata->weights[v]) )
1019 hugesum += consdata->weights[v] * SCIPgetSolVal(scip, sol, consdata->vars[v]);
1020 else
1021 normsum += consdata->weights[v] * SCIPgetSolVal(scip, sol, consdata->vars[v]);
1022 }
1023
1024 /* calculate constraint violation and update it in solution */
1025 normsum += hugesum;
1026
1027 if( normsum > consdata->capacity )
1028 {
1029 absviol = normsum - consdata->capacity;
1030 relviol = SCIPrelDiff(normsum, (SCIP_Real)consdata->capacity);
1031 }
1032 else
1033 {
1034 absviol = 0.0;
1035 relviol = 0.0;
1036 }
1037
1038 if( sol != NULL )
1039 SCIPupdateSolLPConsViolation(scip, sol, absviol, relviol);
1040
1041 if( SCIPisFeasPositive(scip, absviol) )
1042 {
1043 *violated = TRUE;
1044
1045 /* only reset constraint age if we are in enforcement */
1046 if( sol == NULL )
1047 {
1049 }
1050
1051 if( printreason )
1052 {
1053 SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
1054
1055 SCIPinfoMessage(scip, NULL, ";\n");
1056 SCIPinfoMessage(scip, NULL, "violation: the capacity is violated by %.15g\n", absviol);
1057 }
1058 }
1059 }
1060
1061 return SCIP_OKAY;
1062}
1063
1064/* IDX computes the integer index for the optimal solution array */
1065#define IDX(j,d) ((j)*(intcap)+(d))
1066
1067/** solves knapsack problem in maximization form exactly using dynamic programming;
1068 * if needed, one can provide arrays to store all selected items and all not selected items
1069 *
1070 * @note in case you provide the solitems or nonsolitems array you also have to provide the counter part, as well
1071 *
1072 * @note the algorithm will first compute a greedy solution and terminate
1073 * if the greedy solution is proven to be optimal.
1074 * The dynamic programming algorithm runs with a time and space complexity
1075 * of O(nitems * capacity).
1076 *
1077 * @todo If only the objective is relevant, it is easy to change the code to use only one slice with O(capacity) space.
1078 * There are recursive methods (see the book by Kellerer et al.) that require O(capacity) space, but it remains
1079 * to be checked whether they are faster and whether they can reconstruct the solution.
1080 * Dembo and Hammer (see Kellerer et al. Section 5.1.3, page 126) found a method that relies on a fast probing method.
1081 * This fixes additional elements to 0 or 1 similar to a reduced cost fixing.
1082 * This could be implemented, however, it would be technically a bit cumbersome,
1083 * since one needs the greedy solution and the LP-value for this.
1084 * This is currently only available after the redundant items have already been sorted out.
1085 */
1087 SCIP* scip, /**< SCIP data structure */
1088 int nitems, /**< number of available items */
1089 SCIP_Longint* weights, /**< item weights */
1090 SCIP_Real* profits, /**< item profits */
1091 SCIP_Longint capacity, /**< capacity of knapsack */
1092 int* items, /**< item numbers */
1093 int* solitems, /**< array to store items in solution, or NULL */
1094 int* nonsolitems, /**< array to store items not in solution, or NULL */
1095 int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1096 int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1097 SCIP_Real* solval, /**< pointer to store optimal solution value, or NULL */
1098 SCIP_Bool* success /**< pointer to store if an error occured during solving
1099 * (normally a memory problem) */
1100 )
1101{
1102 SCIP_RETCODE retcode;
1103 SCIP_Real* tempsort;
1104 SCIP_Real* optvalues;
1105 int intcap;
1106 int d;
1107 int j;
1108 int greedymedianpos;
1109 SCIP_Longint weightsum;
1110 int* myitems;
1111 SCIP_Longint* myweights;
1112 SCIP_Real* realweights;
1113 int* allcurrminweight;
1114 SCIP_Real* myprofits;
1115 int nmyitems;
1116 SCIP_Longint gcd;
1117 SCIP_Longint minweight;
1118 SCIP_Longint maxweight;
1119 int currminweight;
1120 SCIP_Longint greedysolweight;
1121 SCIP_Real greedysolvalue;
1122 SCIP_Real greedyupperbound;
1123 SCIP_Bool eqweights;
1124 SCIP_Bool intprofits;
1125
1126 assert(weights != NULL);
1127 assert(profits != NULL);
1128 assert(capacity >= 0);
1129 assert(items != NULL);
1130 assert(nitems >= 0);
1131 assert(success != NULL);
1132
1133 *success = TRUE;
1134
1135#ifndef NDEBUG
1136 for( j = nitems - 1; j >= 0; --j )
1137 assert(weights[j] >= 0);
1138#endif
1139
1140 SCIPdebugMsg(scip, "Solving knapsack exactly.\n");
1141
1142 /* initializing solution value */
1143 if( solval != NULL )
1144 *solval = 0.0;
1145
1146 /* init solution information */
1147 if( solitems != NULL )
1148 {
1149 assert(items != NULL);
1150 assert(nsolitems != NULL);
1151 assert(nonsolitems != NULL);
1152 assert(nnonsolitems != NULL);
1153
1154 *nnonsolitems = 0;
1155 *nsolitems = 0;
1156 }
1157
1158 /* allocate temporary memory */
1159 SCIP_CALL( SCIPallocBufferArray(scip, &myweights, nitems) );
1160 SCIP_CALL( SCIPallocBufferArray(scip, &myprofits, nitems) );
1161 SCIP_CALL( SCIPallocBufferArray(scip, &myitems, nitems) );
1162 nmyitems = 0;
1163 weightsum = 0;
1164 minweight = SCIP_LONGINT_MAX;
1165 maxweight = 0;
1166
1167 /* remove unnecessary items */
1168 for( j = 0; j < nitems; ++j )
1169 {
1170 assert(0 <= weights[j] && weights[j] < SCIP_LONGINT_MAX);
1171
1172 /* item does not fit */
1173 if( weights[j] > capacity )
1174 {
1175 if( solitems != NULL )
1176 nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
1177 }
1178 /* item is not profitable */
1179 else if( profits[j] <= 0.0 )
1180 {
1181 if( solitems != NULL )
1182 nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
1183 }
1184 /* item always fits */
1185 else if( weights[j] == 0 )
1186 {
1187 if( solitems != NULL )
1188 solitems[(*nsolitems)++] = items[j]; /*lint !e413*/
1189
1190 if( solval != NULL )
1191 *solval += profits[j];
1192 }
1193 /* all important items */
1194 else
1195 {
1196 myweights[nmyitems] = weights[j];
1197 myprofits[nmyitems] = profits[j];
1198 myitems[nmyitems] = items[j];
1199
1200 /* remember smallest item */
1201 if( myweights[nmyitems] < minweight )
1202 minweight = myweights[nmyitems];
1203
1204 /* remember bigest item */
1205 if( myweights[nmyitems] > maxweight )
1206 maxweight = myweights[nmyitems];
1207
1208 weightsum += myweights[nmyitems];
1209 ++nmyitems;
1210 }
1211 }
1212
1213 intprofits = TRUE;
1214 /* check if all profits are integer to strengthen the upper bound on the greedy solution */
1215 for( j = 0; j < nmyitems && intprofits; ++j )
1216 intprofits = intprofits && SCIPisIntegral(scip, myprofits[j]);
1217
1218 /* if no item is left then goto end */
1219 if( nmyitems == 0 )
1220 {
1221 SCIPdebugMsg(scip, "After preprocessing no items are left.\n");
1222
1223 goto TERMINATE;
1224 }
1225
1226 /* if all items fit, we also do not need to do the expensive stuff later on */
1227 if( weightsum > 0 && weightsum <= capacity )
1228 {
1229 SCIPdebugMsg(scip, "After preprocessing all items fit into knapsack.\n");
1230
1231 for( j = nmyitems - 1; j >= 0; --j )
1232 {
1233 if( solitems != NULL )
1234 solitems[(*nsolitems)++] = myitems[j]; /*lint !e413*/
1235
1236 if( solval != NULL )
1237 *solval += myprofits[j];
1238 }
1239
1240 goto TERMINATE;
1241 }
1242
1243 assert(0 < minweight && minweight <= capacity );
1244 assert(0 < maxweight && maxweight <= capacity);
1245
1246 /* make weights relatively prime */
1247 eqweights = TRUE;
1248 if( maxweight > 1 )
1249 {
1250 /* determine greatest common divisor */
1251 gcd = myweights[nmyitems - 1];
1252 for( j = nmyitems - 2; j >= 0 && gcd >= 2; --j )
1253 gcd = SCIPcalcGreComDiv(gcd, myweights[j]);
1254
1255 SCIPdebugMsg(scip, "Gcd is %" SCIP_LONGINT_FORMAT ".\n", gcd);
1256
1257 /* divide by greatest common divisor */
1258 if( gcd > 1 )
1259 {
1260 for( j = nmyitems - 1; j >= 0; --j )
1261 {
1262 myweights[j] /= gcd;
1263 eqweights = eqweights && (myweights[j] == 1);
1264 }
1265 capacity /= gcd;
1266 minweight /= gcd;
1267 }
1268 else
1269 eqweights = FALSE;
1270 }
1271 assert(minweight <= capacity);
1272
1273 /* if only one item fits, then take the best */
1274 if( minweight > capacity / 2 )
1275 {
1276 int p;
1277
1278 SCIPdebugMsg(scip, "Only one item fits into knapsack, so take the best.\n");
1279
1280 p = nmyitems - 1;
1281
1282 /* find best item */
1283 for( j = nmyitems - 2; j >= 0; --j )
1284 {
1285 if( myprofits[j] > myprofits[p] )
1286 p = j;
1287 }
1288
1289 /* update solution information */
1290 if( solitems != NULL )
1291 {
1292 assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1293
1294 solitems[(*nsolitems)++] = myitems[p];
1295 for( j = nmyitems - 1; j >= 0; --j )
1296 {
1297 if( j != p )
1298 nonsolitems[(*nnonsolitems)++] = myitems[j];
1299 }
1300 }
1301 /* update solution value */
1302 if( solval != NULL )
1303 *solval += myprofits[p];
1304
1305 goto TERMINATE;
1306 }
1307
1308 /* if all items have the same weight, then take the best */
1309 if( eqweights )
1310 {
1311 SCIP_Real addval = 0.0;
1312
1313 SCIPdebugMsg(scip, "All weights are equal, so take the best.\n");
1314
1315 SCIPsortDownRealIntLong(myprofits, myitems, myweights, nmyitems);
1316
1317 /* update solution information */
1318 if( solitems != NULL || solval != NULL )
1319 {
1320 SCIP_Longint i;
1321
1322 /* if all items would fit we had handled this case before */
1323 assert((SCIP_Longint) nmyitems > capacity);
1324 assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1325
1326 /* take the first best items into the solution */
1327 for( i = capacity - 1; i >= 0; --i )
1328 {
1329 if( solitems != NULL )
1330 solitems[(*nsolitems)++] = myitems[i];
1331 addval += myprofits[i];
1332 }
1333
1334 if( solitems != NULL )
1335 {
1336 /* the rest are not in the solution */
1337 for( i = nmyitems - 1; i >= capacity; --i )
1338 nonsolitems[(*nnonsolitems)++] = myitems[i];
1339 }
1340 }
1341 /* update solution value */
1342 if( solval != NULL )
1343 {
1344 assert(addval > 0.0);
1345 *solval += addval;
1346 }
1347
1348 goto TERMINATE;
1349 }
1350
1351 SCIPdebugMsg(scip, "Determine greedy solution.\n");
1352
1353 /* sort myitems (plus corresponding arrays myweights and myprofits) such that
1354 * p_1/w_1 >= p_2/w_2 >= ... >= p_n/w_n, this is only used for the greedy solution
1355 */
1356 SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nmyitems) );
1357 SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nmyitems) );
1358
1359 for( j = 0; j < nmyitems; ++j )
1360 {
1361 tempsort[j] = myprofits[j]/((SCIP_Real) myweights[j]);
1362 realweights[j] = (SCIP_Real)myweights[j];
1363 }
1364
1365 SCIPselectWeightedDownRealLongRealInt(tempsort, myweights, myprofits, myitems, realweights,
1366 (SCIP_Real)capacity, nmyitems, &greedymedianpos);
1367
1368 SCIPfreeBufferArray(scip, &realweights);
1369 SCIPfreeBufferArray(scip, &tempsort);
1370
1371 /* initialize values for greedy solution information */
1372 greedysolweight = 0;
1373 greedysolvalue = 0.0;
1374
1375 /* determine greedy solution */
1376 for( j = 0; j < greedymedianpos; ++j )
1377 {
1378 assert(myweights[j] <= capacity);
1379
1380 /* update greedy solution weight and value */
1381 greedysolweight += myweights[j];
1382 greedysolvalue += myprofits[j];
1383 }
1384
1385 assert(0 < greedysolweight && greedysolweight <= capacity);
1386 assert(greedysolvalue > 0.0);
1387
1388 /* If the greedy solution is optimal by comparing to the LP solution, we take this solution. This happens if:
1389 * - the greedy solution reaches the capacity, because then the LP solution is integral;
1390 * - the greedy solution has an objective that is at least the LP value rounded down in case that all profits are integer, too. */
1391 greedyupperbound = greedysolvalue + myprofits[j] * (SCIP_Real) (capacity - greedysolweight)/((SCIP_Real) myweights[j]);
1392 if( intprofits )
1393 greedyupperbound = SCIPfloor(scip, greedyupperbound);
1394 if( greedysolweight == capacity || SCIPisGE(scip, greedysolvalue, greedyupperbound) )
1395 {
1396 SCIPdebugMsg(scip, "Greedy solution is optimal.\n");
1397
1398 /* update solution information */
1399 if( solitems != NULL )
1400 {
1401 int l;
1402
1403 assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1404
1405 /* collect items */
1406 for( l = 0; l < j; ++l )
1407 solitems[(*nsolitems)++] = myitems[l];
1408 for ( ; l < nmyitems; ++l )
1409 nonsolitems[(*nnonsolitems)++] = myitems[l];
1410 }
1411 /* update solution value */
1412 if( solval != NULL )
1413 {
1414 assert(greedysolvalue > 0.0);
1415 *solval += greedysolvalue;
1416 }
1417
1418 goto TERMINATE;
1419 }
1420
1421 /* in the following table we do not need the first minweight columns */
1422 capacity -= (minweight - 1);
1423
1424 /* we can only handle integers */
1425 if( capacity >= INT_MAX )
1426 {
1427 SCIPdebugMsg(scip, "Capacity is to big, so we cannot handle it here.\n");
1428
1429 *success = FALSE;
1430 goto TERMINATE;
1431 }
1432 assert(capacity < INT_MAX);
1433
1434 intcap = (int)capacity;
1435 assert(intcap >= 0);
1436 assert(nmyitems > 0);
1437 assert(sizeof(size_t) >= sizeof(int)); /*lint !e506*/ /* no following conversion should be messed up */
1438
1439 /* this condition checks whether we will try to allocate a correct number of bytes and do not have an overflow, while
1440 * computing the size for the allocation
1441 */
1442 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*/
1443 {
1444 SCIPdebugMsg(scip, "Too much memory (%lu) would be consumed.\n", (unsigned long) (((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues))); /*lint !e571*/
1445
1446 *success = FALSE;
1447 goto TERMINATE;
1448 }
1449
1450 /* allocate temporary memory and check for memory exceedance */
1451 retcode = SCIPallocBufferArray(scip, &optvalues, nmyitems * intcap);
1452 if( retcode == SCIP_NOMEMORY )
1453 {
1454 SCIPdebugMsg(scip, "Did not get enough memory.\n");
1455
1456 *success = FALSE;
1457 goto TERMINATE;
1458 }
1459 else
1460 {
1461 SCIP_CALL( retcode );
1462 }
1463
1464 SCIPdebugMsg(scip, "Start real exact algorithm.\n");
1465
1466 /* we memorize at each step the current minimal weight to later on know which value in our optvalues matrix is valid;
1467 * each value entries of the j-th row of optvalues is valid if the index is >= allcurrminweight[j], otherwise it is
1468 * invalid; a second possibility would be to clear the whole optvalues, which should be more expensive than storing
1469 * 'nmyitem' values
1470 */
1471 SCIP_CALL( SCIPallocBufferArray(scip, &allcurrminweight, nmyitems) );
1472 assert(myweights[0] - minweight < INT_MAX);
1473 currminweight = (int) (myweights[0] - minweight);
1474 allcurrminweight[0] = currminweight;
1475
1476 /* fills first row of dynamic programming table with optimal values */
1477 for( d = currminweight; d < intcap; ++d )
1478 optvalues[d] = myprofits[0];
1479
1480 /* fills dynamic programming table with optimal values */
1481 for( j = 1; j < nmyitems; ++j )
1482 {
1483 int intweight;
1484
1485 /* compute important part of weight, which will be represented in the table */
1486 intweight = (int)(myweights[j] - minweight);
1487 assert(0 <= intweight && intweight < intcap);
1488
1489 /* copy all nonzeros from row above */
1490 for( d = currminweight; d < intweight && d < intcap; ++d )
1491 optvalues[IDX(j,d)] = optvalues[IDX(j-1,d)];
1492
1493 /* update corresponding row */
1494 for( d = intweight; d < intcap; ++d )
1495 {
1496 /* if index d < current minweight then optvalues[IDX(j-1,d)] is not initialized, i.e. should be 0 */
1497 if( d < currminweight )
1498 optvalues[IDX(j,d)] = myprofits[j];
1499 else
1500 {
1501 SCIP_Real sumprofit;
1502
1503 if( d - myweights[j] < currminweight )
1504 sumprofit = myprofits[j];
1505 else
1506 sumprofit = optvalues[IDX(j-1,(int)(d-myweights[j]))] + myprofits[j];
1507
1508 optvalues[IDX(j,d)] = MAX(sumprofit, optvalues[IDX(j-1,d)]);
1509 }
1510 }
1511
1512 /* update currminweight */
1513 if( intweight < currminweight )
1514 currminweight = intweight;
1515
1516 allcurrminweight[j] = currminweight;
1517 }
1518
1519 /* update optimal solution by following the table */
1520 if( solitems != NULL )
1521 {
1522 assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1523 d = intcap - 1;
1524
1525 SCIPdebugMsg(scip, "Fill the solution vector after solving exactly.\n");
1526
1527 /* insert all items in (non-) solution vector */
1528 for( j = nmyitems - 1; j > 0; --j )
1529 {
1530 /* if the following condition holds this means all remaining items does not fit anymore */
1531 if( d < allcurrminweight[j] )
1532 {
1533 /* we cannot have exceeded our capacity */
1534 assert((SCIP_Longint) d >= -minweight);
1535 break;
1536 }
1537
1538 /* collect solution items; the first condition means that no further item can fit anymore, but this does */
1539 if( d < allcurrminweight[j-1] || optvalues[IDX(j,d)] > optvalues[IDX(j-1,d)] )
1540 {
1541 solitems[(*nsolitems)++] = myitems[j];
1542
1543 /* check that we do not have an underflow */
1544 assert(myweights[j] <= (INT_MAX + (SCIP_Longint) d));
1545 d = (int)(d - myweights[j]);
1546 }
1547 /* collect non-solution items */
1548 else
1549 nonsolitems[(*nnonsolitems)++] = myitems[j];
1550 }
1551
1552 /* insert remaining items */
1553 if( d >= allcurrminweight[j] )
1554 {
1555 assert(j == 0);
1556 solitems[(*nsolitems)++] = myitems[j];
1557 }
1558 else
1559 {
1560 assert(j >= 0);
1561 assert(d < allcurrminweight[j]);
1562
1563 for( ; j >= 0; --j )
1564 nonsolitems[(*nnonsolitems)++] = myitems[j];
1565 }
1566
1567 assert(*nsolitems + *nnonsolitems == nitems);
1568 }
1569
1570 /* update solution value */
1571 if( solval != NULL )
1572 *solval += optvalues[IDX(nmyitems-1,intcap-1)];
1573 SCIPfreeBufferArray(scip, &allcurrminweight);
1574
1575 /* free all temporary memory */
1576 SCIPfreeBufferArray(scip, &optvalues);
1577
1578 TERMINATE:
1579 SCIPfreeBufferArray(scip, &myitems);
1580 SCIPfreeBufferArray(scip, &myprofits);
1581 SCIPfreeBufferArray(scip, &myweights);
1582
1583 return SCIP_OKAY;
1584}
1585
1586/** solves knapsack problem in maximization form approximately by solving the LP-relaxation of the problem using Dantzig's
1587 * method and rounding down the solution; if needed, one can provide arrays to store all selected items and all not
1588 * selected items
1589 */
1591 SCIP* scip, /**< SCIP data structure */
1592 int nitems, /**< number of available items */
1593 SCIP_Longint* weights, /**< item weights */
1594 SCIP_Real* profits, /**< item profits */
1595 SCIP_Longint capacity, /**< capacity of knapsack */
1596 int* items, /**< item numbers */
1597 int* solitems, /**< array to store items in solution, or NULL */
1598 int* nonsolitems, /**< array to store items not in solution, or NULL */
1599 int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1600 int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1601 SCIP_Real* solval /**< pointer to store optimal solution value, or NULL */
1602 )
1603{
1604 SCIP_Real* tempsort;
1605 SCIP_Longint solitemsweight;
1606 SCIP_Real* realweights;
1607 int j;
1608 int criticalindex;
1609
1610 assert(weights != NULL);
1611 assert(profits != NULL);
1612 assert(capacity >= 0);
1613 assert(items != NULL);
1614 assert(nitems >= 0);
1615
1616 if( solitems != NULL )
1617 {
1618 *nsolitems = 0;
1619 *nnonsolitems = 0;
1620 }
1621 if( solval != NULL )
1622 *solval = 0.0;
1623
1624 /* initialize data for median search */
1625 SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nitems) );
1626 SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nitems) );
1627 for( j = nitems - 1; j >= 0; --j )
1628 {
1629 tempsort[j] = profits[j]/((SCIP_Real) weights[j]);
1630 realweights[j] = (SCIP_Real)weights[j];
1631 }
1632
1633 /* partially sort indices such that all elements that are larger than the break item appear first */
1634 SCIPselectWeightedDownRealLongRealInt(tempsort, weights, profits, items, realweights, (SCIP_Real)capacity, nitems, &criticalindex);
1635
1636 /* selects items as long as they fit into the knapsack */
1637 solitemsweight = 0;
1638 for( j = 0; j < nitems && solitemsweight + weights[j] <= capacity; ++j )
1639 {
1640 if( solitems != NULL )
1641 solitems[(*nsolitems)++] = items[j];
1642
1643 if( solval != NULL )
1644 (*solval) += profits[j];
1645 solitemsweight += weights[j];
1646 }
1647 if ( solitems != NULL )
1648 {
1649 for( ; j < nitems; j++ )
1650 nonsolitems[(*nnonsolitems)++] = items[j];
1651 }
1652
1653 SCIPfreeBufferArray(scip, &realweights);
1654 SCIPfreeBufferArray(scip, &tempsort);
1655
1656 return SCIP_OKAY;
1657}
1658
1659#ifdef SCIP_DEBUG
1660/** prints all nontrivial GUB constraints and their LP solution values */
1661static
1662void GUBsetPrint(
1663 SCIP* scip, /**< SCIP data structure */
1664 SCIP_GUBSET* gubset, /**< GUB set data structure */
1665 SCIP_VAR** vars, /**< variables in knapsack constraint */
1666 SCIP_Real* solvals /**< solution values of variables in knapsack constraint; or NULL */
1667 )
1668{
1669 int nnontrivialgubconss;
1670 int c;
1671
1672 nnontrivialgubconss = 0;
1673
1674 SCIPdebugMsg(scip, " Nontrivial GUBs of current GUB set:\n");
1675
1676 /* print out all nontrivial GUB constraints, i.e., with more than one variable */
1677 for( c = 0; c < gubset->ngubconss; c++ )
1678 {
1679 SCIP_Real gubsolval;
1680
1681 assert(gubset->gubconss[c]->ngubvars >= 0);
1682
1683 /* nontrivial GUB */
1684 if( gubset->gubconss[c]->ngubvars > 1 )
1685 {
1686 int v;
1687
1688 gubsolval = 0.0;
1689 SCIPdebugMsg(scip, " GUB<%d>:\n", c);
1690
1691 /* print GUB var */
1692 for( v = 0; v < gubset->gubconss[c]->ngubvars; v++ )
1693 {
1694 int currentvar;
1695
1696 currentvar = gubset->gubconss[c]->gubvars[v];
1697 if( solvals != NULL )
1698 {
1699 gubsolval += solvals[currentvar];
1700 SCIPdebugMsg(scip, " +<%s>(%4.2f)\n", SCIPvarGetName(vars[currentvar]), solvals[currentvar]);
1701 }
1702 else
1703 {
1704 SCIPdebugMsg(scip, " +<%s>\n", SCIPvarGetName(vars[currentvar]));
1705 }
1706 }
1707
1708 /* check whether LP solution satisfies the GUB constraint */
1709 if( solvals != NULL )
1710 {
1711 SCIPdebugMsg(scip, " =%4.2f <= 1 %s\n", gubsolval,
1712 SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1713 }
1714 else
1715 {
1716 SCIPdebugMsg(scip, " <= 1 %s\n", SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1717 }
1718 nnontrivialgubconss++;
1719 }
1720 }
1721
1722 SCIPdebugMsg(scip, " --> %d/%d nontrivial GUBs\n", nnontrivialgubconss, gubset->ngubconss);
1723}
1724#endif
1725
1726/** creates an empty GUB constraint */
1727static
1729 SCIP* scip, /**< SCIP data structure */
1730 SCIP_GUBCONS** gubcons /**< pointer to store GUB constraint data */
1731 )
1732{
1733 assert(scip != NULL);
1734 assert(gubcons != NULL);
1735
1736 /* allocate memory for GUB constraint data structures */
1737 SCIP_CALL( SCIPallocBuffer(scip, gubcons) );
1738 (*gubcons)->gubvarssize = GUBCONSGROWVALUE;
1739 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvars, (*gubcons)->gubvarssize) );
1740 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvarsstatus, (*gubcons)->gubvarssize) );
1741
1742 (*gubcons)->ngubvars = 0;
1743
1744 return SCIP_OKAY;
1745}
1746
1747/** frees GUB constraint */
1748static
1750 SCIP* scip, /**< SCIP data structure */
1751 SCIP_GUBCONS** gubcons /**< pointer to GUB constraint data structure */
1752 )
1753{
1754 assert(scip != NULL);
1755 assert(gubcons != NULL);
1756 assert((*gubcons)->gubvars != NULL);
1757 assert((*gubcons)->gubvarsstatus != NULL);
1758
1759 /* free allocated memory */
1760 SCIPfreeBufferArray(scip, &(*gubcons)->gubvarsstatus);
1761 SCIPfreeBufferArray(scip, &(*gubcons)->gubvars);
1762 SCIPfreeBuffer(scip, gubcons);
1763}
1764
1765/** adds variable to given GUB constraint */
1766static
1768 SCIP* scip, /**< SCIP data structure */
1769 SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1770 int var /**< index of given variable in knapsack constraint */
1771 )
1772{
1773 assert(scip != NULL);
1774 assert(gubcons != NULL);
1775 assert(gubcons->ngubvars >= 0 && gubcons->ngubvars < gubcons->gubvarssize);
1776 assert(gubcons->gubvars != NULL);
1777 assert(gubcons->gubvarsstatus != NULL);
1778 assert(var >= 0);
1779
1780 /* add variable to GUB constraint */
1781 gubcons->gubvars[gubcons->ngubvars] = var;
1782 gubcons->gubvarsstatus[gubcons->ngubvars] = GUBVARSTATUS_UNINITIAL;
1783 gubcons->ngubvars++;
1784
1785 /* increase space allocated to GUB constraint if the number of variables reaches the size */
1786 if( gubcons->ngubvars == gubcons->gubvarssize )
1787 {
1788 int newlen;
1789
1790 newlen = gubcons->gubvarssize + GUBCONSGROWVALUE;
1791 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1792 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1793
1794 gubcons->gubvarssize = newlen;
1795 }
1796
1797 return SCIP_OKAY;
1798}
1799
1800/** deletes variable from its current GUB constraint */
1801static
1803 SCIP* scip, /**< SCIP data structure */
1804 SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1805 int var, /**< index of given variable in knapsack constraint */
1806 int gubvarsidx /**< index of the variable in its current GUB constraint */
1807 )
1808{
1809 assert(scip != NULL);
1810 assert(gubcons != NULL);
1811 assert(var >= 0);
1812 assert(gubvarsidx >= 0 && gubvarsidx < gubcons->ngubvars);
1813 assert(gubcons->ngubvars >= gubvarsidx+1);
1814 assert(gubcons->gubvars[gubvarsidx] == var);
1815
1816 /* delete variable from GUB by swapping it replacing in by the last variable in the GUB constraint */
1817 gubcons->gubvars[gubvarsidx] = gubcons->gubvars[gubcons->ngubvars-1];
1818 gubcons->gubvarsstatus[gubvarsidx] = gubcons->gubvarsstatus[gubcons->ngubvars-1];
1819 gubcons->ngubvars--;
1820
1821 /* decrease space allocated for the GUB constraint, if the last GUBCONSGROWVALUE+1 array entries are now empty */
1822 if( gubcons->ngubvars < gubcons->gubvarssize - GUBCONSGROWVALUE && gubcons->ngubvars > 0 )
1823 {
1824 int newlen;
1825
1826 newlen = gubcons->gubvarssize - GUBCONSGROWVALUE;
1827
1828 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1829 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1830
1831 gubcons->gubvarssize = newlen;
1832 }
1833
1834 return SCIP_OKAY;
1835}
1836
1837/** moves variable from current GUB constraint to a different existing (nonempty) GUB constraint */
1838static
1840 SCIP* scip, /**< SCIP data structure */
1841 SCIP_GUBSET* gubset, /**< GUB set data structure */
1842 SCIP_VAR** vars, /**< variables in knapsack constraint */
1843 int var, /**< index of given variable in knapsack constraint */
1844 int oldgubcons, /**< index of old GUB constraint of given variable */
1845 int newgubcons /**< index of new GUB constraint of given variable */
1846 )
1847{
1848 int oldgubvaridx;
1849 int replacevar;
1850 int j;
1851
1852 assert(scip != NULL);
1853 assert(gubset != NULL);
1854 assert(var >= 0);
1855 assert(oldgubcons >= 0 && oldgubcons < gubset->ngubconss);
1856 assert(newgubcons >= 0 && newgubcons < gubset->ngubconss);
1857 assert(oldgubcons != newgubcons);
1858 assert(gubset->gubconssidx[var] == oldgubcons);
1859 assert(gubset->gubconss[oldgubcons]->ngubvars > 0);
1860 assert(gubset->gubconss[newgubcons]->ngubvars >= 0);
1861
1862 SCIPdebugMsg(scip, " moving variable<%s> from GUB<%d> to GUB<%d>\n", SCIPvarGetName(vars[var]), oldgubcons, newgubcons);
1863
1864 oldgubvaridx = gubset->gubvarsidx[var];
1865
1866 /* delete variable from old GUB constraint by replacing it by the last variable of the GUB constraint */
1867 SCIP_CALL( GUBconsDelVar(scip, gubset->gubconss[oldgubcons], var, oldgubvaridx) );
1868
1869 /* in GUB set, update stored index of variable in old GUB constraint for the variable used for replacement;
1870 * replacement variable is given by old position of the deleted variable
1871 */
1872 replacevar = gubset->gubconss[oldgubcons]->gubvars[oldgubvaridx];
1873 assert(gubset->gubvarsidx[replacevar] == gubset->gubconss[oldgubcons]->ngubvars);
1874 gubset->gubvarsidx[replacevar] = oldgubvaridx;
1875
1876 /* add variable to the end of new GUB constraint */
1877 SCIP_CALL( GUBconsAddVar(scip, gubset->gubconss[newgubcons], var) );
1878 assert(gubset->gubconss[newgubcons]->gubvars[gubset->gubconss[newgubcons]->ngubvars-1] == var);
1879
1880 /* in GUB set, update stored index of GUB of moved variable and stored index of variable in this GUB constraint */
1881 gubset->gubconssidx[var] = newgubcons;
1882 gubset->gubvarsidx[var] = gubset->gubconss[newgubcons]->ngubvars-1;
1883
1884 /* delete old GUB constraint if it became empty */
1885 if( gubset->gubconss[oldgubcons]->ngubvars == 0 )
1886 {
1887 SCIPdebugMsg(scip, "deleting empty GUB cons<%d> from current GUB set\n", oldgubcons);
1888#ifdef SCIP_DEBUG
1889 GUBsetPrint(scip, gubset, vars, NULL);
1890#endif
1891
1892 /* free old GUB constraint */
1893 GUBconsFree(scip, &gubset->gubconss[oldgubcons]);
1894
1895 /* if empty GUB was not the last one in GUB set data structure, replace it by last GUB constraint */
1896 if( oldgubcons != gubset->ngubconss-1 )
1897 {
1898 gubset->gubconss[oldgubcons] = gubset->gubconss[gubset->ngubconss-1];
1899 gubset->gubconsstatus[oldgubcons] = gubset->gubconsstatus[gubset->ngubconss-1];
1900
1901 /* in GUB set, update stored index of GUB constraint for all variable of the GUB constraint used for replacement;
1902 * replacement GUB is given by old position of the deleted GUB
1903 */
1904 for( j = 0; j < gubset->gubconss[oldgubcons]->ngubvars; j++ )
1905 {
1906 assert(gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] == gubset->ngubconss-1);
1907 gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] = oldgubcons;
1908 }
1909 }
1910
1911 /* update number of GUB constraints */
1912 gubset->ngubconss--;
1913
1914 /* variable should be at given new position, unless new GUB constraint replaced empty old GUB constraint
1915 * (because it was at the end of the GUB constraint array)
1916 */
1917 assert(gubset->gubconssidx[var] == newgubcons
1918 || (newgubcons == gubset->ngubconss && gubset->gubconssidx[var] == oldgubcons));
1919 }
1920#ifndef NDEBUG
1921 else
1922 assert(gubset->gubconssidx[var] == newgubcons);
1923#endif
1924
1925 return SCIP_OKAY;
1926}
1927
1928/** swaps two variables in the same GUB constraint */
1929static
1931 SCIP* scip, /**< SCIP data structure */
1932 SCIP_GUBSET* gubset, /**< GUB set data structure */
1933 int var1, /**< first variable to be swapped */
1934 int var2 /**< second variable to be swapped */
1935 )
1936{
1937 int gubcons;
1938 int var1idx;
1939 GUBVARSTATUS var1status;
1940 int var2idx;
1941 GUBVARSTATUS var2status;
1942
1943 assert(scip != NULL);
1944 assert(gubset != NULL);
1945
1946 gubcons = gubset->gubconssidx[var1];
1947 assert(gubcons == gubset->gubconssidx[var2]);
1948
1949 /* nothing to be done if both variables are the same */
1950 if( var1 == var2 )
1951 return;
1952
1953 /* swap index and status of variables in GUB constraint */
1954 var1idx = gubset->gubvarsidx[var1];
1955 var1status = gubset->gubconss[gubcons]->gubvarsstatus[var1idx];
1956 var2idx = gubset->gubvarsidx[var2];
1957 var2status = gubset->gubconss[gubcons]->gubvarsstatus[var2idx];
1958
1959 gubset->gubvarsidx[var1] = var2idx;
1960 gubset->gubconss[gubcons]->gubvars[var1idx] = var2;
1961 gubset->gubconss[gubcons]->gubvarsstatus[var1idx] = var2status;
1962
1963 gubset->gubvarsidx[var2] = var1idx;
1964 gubset->gubconss[gubcons]->gubvars[var2idx] = var1;
1965 gubset->gubconss[gubcons]->gubvarsstatus[var2idx] = var1status;
1966}
1967
1968/** initializes partition of knapsack variables into nonoverlapping trivial GUB constraints (GUB with one variable) */
1969static
1971 SCIP* scip, /**< SCIP data structure */
1972 SCIP_GUBSET** gubset, /**< pointer to store GUB set data structure */
1973 int nvars, /**< number of variables in the knapsack constraint */
1974 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
1975 SCIP_Longint capacity /**< capacity of knapsack */
1976 )
1977{
1978 int i;
1979
1980 assert(scip != NULL);
1981 assert(gubset != NULL);
1982 assert(nvars > 0);
1983 assert(weights != NULL);
1984 assert(capacity >= 0);
1985
1986 /* allocate memory for GUB set data structures */
1987 SCIP_CALL( SCIPallocBuffer(scip, gubset) );
1988 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconss, nvars) );
1989 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconsstatus, nvars) );
1990 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconssidx, nvars) );
1991 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubvarsidx, nvars) );
1992 (*gubset)->ngubconss = nvars;
1993 (*gubset)->nvars = nvars;
1994
1995 /* initialize the set of GUB constraints */
1996 for( i = 0; i < nvars; i++ )
1997 {
1998 /* assign each variable to a new (trivial) GUB constraint */
1999 SCIP_CALL( GUBconsCreate(scip, &(*gubset)->gubconss[i]) );
2000 SCIP_CALL( GUBconsAddVar(scip, (*gubset)->gubconss[i], i) );
2001
2002 /* set status of GUB constraint to initial */
2003 (*gubset)->gubconsstatus[i] = GUBCONSSTATUS_UNINITIAL;
2004
2005 (*gubset)->gubconssidx[i] = i;
2006 (*gubset)->gubvarsidx[i] = 0;
2007 assert((*gubset)->gubconss[i]->ngubvars == 1);
2008
2009 /* already updated status of variable in GUB constraint if it exceeds the capacity of the knapsack */
2010 if( weights[i] > capacity )
2011 (*gubset)->gubconss[(*gubset)->gubconssidx[i]]->gubvarsstatus[(*gubset)->gubvarsidx[i]] = GUBVARSTATUS_CAPACITYEXCEEDED;
2012 }
2013
2014 return SCIP_OKAY;
2015}
2016
2017/** frees GUB set data structure */
2018static
2020 SCIP* scip, /**< SCIP data structure */
2021 SCIP_GUBSET** gubset /**< pointer to GUB set data structure */
2022 )
2023{
2024 int i;
2025
2026 assert(scip != NULL);
2027 assert(gubset != NULL);
2028 assert((*gubset)->gubconss != NULL);
2029 assert((*gubset)->gubconsstatus != NULL);
2030 assert((*gubset)->gubconssidx != NULL);
2031 assert((*gubset)->gubvarsidx != NULL);
2032
2033 /* free all GUB constraints */
2034 for( i = (*gubset)->ngubconss-1; i >= 0; --i )
2035 {
2036 assert((*gubset)->gubconss[i] != NULL);
2037 GUBconsFree(scip, &(*gubset)->gubconss[i]);
2038 }
2039
2040 /* free allocated memory */
2041 SCIPfreeBufferArray( scip, &(*gubset)->gubvarsidx );
2042 SCIPfreeBufferArray( scip, &(*gubset)->gubconssidx );
2043 SCIPfreeBufferArray( scip, &(*gubset)->gubconsstatus );
2044 SCIPfreeBufferArray( scip, &(*gubset)->gubconss );
2045 SCIPfreeBuffer(scip, gubset);
2046}
2047
2048#ifndef NDEBUG
2049/** checks whether GUB set data structure is consistent */
2050static
2052 SCIP* scip, /**< SCIP data structure */
2053 SCIP_GUBSET* gubset, /**< GUB set data structure */
2054 SCIP_VAR** vars /**< variables in the knapsack constraint */
2055 )
2056{
2057 int i;
2058 int gubconsidx;
2059 int gubvaridx;
2060 SCIP_VAR* var1;
2061 SCIP_VAR* var2;
2062 SCIP_Bool var1negated;
2063 SCIP_Bool var2negated;
2064
2065 assert(scip != NULL);
2066 assert(gubset != NULL);
2067
2068 SCIPdebugMsg(scip, " GUB set consistency check:\n");
2069
2070 /* checks for all knapsack vars consistency of stored index of associated gubcons and corresponding index in gubvars */
2071 for( i = 0; i < gubset->nvars; i++ )
2072 {
2073 gubconsidx = gubset->gubconssidx[i];
2074 gubvaridx = gubset->gubvarsidx[i];
2075
2076 if( gubset->gubconss[gubconsidx]->gubvars[gubvaridx] != i )
2077 {
2078 SCIPdebugMsg(scip, " var<%d> should be in GUB<%d> at position<%d>, but stored is var<%d> instead\n", i,
2079 gubconsidx, gubvaridx, gubset->gubconss[gubconsidx]->gubvars[gubvaridx] );
2080 }
2081 assert(gubset->gubconss[gubconsidx]->gubvars[gubvaridx] == i);
2082 }
2083
2084 /* checks for each GUB whether all pairs of its variables have a common clique */
2085 for( i = 0; i < gubset->ngubconss; i++ )
2086 {
2087 int j;
2088
2089 for( j = 0; j < gubset->gubconss[i]->ngubvars; j++ )
2090 {
2091 int k;
2092
2093 /* get corresponding active problem variable */
2094 var1 = vars[gubset->gubconss[i]->gubvars[j]];
2095 var1negated = FALSE;
2096 SCIP_CALL( SCIPvarGetProbvarBinary(&var1, &var1negated) );
2097
2098 for( k = j+1; k < gubset->gubconss[i]->ngubvars; k++ )
2099 {
2100 /* get corresponding active problem variable */
2101 var2 = vars[gubset->gubconss[i]->gubvars[k]];
2102 var2negated = FALSE;
2103 SCIP_CALL( SCIPvarGetProbvarBinary(&var2, &var2negated) );
2104
2105 if( !SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE) )
2106 {
2107 SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2108 SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[j]]), k,
2109 SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[k]]));
2110 SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2111 SCIPvarGetName(var1), k,
2112 SCIPvarGetName(var2));
2113 }
2114
2115 /* @todo: in case we used also negated cliques for the GUB partition, this assert has to be changed */
2116 assert(SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE));
2117 }
2118 }
2119 }
2120 SCIPdebugMsg(scip, " --> successful\n");
2121
2122 return SCIP_OKAY;
2123}
2124#endif
2125
2126/** calculates a partition of the given set of binary variables into cliques;
2127 * afterwards the output array contains one value for each variable, such that two variables got the same value iff they
2128 * were assigned to the same clique;
2129 * the first variable is always assigned to clique 0, and a variable can only be assigned to clique i if at least one of
2130 * the preceding variables was assigned to clique i-1;
2131 * note: in contrast to SCIPcalcCliquePartition(), variables with LP value 1 are put into trivial cliques (with one
2132 * variable) and for the remaining variables, a partition with a small number of cliques is constructed
2133 */
2134
2135static
2137 SCIP*const scip, /**< SCIP data structure */
2138 SCIP_VAR**const vars, /**< binary variables in the clique from which at most one can be set to 1 */
2139 int const nvars, /**< number of variables in the clique */
2140 int*const cliquepartition, /**< array of length nvars to store the clique partition */
2141 int*const ncliques, /**< pointer to store number of cliques actually contained in the partition */
2142 SCIP_Real* solvals /**< solution values of all given binary variables */
2143 )
2144{
2145 SCIP_VAR** tmpvars;
2146 SCIP_VAR** cliquevars;
2147 SCIP_Bool* cliquevalues;
2148 SCIP_Bool* tmpvalues;
2149 int* varseq;
2150 int* sortkeys;
2151 int ncliquevars;
2152 int maxncliquevarscomp;
2153 int nignorevars;
2154 int nvarsused;
2155 int i;
2156
2157 assert(scip != NULL);
2158 assert(nvars == 0 || vars != NULL);
2159 assert(nvars == 0 || cliquepartition != NULL);
2160 assert(ncliques != NULL);
2161
2162 if( nvars == 0 )
2163 {
2164 *ncliques = 0;
2165 return SCIP_OKAY;
2166 }
2167
2168 /* allocate temporary memory for storing the variables of the current clique */
2169 SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
2170 SCIP_CALL( SCIPallocBufferArray(scip, &cliquevalues, nvars) );
2171 SCIP_CALL( SCIPallocBufferArray(scip, &tmpvalues, nvars) );
2172 SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpvars, vars, nvars) );
2174 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvars) );
2175
2176 /* initialize the cliquepartition array with -1 */
2177 /* initialize the tmpvalues array */
2178 for( i = nvars - 1; i >= 0; --i )
2179 {
2180 tmpvalues[i] = TRUE;
2181 cliquepartition[i] = -1;
2182 }
2183
2184 /* get corresponding active problem variables */
2185 SCIP_CALL( SCIPvarsGetProbvarBinary(&tmpvars, &tmpvalues, nvars) );
2186
2187 /* ignore variables with LP value 1 (will be assigned to trivial GUBs at the end) and sort remaining variables
2188 * by nondecreasing number of cliques the variables are in
2189 */
2190 nignorevars = 0;
2191 nvarsused = 0;
2192 for( i = 0; i < nvars; i++ )
2193 {
2194 if( SCIPisFeasEQ(scip, solvals[i], 1.0) )
2195 {
2196 /* variables with LP value 1 are put to the end of varseq array and will not be sorted */
2197 varseq[nvars-1-nignorevars] = i;
2198 nignorevars++;
2199 }
2200 else
2201 {
2202 /* remaining variables are put to the front of varseq array and will be sorted by their number of cliques */
2203 varseq[nvarsused] = i;
2204 sortkeys[nvarsused] = SCIPvarGetNCliques(tmpvars[i], tmpvalues[i]);
2205 nvarsused++;
2206 }
2207 }
2208 assert(nvarsused + nignorevars == nvars);
2209
2210 /* sort variables with LP value less than 1 by nondecreasing order of the number of cliques they are in */
2211 SCIPsortIntInt(sortkeys, varseq, nvarsused);
2212
2213 maxncliquevarscomp = MIN(nvars*nvars, MAXNCLIQUEVARSCOMP);
2214
2215 /* calculate the clique partition */
2216 *ncliques = 0;
2217 for( i = 0; i < nvars; ++i )
2218 {
2219 if( cliquepartition[varseq[i]] == -1 )
2220 {
2221 int j;
2222
2223 /* variable starts a new clique */
2224 cliquepartition[varseq[i]] = *ncliques;
2225 cliquevars[0] = tmpvars[varseq[i]];
2226 cliquevalues[0] = tmpvalues[varseq[i]];
2227 ncliquevars = 1;
2228
2229 /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique and
2230 * if the variable has LP value 1 we do not want it to be in nontrivial cliques
2231 */
2232 if( SCIPvarIsActive(tmpvars[varseq[i]]) && i < nvarsused )
2233 {
2234 /* greedily fill up the clique */
2235 for( j = i + 1; j < nvarsused; ++j )
2236 {
2237 /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique */
2238 if( cliquepartition[varseq[j]] == -1 && SCIPvarIsActive(tmpvars[varseq[j]]) )
2239 {
2240 int k;
2241
2242 /* check if every variable in the actual clique is in clique with the new variable */
2243 for( k = ncliquevars - 1; k >= 0; --k )
2244 {
2245 if( !SCIPvarsHaveCommonClique(tmpvars[varseq[j]], tmpvalues[varseq[j]], cliquevars[k],
2246 cliquevalues[k], TRUE) )
2247 break;
2248 }
2249
2250 if( k == -1 )
2251 {
2252 /* put the variable into the same clique */
2253 cliquepartition[varseq[j]] = cliquepartition[varseq[i]];
2254 cliquevars[ncliquevars] = tmpvars[varseq[j]];
2255 cliquevalues[ncliquevars] = tmpvalues[varseq[j]];
2256 ++ncliquevars;
2257 }
2258 }
2259 }
2260 }
2261
2262 /* this clique is finished */
2263 ++(*ncliques);
2264 }
2265 assert(cliquepartition[varseq[i]] >= 0 && cliquepartition[varseq[i]] < i + 1);
2266
2267 /* break if we reached the maximal number of comparisons */
2268 if( i * nvars > maxncliquevarscomp )
2269 break;
2270 }
2271 /* if we had too many variables fill up the cliquepartition and put each variable in a separate clique */
2272 for( ; i < nvars; ++i )
2273 {
2274 if( cliquepartition[varseq[i]] == -1 )
2275 {
2276 cliquepartition[varseq[i]] = *ncliques;
2277 ++(*ncliques);
2278 }
2279 }
2280
2281 /* free temporary memory */
2282 SCIPfreeBufferArray(scip, &sortkeys);
2283 SCIPfreeBufferArray(scip, &varseq);
2284 SCIPfreeBufferArray(scip, &tmpvars);
2285 SCIPfreeBufferArray(scip, &tmpvalues);
2286 SCIPfreeBufferArray(scip, &cliquevalues);
2287 SCIPfreeBufferArray(scip, &cliquevars);
2288
2289 return SCIP_OKAY;
2290}
2291
2292/** constructs sophisticated partition of knapsack variables into non-overlapping GUBs; current partition uses trivial GUBs */
2293static
2295 SCIP* scip, /**< SCIP data structure */
2296 SCIP_GUBSET* gubset, /**< GUB set data structure */
2297 SCIP_VAR** vars, /**< variables in the knapsack constraint */
2298 SCIP_Real* solvals /**< solution values of all knapsack variables */
2299 )
2300{
2301 int* cliquepartition;
2302 int* gubfirstvar;
2303 int ncliques;
2304 int currentgubconsidx;
2305 int newgubconsidx;
2306 int cliqueidx;
2307 int nvars;
2308 int i;
2309
2310 assert(scip != NULL);
2311 assert(gubset != NULL);
2312 assert(vars != NULL);
2313
2314 nvars = gubset->nvars;
2315 assert(nvars >= 0);
2316
2317 /* allocate temporary memory for clique partition */
2318 SCIP_CALL( SCIPallocBufferArray(scip, &cliquepartition, nvars) );
2319
2320 /* compute sophisticated clique partition */
2321 SCIP_CALL( GUBsetCalcCliquePartition(scip, vars, nvars, cliquepartition, &ncliques, solvals) );
2322
2323 /* allocate temporary memory for GUB set data structure */
2324 SCIP_CALL( SCIPallocBufferArray(scip, &gubfirstvar, ncliques) );
2325
2326 /* translate GUB partition into GUB set data structure */
2327 for( i = 0; i < ncliques; i++ )
2328 {
2329 /* initialize first variable for every GUB */
2330 gubfirstvar[i] = -1;
2331 }
2332 /* move every knapsack variable into GUB defined by clique partition */
2333 for( i = 0; i < nvars; i++ )
2334 {
2335 assert(cliquepartition[i] >= 0);
2336
2337 cliqueidx = cliquepartition[i];
2338 currentgubconsidx = gubset->gubconssidx[i];
2339 assert(gubset->gubconss[currentgubconsidx]->ngubvars == 1 );
2340
2341 /* variable is first element in GUB constraint defined by clique partition */
2342 if( gubfirstvar[cliqueidx] == -1 )
2343 {
2344 /* corresponding GUB constraint in GUB set data structure was already constructed (as initial trivial GUB);
2345 * note: no assert for gubconssidx, because it can changed due to deleting empty GUBs in GUBsetMoveVar()
2346 */
2347 assert(gubset->gubvarsidx[i] == 0);
2348 assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2349
2350 /* remember the first variable found for the current GUB */
2351 gubfirstvar[cliqueidx] = i;
2352 }
2353 /* variable is additional element of GUB constraint defined by clique partition */
2354 else
2355 {
2356 assert(gubfirstvar[cliqueidx] >= 0 && gubfirstvar[cliqueidx] < i);
2357
2358 /* move variable to GUB constraint defined by clique partition; index of this GUB constraint is given by the
2359 * first variable of this GUB constraint
2360 */
2361 newgubconsidx = gubset->gubconssidx[gubfirstvar[cliqueidx]];
2362 assert(newgubconsidx != currentgubconsidx); /* because initially every variable is in a different GUB */
2363 SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, i, currentgubconsidx, newgubconsidx) );
2364
2365 assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2366 }
2367 }
2368
2369#ifdef SCIP_DEBUG
2370 /* prints GUB set data structure */
2371 GUBsetPrint(scip, gubset, vars, solvals);
2372#endif
2373
2374#ifndef NDEBUG
2375 /* checks consistency of GUB set data structure */
2376 SCIP_CALL( GUBsetCheck(scip, gubset, vars) );
2377#endif
2378
2379 /* free temporary memory */
2380 SCIPfreeBufferArray(scip, &gubfirstvar);
2381 SCIPfreeBufferArray(scip, &cliquepartition);
2382
2383 return SCIP_OKAY;
2384}
2385
2386/** 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$
2387 * 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
2388 * \f$j \in N \setminus C\f$, if \f$j \in N_0 = \{j \in N : x^*_j = 0\}\f$, if one exists.
2389 */
2390static
2392 SCIP* scip, /**< SCIP data structure */
2393 SCIP_VAR** vars, /**< variables in knapsack constraint */
2394 int nvars, /**< number of variables in knapsack constraint */
2395 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2396 SCIP_Longint capacity, /**< capacity of knapsack */
2397 SCIP_Real* solvals, /**< solution values of all problem variables */
2398 int* covervars, /**< pointer to store cover variables */
2399 int* noncovervars, /**< pointer to store noncover variables */
2400 int* ncovervars, /**< pointer to store number of cover variables */
2401 int* nnoncovervars, /**< pointer to store number of noncover variables */
2402 SCIP_Longint* coverweight, /**< pointer to store weight of cover */
2403 SCIP_Bool* found, /**< pointer to store whether a cover was found */
2404 SCIP_Bool modtransused, /**< should modified transformed separation problem be used to find cover */
2405 int* ntightened, /**< pointer to store number of variables with tightened upper bound */
2406 SCIP_Bool* fractional /**< pointer to store whether the LP sol for knapsack vars is fractional */
2407 )
2408{
2409 SCIP_Longint* transweights;
2410 SCIP_Real* transprofits;
2411 SCIP_Longint transcapacity;
2412 SCIP_Longint fixedonesweight;
2413 SCIP_Longint itemsweight;
2414 SCIP_Bool infeasible;
2415 int* fixedones;
2416 int* fixedzeros;
2417 int* items;
2418 int nfixedones;
2419 int nfixedzeros;
2420 int nitems;
2421 int j;
2422
2423 assert(scip != NULL);
2424 assert(vars != NULL);
2425 assert(nvars > 0);
2426 assert(weights != NULL);
2427 assert(capacity >= 0);
2428 assert(solvals != NULL);
2429 assert(covervars != NULL);
2430 assert(noncovervars != NULL);
2431 assert(ncovervars != NULL);
2432 assert(nnoncovervars != NULL);
2433 assert(coverweight != NULL);
2434 assert(found != NULL);
2435 assert(ntightened != NULL);
2436 assert(fractional != NULL);
2437
2438 SCIPdebugMsg(scip, " get cover for knapsack constraint\n");
2439
2440 /* allocates temporary memory */
2441 SCIP_CALL( SCIPallocBufferArray(scip, &transweights, nvars) );
2442 SCIP_CALL( SCIPallocBufferArray(scip, &transprofits, nvars) );
2443 SCIP_CALL( SCIPallocBufferArray(scip, &fixedones, nvars) );
2444 SCIP_CALL( SCIPallocBufferArray(scip, &fixedzeros, nvars) );
2446
2447 *found = FALSE;
2448 *ncovervars = 0;
2449 *nnoncovervars = 0;
2450 *coverweight = 0;
2451 *fractional = TRUE;
2452
2453 /* gets the following sets
2454 * N_1 = {j in N : x*_j = 1} (fixedones),
2455 * N_0 = {j in N : x*_j = 0} (fixedzeros) and
2456 * N\‍(N_0 & N_1) (items),
2457 * where x*_j is the solution value of variable x_j
2458 */
2459 nfixedones = 0;
2460 nfixedzeros = 0;
2461 nitems = 0;
2462 fixedonesweight = 0;
2463 itemsweight = 0;
2464 *ntightened = 0;
2465 for( j = 0; j < nvars; j++ )
2466 {
2467 assert(SCIPvarIsBinary(vars[j]));
2468
2469 /* tightens upper bound of x_j if weight of x_j is greater than capacity of knapsack */
2470 if( weights[j] > capacity )
2471 {
2472 SCIP_CALL( SCIPtightenVarUb(scip, vars[j], 0.0, FALSE, &infeasible, NULL) );
2473 assert(!infeasible);
2474 (*ntightened)++;
2475 continue;
2476 }
2477
2478 /* variable x_j has solution value one */
2479 if( SCIPisFeasEQ(scip, solvals[j], 1.0) )
2480 {
2481 fixedones[nfixedones] = j;
2482 nfixedones++;
2483 fixedonesweight += weights[j];
2484 }
2485 /* variable x_j has solution value zero */
2486 else if( SCIPisFeasEQ(scip, solvals[j], 0.0) )
2487 {
2488 fixedzeros[nfixedzeros] = j;
2489 nfixedzeros++;
2490 }
2491 /* variable x_j has fractional solution value */
2492 else
2493 {
2494 assert( SCIPisFeasGT(scip, solvals[j], 0.0) && SCIPisFeasLT(scip, solvals[j], 1.0) );
2495 items[nitems] = j;
2496 nitems++;
2497 itemsweight += weights[j];
2498 }
2499 }
2500 assert(nfixedones + nfixedzeros + nitems == nvars - (*ntightened));
2501
2502 /* sets whether the LP solution x* for the knapsack variables is fractional; if it is not fractional we stop
2503 * the separation routine
2504 */
2505 assert(nitems >= 0);
2506 if( nitems == 0 )
2507 {
2508 *fractional = FALSE;
2509 goto TERMINATE;
2510 }
2511 assert(*fractional);
2512
2513 /* transforms the traditional separation problem (under consideration of the following fixing:
2514 * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2515 *
2516 * min sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) z_j
2517 * sum_{j in N\‍(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2518 * z_j in {0,1}, j in N\‍(N_0 & N_1)
2519 *
2520 * to a knapsack problem in maximization form by complementing the variables
2521 *
2522 * sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) -
2523 * max sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) z_j
2524 * sum_{j in N\‍(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2525 * z_j in {0,1}, j in N\‍(N_0 & N_1)
2526 */
2527
2528 /* gets weight and profit of variables in transformed knapsack problem */
2529 for( j = 0; j < nitems; j++ )
2530 {
2531 transweights[j] = weights[items[j]];
2532 transprofits[j] = 1.0 - solvals[items[j]];
2533 }
2534 /* gets capacity of transformed knapsack problem */
2535 transcapacity = fixedonesweight + itemsweight - capacity - 1;
2536
2537 /* if capacity of transformed knapsack problem is less than zero, there is no cover
2538 * (when variables fixed to zero are not used)
2539 */
2540 if( transcapacity < 0 )
2541 {
2542 assert(!(*found));
2543 goto TERMINATE;
2544 }
2545
2546 if( modtransused )
2547 {
2548 /* transforms the modified separation problem (under consideration of the following fixing:
2549 * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2550 *
2551 * min sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) a_j z_j
2552 * sum_{j in N\‍(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2553 * z_j in {0,1}, j in N\‍(N_0 & N_1)
2554 *
2555 * to a knapsack problem in maximization form by complementing the variables
2556 *
2557 * sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) a_j -
2558 * max sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) a_j z_j
2559 * sum_{j in N\‍(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2560 * z_j in {0,1}, j in N\‍(N_0 & N_1)
2561 */
2562
2563 /* gets weight and profit of variables in modified transformed knapsack problem */
2564 for( j = 0; j < nitems; j++ )
2565 {
2566 transprofits[j] *= weights[items[j]];
2567 assert(SCIPisFeasPositive(scip, transprofits[j]));
2568 }
2569 }
2570
2571 /* solves (modified) transformed knapsack problem approximately by solving the LP-relaxation of the (modified)
2572 * transformed knapsack problem using Dantzig's method and rounding down the solution.
2573 * let z* be the solution, then
2574 * j in C, if z*_j = 0 and
2575 * i in N\C, if z*_j = 1.
2576 */
2577 SCIP_CALL( SCIPsolveKnapsackApproximately(scip, nitems, transweights, transprofits, transcapacity, items,
2578 noncovervars, covervars, nnoncovervars, ncovervars, NULL) );
2579 /*assert(checkSolveKnapsack(scip, nitems, transweights, transprofits, items, weights, solvals, modtransused));*/
2580
2581 /* constructs cover C (sum_{j in C} a_j > a_0) */
2582 for( j = 0; j < *ncovervars; j++ )
2583 {
2584 (*coverweight) += weights[covervars[j]];
2585 }
2586
2587 /* adds all variables from N_1 to C */
2588 for( j = 0; j < nfixedones; j++ )
2589 {
2590 covervars[*ncovervars] = fixedones[j];
2591 (*ncovervars)++;
2592 (*coverweight) += weights[fixedones[j]];
2593 }
2594
2595 /* adds all variables from N_0 to N\C */
2596 for( j = 0; j < nfixedzeros; j++ )
2597 {
2598 noncovervars[*nnoncovervars] = fixedzeros[j];
2599 (*nnoncovervars)++;
2600 }
2601 assert((*ncovervars) + (*nnoncovervars) == nvars - (*ntightened));
2602 assert((*coverweight) > capacity);
2603 *found = TRUE;
2604
2605 TERMINATE:
2606 /* frees temporary memory */
2607 SCIPfreeBufferArray(scip, &items);
2608 SCIPfreeBufferArray(scip, &fixedzeros);
2609 SCIPfreeBufferArray(scip, &fixedones);
2610 SCIPfreeBufferArray(scip, &transprofits);
2611 SCIPfreeBufferArray(scip, &transweights);
2612
2613 SCIPdebugMsg(scip, " get cover for knapsack constraint -- end\n");
2614
2615 return SCIP_OKAY;
2616}
2617
2618#ifndef NDEBUG
2619/** checks if minweightidx is set correctly
2620 */
2621static
2623 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2624 SCIP_Longint capacity, /**< capacity of knapsack */
2625 int* covervars, /**< pointer to store cover variables */
2626 int ncovervars, /**< pointer to store number of cover variables */
2627 SCIP_Longint coverweight, /**< pointer to store weight of cover */
2628 int minweightidx, /**< index of variable in cover variables with minimum weight */
2629 int j /**< current index in cover variables */
2630 )
2631{
2632 SCIP_Longint minweight;
2633 int i;
2634
2635 assert(weights != NULL);
2636 assert(covervars != NULL);
2637 assert(ncovervars > 0);
2638
2639 minweight = weights[covervars[minweightidx]];
2640
2641 /* checks if all cover variables before index j have weight greater than minweight */
2642 for( i = 0; i < j; i++ )
2643 {
2644 assert(weights[covervars[i]] > minweight);
2645 if( weights[covervars[i]] <= minweight )
2646 return FALSE;
2647 }
2648
2649 /* checks if all variables before index j cannot be removed, i.e. i cannot be the next minweightidx */
2650 for( i = 0; i < j; i++ )
2651 {
2652 assert(coverweight - weights[covervars[i]] <= capacity);
2653 if( coverweight - weights[covervars[i]] > capacity )
2654 return FALSE;
2655 }
2656 return TRUE;
2657}
2658#endif
2659
2660
2661/** 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$,
2662 * 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$
2663 */
2664static
2666 SCIP* scip, /**< SCIP data structure */
2667 SCIP_Real* solvals, /**< solution values of all problem variables */
2668 int* covervars, /**< cover variables */
2669 int ncovervars, /**< number of cover variables */
2670 int* varsC1, /**< pointer to store variables in C1 */
2671 int* varsC2, /**< pointer to store variables in C2 */
2672 int* nvarsC1, /**< pointer to store number of variables in C1 */
2673 int* nvarsC2 /**< pointer to store number of variables in C2 */
2674 )
2675{
2676 int j;
2677
2678 assert(scip != NULL);
2679 assert(ncovervars >= 0);
2680 assert(solvals != NULL);
2681 assert(covervars != NULL);
2682 assert(varsC1 != NULL);
2683 assert(varsC2 != NULL);
2684 assert(nvarsC1 != NULL);
2685 assert(nvarsC2 != NULL);
2686
2687 *nvarsC1 = 0;
2688 *nvarsC2 = 0;
2689 for( j = 0; j < ncovervars; j++ )
2690 {
2691 assert(SCIPisFeasGT(scip, solvals[covervars[j]], 0.0));
2692
2693 /* variable has solution value one */
2694 if( SCIPisGE(scip, solvals[covervars[j]], 1.0) )
2695 {
2696 varsC2[*nvarsC2] = covervars[j];
2697 (*nvarsC2)++;
2698 }
2699 /* variable has solution value less than one */
2700 else
2701 {
2702 assert(SCIPisLT(scip, solvals[covervars[j]], 1.0));
2703 varsC1[*nvarsC1] = covervars[j];
2704 (*nvarsC1)++;
2705 }
2706 }
2707 assert((*nvarsC1) + (*nvarsC2) == ncovervars);
2708}
2709
2710/** changes given partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one and two (if possible) variables from
2711 * C2 to C1 if |C1| = 1 and |C1| = 0, respectively.
2712 */
2713static
2715 SCIP* scip, /**< SCIP data structure */
2716 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2717 int* varsC1, /**< pointer to store variables in C1 */
2718 int* varsC2, /**< pointer to store variables in C2 */
2719 int* nvarsC1, /**< pointer to store number of variables in C1 */
2720 int* nvarsC2 /**< pointer to store number of variables in C2 */
2721 )
2722{
2723 SCIP_Real* sortkeysC2;
2724 int j;
2725
2726 assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2727 assert(*nvarsC2 > 0);
2728
2729 /* allocates temporary memory */
2730 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2731
2732 /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2733 for( j = 0; j < *nvarsC2; j++ )
2734 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2735 SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2736
2737 /* adds one or two variable from C2 with smallest weight to C1 and removes them from C2 */
2738 assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2739 while( *nvarsC1 < 2 && *nvarsC2 > 0 )
2740 {
2741 varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2742 (*nvarsC1)++;
2743 (*nvarsC2)--;
2744 }
2745
2746 /* frees temporary memory */
2747 SCIPfreeBufferArray(scip, &sortkeysC2);
2748
2749 return SCIP_OKAY;
2750}
2751
2752/** changes given partition (C_1,C_2) of feasible set C, if |C1| = 1, by moving one variable from C2 to C1 */
2753static
2755 SCIP* scip, /**< SCIP data structure */
2756 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2757 int* varsC1, /**< pointer to store variables in C1 */
2758 int* varsC2, /**< pointer to store variables in C2 */
2759 int* nvarsC1, /**< pointer to store number of variables in C1 */
2760 int* nvarsC2 /**< pointer to store number of variables in C2 */
2761 )
2762{
2763 SCIP_Real* sortkeysC2;
2764 int j;
2765
2766 assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2767 assert(*nvarsC2 > 0);
2768
2769 /* allocates temporary memory */
2770 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2771
2772 /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2773 for( j = 0; j < *nvarsC2; j++ )
2774 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2775 SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2776
2777 /* adds variable from C2 with smallest weight to C1 and removes it from C2 */
2778 assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2779 varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2780 (*nvarsC1)++;
2781 (*nvarsC2)--;
2782
2783 /* frees temporary memory */
2784 SCIPfreeBufferArray(scip, &sortkeysC2);
2785
2786 return SCIP_OKAY;
2787}
2788
2789
2790/** 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$
2791 * and \f$F \cap R = \emptyset\f$; chooses partition as follows \f$R = \{ j \in N \setminus C : x^*_j = 0 \}\f$ and
2792 * \f$F = (N \setminus C) \setminus F\f$
2793 */
2794static
2796 SCIP* scip, /**< SCIP data structure */
2797 SCIP_Real* solvals, /**< solution values of all problem variables */
2798 int* noncovervars, /**< noncover variables */
2799 int nnoncovervars, /**< number of noncover variables */
2800 int* varsF, /**< pointer to store variables in F */
2801 int* varsR, /**< pointer to store variables in R */
2802 int* nvarsF, /**< pointer to store number of variables in F */
2803 int* nvarsR /**< pointer to store number of variables in R */
2804 )
2805{
2806 int j;
2807
2808 assert(scip != NULL);
2809 assert(nnoncovervars >= 0);
2810 assert(solvals != NULL);
2811 assert(noncovervars != NULL);
2812 assert(varsF != NULL);
2813 assert(varsR != NULL);
2814 assert(nvarsF != NULL);
2815 assert(nvarsR != NULL);
2816
2817 *nvarsF = 0;
2818 *nvarsR = 0;
2819
2820 for( j = 0; j < nnoncovervars; j++ )
2821 {
2822 /* variable has solution value zero */
2823 if( SCIPisFeasEQ(scip, solvals[noncovervars[j]], 0.0) )
2824 {
2825 varsR[*nvarsR] = noncovervars[j];
2826 (*nvarsR)++;
2827 }
2828 /* variable has solution value greater than zero */
2829 else
2830 {
2831 assert(SCIPisFeasGT(scip, solvals[noncovervars[j]], 0.0));
2832 varsF[*nvarsF] = noncovervars[j];
2833 (*nvarsF)++;
2834 }
2835 }
2836 assert((*nvarsF) + (*nvarsR) == nnoncovervars);
2837}
2838
2839/** sorts variables in F, C_2, and R according to the second level lifting sequence that will be used in the sequential
2840 * lifting procedure
2841 */
2842static
2844 SCIP* scip, /**< SCIP data structure */
2845 SCIP_Real* solvals, /**< solution values of all problem variables */
2846 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2847 int* varsF, /**< pointer to store variables in F */
2848 int* varsC2, /**< pointer to store variables in C2 */
2849 int* varsR, /**< pointer to store variables in R */
2850 int nvarsF, /**< number of variables in F */
2851 int nvarsC2, /**< number of variables in C2 */
2852 int nvarsR /**< number of variables in R */
2853 )
2854{
2855 SORTKEYPAIR** sortkeypairsF;
2856 SORTKEYPAIR* sortkeypairsFstore;
2857 SCIP_Real* sortkeysC2;
2858 SCIP_Real* sortkeysR;
2859 int j;
2860
2861 assert(scip != NULL);
2862 assert(solvals != NULL);
2863 assert(weights != NULL);
2864 assert(varsF != NULL);
2865 assert(varsC2 != NULL);
2866 assert(varsR != NULL);
2867 assert(nvarsF >= 0);
2868 assert(nvarsC2 >= 0);
2869 assert(nvarsR >= 0);
2870
2871 /* allocates temporary memory */
2872 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsF, nvarsF) );
2873 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsFstore, nvarsF) );
2874 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
2875 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
2876
2877 /* gets sorting key for variables in F corresponding to the following lifting sequence
2878 * sequence 1: non-increasing absolute difference between x*_j and the value the variable is fixed to, i.e.
2879 * x*_1 >= x*_2 >= ... >= x*_|F|
2880 * in case of equality uses
2881 * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2882 */
2883 for( j = 0; j < nvarsF; j++ )
2884 {
2885 sortkeypairsF[j] = &(sortkeypairsFstore[j]);
2886 sortkeypairsF[j]->key1 = solvals[varsF[j]];
2887 sortkeypairsF[j]->key2 = (SCIP_Real) weights[varsF[j]];
2888 }
2889
2890 /* gets sorting key for variables in C_2 corresponding to the following lifting sequence
2891 * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2892 */
2893 for( j = 0; j < nvarsC2; j++ )
2894 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2895
2896 /* gets sorting key for variables in R corresponding to the following lifting sequence
2897 * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|R|
2898 */
2899 for( j = 0; j < nvarsR; j++ )
2900 sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
2901
2902 /* sorts F, C2 and R */
2903 if( nvarsF > 0 )
2904 {
2905 SCIPsortDownPtrInt((void**)sortkeypairsF, varsF, compSortkeypairs, nvarsF);
2906 }
2907 if( nvarsC2 > 0 )
2908 {
2909 SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
2910 }
2911 if( nvarsR > 0)
2912 {
2913 SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
2914 }
2915
2916 /* frees temporary memory */
2917 SCIPfreeBufferArray(scip, &sortkeysR);
2918 SCIPfreeBufferArray(scip, &sortkeysC2);
2919 SCIPfreeBufferArray(scip, &sortkeypairsFstore);
2920 SCIPfreeBufferArray(scip, &sortkeypairsF);
2921
2922 return SCIP_OKAY;
2923}
2924
2925/** categorizes GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of the GUBs
2926 * for the sequential GUB wise lifting procedure
2927 */
2928static
2930 SCIP* scip, /**< SCIP data structure */
2931 SCIP_GUBSET* gubset, /**< GUB set data structure */
2932 SCIP_Real* solvals, /**< solution values of variables in knapsack constraint */
2933 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2934 int* varsC1, /**< variables in C1 */
2935 int* varsC2, /**< variables in C2 */
2936 int* varsF, /**< variables in F */
2937 int* varsR, /**< variables in R */
2938 int nvarsC1, /**< number of variables in C1 */
2939 int nvarsC2, /**< number of variables in C2 */
2940 int nvarsF, /**< number of variables in F */
2941 int nvarsR, /**< number of variables in R */
2942 int* gubconsGC1, /**< pointer to store GUBs in GC1(GNC1+GOC1) */
2943 int* gubconsGC2, /**< pointer to store GUBs in GC2 */
2944 int* gubconsGFC1, /**< pointer to store GUBs in GFC1(GNC1+GF) */
2945 int* gubconsGR, /**< pointer to store GUBs in GR */
2946 int* ngubconsGC1, /**< pointer to store number of GUBs in GC1(GNC1+GOC1) */
2947 int* ngubconsGC2, /**< pointer to store number of GUBs in GC2 */
2948 int* ngubconsGFC1, /**< pointer to store number of GUBs in GFC1(GNC1+GF) */
2949 int* ngubconsGR, /**< pointer to store number of GUBs in GR */
2950 int* ngubconscapexceed, /**< pointer to store number of GUBs with only capacity exceeding variables */
2951 int* maxgubvarssize /**< pointer to store the maximal size of GUB constraints */
2952 )
2953{
2954 SORTKEYPAIR** sortkeypairsGFC1;
2955 SORTKEYPAIR* sortkeypairsGFC1store;
2956 SCIP_Real* sortkeysC1;
2957 SCIP_Real* sortkeysC2;
2958 SCIP_Real* sortkeysR;
2959 int* nC1varsingubcons;
2960 int var;
2961 int gubconsidx;
2962 int varidx;
2963 int ngubconss;
2964 int ngubconsGOC1;
2965 int targetvar;
2966#ifndef NDEBUG
2967 int nvarsprocessed = 0;
2968#endif
2969 int i;
2970 int j;
2971
2972#if GUBSPLITGNC1GUBS
2973 SCIP_Bool gubconswithF;
2974 int origngubconss;
2975 origngubconss = gubset->ngubconss;
2976#endif
2977
2978 assert(scip != NULL);
2979 assert(gubset != NULL);
2980 assert(solvals != NULL);
2981 assert(weights != NULL);
2982 assert(varsC1 != NULL);
2983 assert(varsC2 != NULL);
2984 assert(varsF != NULL);
2985 assert(varsR != NULL);
2986 assert(nvarsC1 > 0);
2987 assert(nvarsC2 >= 0);
2988 assert(nvarsF >= 0);
2989 assert(nvarsR >= 0);
2990 assert(gubconsGC1 != NULL);
2991 assert(gubconsGC2 != NULL);
2992 assert(gubconsGFC1 != NULL);
2993 assert(gubconsGR != NULL);
2994 assert(ngubconsGC1 != NULL);
2995 assert(ngubconsGC2 != NULL);
2996 assert(ngubconsGFC1 != NULL);
2997 assert(ngubconsGR != NULL);
2998 assert(maxgubvarssize != NULL);
2999
3000 ngubconss = gubset->ngubconss;
3001 ngubconsGOC1 = 0;
3002
3003 /* GUBs are categorized into different types according to the variables in volved
3004 * - GOC1: involves variables in C1 only -- no C2, R, F
3005 * - GNC1: involves variables in C1 and F (and R) -- no C2
3006 * - GF: involves variables in F (and R) only -- no C1, C2
3007 * - GC2: involves variables in C2 only -- no C1, R, F
3008 * - GR: involves variables in R only -- no C1, C2, F
3009 * which requires splitting GUBs in case they include variable in F and R.
3010 *
3011 * afterwards all GUBs (except GOC1 GUBs, which we do not need to lift) are sorted by a two level lifting sequence.
3012 * - first ordering level is: GFC1 (GNC1+GF), GC2, and GR.
3013 * - second ordering level is
3014 * GFC1: non-increasing number of variables in F and non-increasing max{x*_k : k in GFC1_j} in case of equality
3015 * GC2: non-increasing max{ a_k : k in GC2_j}; note that |GFC2_j| = 1
3016 * GR: non-increasing max{ a_k : k in GR_j}
3017 *
3018 * in additon, another GUB union, which is helpful for the lifting procedure, is formed
3019 * - GC1: GUBs of category GOC1 and GNC1
3020 * with second ordering level non-decreasing min{ a_k : k in GC1_j };
3021 * note that min{ a_k : k in GC1_j } always comes from the first variable in the GUB
3022 */
3023
3024 /* allocates temporary memory */
3025 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC1, nvarsC1) );
3026 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
3027 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
3028
3029 /* to get the GUB lifting sequence, we first sort all variables in F, C2, and R
3030 * - F: non-increasing x*_j and non-increasing a_j in case of equality
3031 * - C2: non-increasing a_j
3032 * - R: non-increasing a_j
3033 * furthermore, sort C1 variables as needed for initializing the minweight table (non-increasing a_j).
3034 */
3035
3036 /* gets sorting key for variables in C1 corresponding to the following ordering
3037 * non-decreasing a_j, i.e. a_1 <= a_2 <= ... <= a_|C_1|
3038 */
3039 for( j = 0; j < nvarsC1; j++ )
3040 {
3041 /* gets sortkeys */
3042 sortkeysC1[j] = (SCIP_Real) weights[varsC1[j]];
3043
3044 /* update status of variable in its gub constraint */
3045 gubconsidx = gubset->gubconssidx[varsC1[j]];
3046 varidx = gubset->gubvarsidx[varsC1[j]];
3047 gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C1;
3048 }
3049
3050 /* gets sorting key for variables in F corresponding to the following ordering
3051 * non-increasing x*_j, i.e., x*_1 >= x*_2 >= ... >= x*_|F|, and
3052 * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|F| in case of equality
3053 * and updates status of each variable in F in GUB set data structure
3054 */
3055 for( j = 0; j < nvarsF; j++ )
3056 {
3057 /* update status of variable in its gub constraint */
3058 gubconsidx = gubset->gubconssidx[varsF[j]];
3059 varidx = gubset->gubvarsidx[varsF[j]];
3060 gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_F;
3061 }
3062
3063 /* gets sorting key for variables in C2 corresponding to the following ordering
3064 * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|C2|
3065 * and updates status of each variable in F in GUB set data structure
3066 */
3067 for( j = 0; j < nvarsC2; j++ )
3068 {
3069 /* gets sortkeys */
3070 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
3071
3072 /* update status of variable in its gub constraint */
3073 gubconsidx = gubset->gubconssidx[varsC2[j]];
3074 varidx = gubset->gubvarsidx[varsC2[j]];
3075 gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C2;
3076 }
3077
3078 /* gets sorting key for variables in R corresponding to the following ordering
3079 * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|R|
3080 * and updates status of each variable in F in GUB set data structure
3081 */
3082 for( j = 0; j < nvarsR; j++ )
3083 {
3084 /* gets sortkeys */
3085 sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
3086
3087 /* update status of variable in its gub constraint */
3088 gubconsidx = gubset->gubconssidx[varsR[j]];
3089 varidx = gubset->gubvarsidx[varsR[j]];
3090 gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_R;
3091 }
3092
3093 /* sorts C1, F, C2 and R */
3094 assert(nvarsC1 > 0);
3095 SCIPsortRealInt(sortkeysC1, varsC1, nvarsC1);
3096
3097 if( nvarsC2 > 0 )
3098 {
3099 SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
3100 }
3101 if( nvarsR > 0)
3102 {
3103 SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
3104 }
3105
3106 /* frees temporary memory */
3107 SCIPfreeBufferArray(scip, &sortkeysR);
3108 SCIPfreeBufferArray(scip, &sortkeysC2);
3109 SCIPfreeBufferArray(scip, &sortkeysC1);
3110
3111 /* allocate and initialize temporary memory for sorting GUB constraints */
3112 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1, ngubconss) );
3113 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1store, ngubconss) );
3114 SCIP_CALL( SCIPallocBufferArray(scip, &nC1varsingubcons, ngubconss) );
3115 BMSclearMemoryArray(nC1varsingubcons, ngubconss);
3116 for( i = 0; i < ngubconss; i++)
3117 {
3118 sortkeypairsGFC1[i] = &(sortkeypairsGFC1store[i]);
3119 sortkeypairsGFC1[i]->key1 = 0.0;
3120 sortkeypairsGFC1[i]->key2 = 0.0;
3121 }
3122 *ngubconsGC1 = 0;
3123 *ngubconsGC2 = 0;
3124 *ngubconsGFC1 = 0;
3125 *ngubconsGR = 0;
3126 *ngubconscapexceed = 0;
3127 *maxgubvarssize = 0;
3128
3129#ifndef NDEBUG
3130 for( i = 0; i < gubset->ngubconss; i++ )
3131 assert(gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL);
3132#endif
3133
3134 /* stores GUBs of group GC1 (GOC1+GNC1) and part of the GUBs of group GFC1 (GNC1 GUBs) and sorts variables in these GUBs
3135 * s.t. C1 variables come first (will automatically be sorted by non-decreasing weight).
3136 * gets sorting keys for GUBs of type GFC1 corresponding to the following ordering
3137 * non-increasing number of variables in F, and
3138 * non-increasing max{x*_k : k in GFC1_j} in case of equality
3139 */
3140 for( i = 0; i < nvarsC1; i++ )
3141 {
3142 int nvarsC1capexceed;
3143
3144 nvarsC1capexceed = 0;
3145
3146 var = varsC1[i];
3147 gubconsidx = gubset->gubconssidx[var];
3148 varidx = gubset->gubvarsidx[var];
3149
3150 assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3151 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C1);
3152
3153 /* current C1 variable is put to the front of its GUB where C1 part is stored by non-decreasing weigth;
3154 * note that variables in C1 are already sorted by non-decreasing weigth
3155 */
3156 targetvar = gubset->gubconss[gubconsidx]->gubvars[nC1varsingubcons[gubconsidx]];
3157 GUBsetSwapVars(scip, gubset, var, targetvar);
3158 nC1varsingubcons[gubconsidx]++;
3159
3160 /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3161 if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3162 {
3163 assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
3164 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3165 continue;
3166 }
3167
3168 /* determine the status of the current GUB constraint, GOC1 or GNC1; GUBs involving R variables are split into
3169 * GOC1/GNC1 and GF, if wanted. also update sorting key if GUB is of type GFC1 (GNC1)
3170 */
3171#if GUBSPLITGNC1GUBS
3172 gubconswithF = FALSE;
3173#endif
3174 for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3175 {
3176 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2);
3177
3178 /* C1-variable: update number of C1/capacity exceeding variables */
3179 if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_C1 )
3180 {
3181 nvarsC1capexceed++;
3182#ifndef NDEBUG
3183 nvarsprocessed++;
3184#endif
3185 }
3186 /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3187 else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3188 {
3189#if GUBSPLITGNC1GUBS
3190 gubconswithF = TRUE;
3191#endif
3192 sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3193
3194 if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3195 sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3196 }
3197 else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_CAPACITYEXCEEDED )
3198 {
3199 nvarsC1capexceed++;
3200 }
3201 else
3202 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_R);
3203 }
3204
3205 /* update set of GC1 GUBs */
3206 gubconsGC1[*ngubconsGC1] = gubconsidx;
3207 (*ngubconsGC1)++;
3208
3209 /* update maximum size of all GUB constraints */
3210 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3211 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3212
3213 /* set status of GC1-GUB (GOC1 or GNC1) and update set of GFC1 GUBs */
3214 if( nvarsC1capexceed == gubset->gubconss[gubconsidx]->ngubvars )
3215 {
3216 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3217 ngubconsGOC1++;
3218 }
3219 else
3220 {
3221#if GUBSPLITGNC1GUBS
3222 /* only variables in C1 and R -- no in F: GUB will be split into GR and GOC1 GUBs */
3223 if( !gubconswithF )
3224 {
3225 GUBVARSTATUS movevarstatus;
3226
3227 assert(gubset->ngubconss < gubset->nvars);
3228
3229 /* create a new GUB for GR part of splitting */
3230 SCIP_CALL( GUBconsCreate(scip, &gubset->gubconss[gubset->ngubconss]) );
3231 gubset->ngubconss++;
3232 ngubconss = gubset->ngubconss;
3233
3234 /* fill GR with R variables in current GUB */
3235 for( j = gubset->gubconss[gubconsidx]->ngubvars-1; j >= 0; j-- )
3236 {
3237 movevarstatus = gubset->gubconss[gubconsidx]->gubvarsstatus[j];
3238 if( movevarstatus != GUBVARSTATUS_BELONGSTOSET_C1 )
3239 {
3240 assert(movevarstatus == GUBVARSTATUS_BELONGSTOSET_R || movevarstatus == GUBVARSTATUS_CAPACITYEXCEEDED);
3241 SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, gubset->gubconss[gubconsidx]->gubvars[j],
3242 gubconsidx, ngubconss-1) );
3243 gubset->gubconss[ngubconss-1]->gubvarsstatus[gubset->gubconss[ngubconss-1]->ngubvars-1] =
3244 movevarstatus;
3245 }
3246 }
3247
3248 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3249 ngubconsGOC1++;
3250
3252 gubconsGR[*ngubconsGR] = ngubconss-1;
3253 (*ngubconsGR)++;
3254 }
3255 /* variables in C1, F, and maybe R: GNC1 GUB */
3256 else
3257 {
3258 assert(gubconswithF);
3259
3260 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3261 gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3262 (*ngubconsGFC1)++;
3263 }
3264#else
3265 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3266 gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3267 (*ngubconsGFC1)++;
3268#endif
3269 }
3270 }
3271
3272 /* stores GUBs of group GC2 (only trivial GUBs); sorting is not required because the C2 variables (which we loop over)
3273 * are already sorted correctly
3274 */
3275 for( i = 0; i < nvarsC2; i++ )
3276 {
3277 var = varsC2[i];
3278 gubconsidx = gubset->gubconssidx[var];
3279 varidx = gubset->gubvarsidx[var];
3280
3281 assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3282 assert(gubset->gubconss[gubconsidx]->ngubvars == 1);
3283 assert(varidx == 0);
3284 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C2);
3285 assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_UNINITIAL);
3286
3287 /* set status of GC2 GUB */
3288 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GC2;
3289
3290 /* update group of GC2 GUBs */
3291 gubconsGC2[*ngubconsGC2] = gubconsidx;
3292 (*ngubconsGC2)++;
3293
3294 /* update maximum size of all GUB constraints */
3295 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3296 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3297
3298#ifndef NDEBUG
3299 nvarsprocessed++;
3300#endif
3301 }
3302
3303 /* stores remaining part of the GUBs of group GFC1 (GF GUBs) and gets GUB sorting keys corresp. to following ordering
3304 * non-increasing number of variables in F, and
3305 * non-increasing max{x*_k : k in GFC1_j} in case of equality
3306 */
3307 for( i = 0; i < nvarsF; i++ )
3308 {
3309 var = varsF[i];
3310 gubconsidx = gubset->gubconssidx[var];
3311 varidx = gubset->gubvarsidx[var];
3312
3313 assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3314 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_F);
3315
3316#ifndef NDEBUG
3317 nvarsprocessed++;
3318#endif
3319
3320 /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3321 if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3322 {
3323 assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3324 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3325 continue;
3326 }
3327
3328 /* set status of GF GUB */
3329 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GF;
3330
3331 /* update sorting key of corresponding GFC1 GUB */
3332 for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3333 {
3334 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2
3335 && gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C1);
3336
3337 /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3338 if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3339 {
3340 sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3341
3342 if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3343 sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3344 }
3345 }
3346
3347 /* update set of GFC1 GUBs */
3348 gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3349 (*ngubconsGFC1)++;
3350
3351 /* update maximum size of all GUB constraints */
3352 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3353 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3354 }
3355
3356 /* stores GUBs of group GR; sorting is not required because the R variables (which we loop over) are already sorted
3357 * correctly
3358 */
3359 for( i = 0; i < nvarsR; i++ )
3360 {
3361 var = varsR[i];
3362 gubconsidx = gubset->gubconssidx[var];
3363 varidx = gubset->gubvarsidx[var];
3364
3365 assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3366 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_R);
3367
3368#ifndef NDEBUG
3369 nvarsprocessed++;
3370#endif
3371
3372 /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3373 if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3374 {
3375 assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR
3376 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3377 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3378 continue;
3379 }
3380
3381 /* set status of GR GUB */
3382 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GR;
3383
3384 /* update set of GR GUBs */
3385 gubconsGR[*ngubconsGR] = gubconsidx;
3386 (*ngubconsGR)++;
3387
3388 /* update maximum size of all GUB constraints */
3389 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3390 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3391 }
3392 assert(nvarsprocessed == nvarsC1 + nvarsC2 + nvarsF + nvarsR);
3393
3394 /* update number of GUBs with only capacity exceeding variables (will not be used for lifting) */
3395 (*ngubconscapexceed) = ngubconss - (ngubconsGOC1 + (*ngubconsGC2) + (*ngubconsGFC1) + (*ngubconsGR));
3396 assert(*ngubconscapexceed >= 0);
3397#ifndef NDEBUG
3398 {
3399 int check;
3400
3401 check = 0;
3402
3403 /* remaining not handled GUBs should only contain capacity exceeding variables */
3404 for( i = 0; i < ngubconss; i++ )
3405 {
3406 if( gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL )
3407 check++;
3408 }
3409 assert(check == *ngubconscapexceed);
3410 }
3411#endif
3412
3413 /* sort GFCI GUBs according to computed sorting keys */
3414 if( (*ngubconsGFC1) > 0 )
3415 {
3416 SCIPsortDownPtrInt((void**)sortkeypairsGFC1, gubconsGFC1, compSortkeypairs, (*ngubconsGFC1));
3417 }
3418
3419 /* free temporary memory */
3420#if GUBSPLITGNC1GUBS
3421 ngubconss = origngubconss;
3422#endif
3423 SCIPfreeBufferArray(scip, &nC1varsingubcons);
3424 SCIPfreeBufferArray(scip, &sortkeypairsGFC1store);
3425 SCIPfreeBufferArray(scip, &sortkeypairsGFC1);
3426
3427 return SCIP_OKAY;
3428}
3429
3430/** enlarges minweight table to at least the given length */
3431static
3433 SCIP* scip, /**< SCIP data structure */
3434 SCIP_Longint** minweightsptr, /**< pointer to minweights table */
3435 int* minweightslen, /**< pointer to store number of entries in minweights table (incl. z=0) */
3436 int* minweightssize, /**< pointer to current size of minweights table */
3437 int newlen /**< new length of minweights table */
3438 )
3439{
3440 int j;
3441
3442 assert(minweightsptr != NULL);
3443 assert(*minweightsptr != NULL);
3444 assert(minweightslen != NULL);
3445 assert(*minweightslen >= 0);
3446 assert(minweightssize != NULL);
3447 assert(*minweightssize >= 0);
3448
3449 if( newlen > *minweightssize )
3450 {
3451 int newsize;
3452
3453 /* reallocate table memory */
3454 newsize = SCIPcalcMemGrowSize(scip, newlen);
3455 SCIP_CALL( SCIPreallocBufferArray(scip, minweightsptr, newsize) );
3456 *minweightssize = newsize;
3457 }
3458 assert(newlen <= *minweightssize);
3459
3460 /* initialize new elements */
3461 for( j = *minweightslen; j < newlen; ++j )
3462 (*minweightsptr)[j] = SCIP_LONGINT_MAX;
3463 *minweightslen = newlen;
3464
3465 return SCIP_OKAY;
3466}
3467
3468/** lifts given inequality
3469 * sum_{j in M_1} x_j <= alpha_0
3470 * valid for
3471 * 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 }
3472 * to a valid inequality
3473 * 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
3474 * <= alpha_0 + sum_{j in M_2} alpha_j
3475 * for
3476 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 };
3477 * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in M_2, and
3478 * sequential up-lifting for the variables in R; procedure can be used to strengthen minimal cover inequalities and
3479 * extended weight inequalities.
3480 */
3481static
3483 SCIP* scip, /**< SCIP data structure */
3484 SCIP_VAR** vars, /**< variables in knapsack constraint */
3485 int nvars, /**< number of variables in knapsack constraint */
3486 int ntightened, /**< number of variables with tightened upper bound */
3487 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3488 SCIP_Longint capacity, /**< capacity of knapsack */
3489 SCIP_Real* solvals, /**< solution values of all problem variables */
3490 int* varsM1, /**< variables in M_1 */
3491 int* varsM2, /**< variables in M_2 */
3492 int* varsF, /**< variables in F */
3493 int* varsR, /**< variables in R */
3494 int nvarsM1, /**< number of variables in M_1 */
3495 int nvarsM2, /**< number of variables in M_2 */
3496 int nvarsF, /**< number of variables in F */
3497 int nvarsR, /**< number of variables in R */
3498 int alpha0, /**< rights hand side of given valid inequality */
3499 int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3500 SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3501 int* liftrhs /**< pointer to store right hand side of the lifted valid inequality */
3502 )
3503{
3504 SCIP_Longint* minweights;
3505 SCIP_Real* sortkeys;
3506 SCIP_Longint fixedonesweight;
3507 int minweightssize;
3508 int minweightslen;
3509 int j;
3510 int w;
3511
3512 assert(scip != NULL);
3513 assert(vars != NULL);
3514 assert(nvars >= 0);
3515 assert(weights != NULL);
3516 assert(capacity >= 0);
3517 assert(solvals != NULL);
3518 assert(varsM1 != NULL);
3519 assert(varsM2 != NULL);
3520 assert(varsF != NULL);
3521 assert(varsR != NULL);
3522 assert(nvarsM1 >= 0 && nvarsM1 <= nvars - ntightened);
3523 assert(nvarsM2 >= 0 && nvarsM2 <= nvars - ntightened);
3524 assert(nvarsF >= 0 && nvarsF <= nvars - ntightened);
3525 assert(nvarsR >= 0 && nvarsR <= nvars - ntightened);
3526 assert(nvarsM1 + nvarsM2 + nvarsF + nvarsR == nvars - ntightened);
3527 assert(alpha0 >= 0);
3528 assert(liftcoefs != NULL);
3529 assert(cutact != NULL);
3530 assert(liftrhs != NULL);
3531
3532 /* allocates temporary memory */
3533 minweightssize = nvarsM1 + 1;
3534 SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
3535 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvarsM1) );
3536
3537 /* initializes data structures */
3538 BMSclearMemoryArray(liftcoefs, nvars);
3539 *cutact = 0.0;
3540
3541 /* sets lifting coefficient of variables in M1, sorts variables in M1 such that a_1 <= a_2 <= ... <= a_|M1|
3542 * and calculates activity of the current valid inequality
3543 */
3544 for( j = 0; j < nvarsM1; j++ )
3545 {
3546 assert(liftcoefs[varsM1[j]] == 0);
3547 liftcoefs[varsM1[j]] = 1;
3548 sortkeys[j] = (SCIP_Real) (weights[varsM1[j]]);
3549 (*cutact) += solvals[varsM1[j]];
3550 }
3551
3552 SCIPsortRealInt(sortkeys, varsM1, nvarsM1);
3553
3554 /* initializes (i = 1) the minweight table, defined as: minweights_i[w] =
3555 * min sum_{j in M_1} a_j x_j + sum_{k=1}^{i-1} a_{j_k} x_{j_k}
3556 * s.t. sum_{j in M_1} x_j + sum_{k=1}^{i-1} alpha_{j_k} x_{j_k} >= w
3557 * x_j in {0,1} for j in M_1 & {j_i,...,j_i-1},
3558 * for i = 1,...,t with t = |N\M1| and w = 0,...,|M1| + sum_{k=1}^{i-1} alpha_{j_k};
3559 */
3560 minweights[0] = 0;
3561 for( w = 1; w <= nvarsM1; w++ )
3562 minweights[w] = minweights[w-1] + weights[varsM1[w-1]];
3563 minweightslen = nvarsM1 + 1;
3564
3565 /* gets sum of weights of variables fixed to one, i.e. sum of weights of variables in M_2 */
3566 fixedonesweight = 0;
3567 for( j = 0; j < nvarsM2; j++ )
3568 fixedonesweight += weights[varsM2[j]];
3569 assert(fixedonesweight >= 0);
3570
3571 /* initializes right hand side of lifted valid inequality */
3572 *liftrhs = alpha0;
3573
3574 /* sequentially up-lifts all variables in F: */
3575 for( j = 0; j < nvarsF; j++ )
3576 {
3577 SCIP_Longint weight;
3578 int liftvar;
3579 int liftcoef;
3580 int z;
3581
3582 liftvar = varsF[j];
3583 weight = weights[liftvar];
3584 assert(liftvar >= 0 && liftvar < nvars);
3585 assert(SCIPisFeasGT(scip, solvals[liftvar], 0.0));
3586 assert(weight > 0);
3587
3588 /* knapsack problem is infeasible:
3589 * sets z = 0
3590 */
3591 if( capacity - fixedonesweight - weight < 0 )
3592 {
3593 z = 0;
3594 }
3595 /* knapsack problem is feasible:
3596 * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
3597 * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
3598 */
3599 else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
3600 {
3601 z = *liftrhs;
3602 }
3603 /* knapsack problem is feasible:
3604 * uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} }
3605 */
3606 else
3607 {
3608 int left;
3609 int right;
3610 int middle;
3611
3612 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
3613 left = 0;
3614 right = (*liftrhs) + 1;
3615 while( left < right - 1 )
3616 {
3617 middle = (left + right) / 2;
3618 assert(0 <= middle && middle < minweightslen);
3619 if( minweights[middle] <= capacity - fixedonesweight - weight )
3620 left = middle;
3621 else
3622 right = middle;
3623 }
3624 assert(left == right - 1);
3625 assert(0 <= left && left < minweightslen);
3626 assert(minweights[left] <= capacity - fixedonesweight - weight );
3627 assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
3628
3629 /* now z = left */
3630 z = left;
3631 assert(z <= *liftrhs);
3632 }
3633
3634 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3635 liftcoef = (*liftrhs) - z;
3636 liftcoefs[liftvar] = liftcoef;
3637 assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
3638
3639 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3640 if( liftcoef == 0 )
3641 continue;
3642
3643 /* updates activity of current valid inequality */
3644 (*cutact) += liftcoef * solvals[liftvar];
3645
3646 /* enlarges current minweight table:
3647 * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3648 * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3649 * and sets minweights_i[w] = infinity for
3650 * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3651 */
3652 SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3653
3654 /* updates minweight table: minweight_i+1[w] =
3655 * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3656 * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3657 */
3658 for( w = minweightslen - 1; w >= 0; w-- )
3659 {
3660 SCIP_Longint min;
3661 if( w < liftcoef )
3662 {
3663 min = MIN(minweights[w], weight);
3664 minweights[w] = min;
3665 }
3666 else
3667 {
3668 assert(w >= liftcoef);
3669 min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3670 minweights[w] = min;
3671 }
3672 }
3673 }
3674 assert(minweights[0] == 0);
3675
3676 /* sequentially down-lifts all variables in M_2: */
3677 for( j = 0; j < nvarsM2; j++ )
3678 {
3679 SCIP_Longint weight;
3680 int liftvar;
3681 int liftcoef;
3682 int left;
3683 int right;
3684 int middle;
3685 int z;
3686
3687 liftvar = varsM2[j];
3688 weight = weights[liftvar];
3689 assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
3690 assert(liftvar >= 0 && liftvar < nvars);
3691 assert(weight > 0);
3692
3693 /* uses binary search to find
3694 * z = max { w : 0 <= w <= |M_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
3695 */
3696 left = 0;
3697 right = minweightslen;
3698 while( left < right - 1 )
3699 {
3700 middle = (left + right) / 2;
3701 assert(0 <= middle && middle < minweightslen);
3702 if( minweights[middle] <= capacity - fixedonesweight + weight )
3703 left = middle;
3704 else
3705 right = middle;
3706 }
3707 assert(left == right - 1);
3708 assert(0 <= left && left < minweightslen);
3709 assert(minweights[left] <= capacity - fixedonesweight + weight );
3710 assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight + weight);
3711
3712 /* now z = left */
3713 z = left;
3714 assert(z >= *liftrhs);
3715
3716 /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
3717 liftcoef = z - (*liftrhs);
3718 liftcoefs[liftvar] = liftcoef;
3719 assert(liftcoef >= 0);
3720
3721 /* updates sum of weights of variables fixed to one */
3722 fixedonesweight -= weight;
3723
3724 /* updates right-hand side of current valid inequality */
3725 (*liftrhs) += liftcoef;
3726 assert(*liftrhs >= alpha0);
3727
3728 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3729 if( liftcoef == 0 )
3730 continue;
3731
3732 /* updates activity of current valid inequality */
3733 (*cutact) += liftcoef * solvals[liftvar];
3734
3735 /* enlarges current minweight table:
3736 * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3737 * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3738 * and sets minweights_i[w] = infinity for
3739 * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3740 */
3741 SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3742
3743 /* updates minweight table: minweight_i+1[w] =
3744 * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3745 * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3746 */
3747 for( w = minweightslen - 1; w >= 0; w-- )
3748 {
3749 SCIP_Longint min;
3750 if( w < liftcoef )
3751 {
3752 min = MIN(minweights[w], weight);
3753 minweights[w] = min;
3754 }
3755 else
3756 {
3757 assert(w >= liftcoef);
3758 min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3759 minweights[w] = min;
3760 }
3761 }
3762 }
3763 assert(fixedonesweight == 0);
3764 assert(*liftrhs >= alpha0);
3765
3766 /* sequentially up-lifts all variables in R: */
3767 for( j = 0; j < nvarsR; j++ )
3768 {
3769 SCIP_Longint weight;
3770 int liftvar;
3771 int liftcoef;
3772 int z;
3773
3774 liftvar = varsR[j];
3775 weight = weights[liftvar];
3776 assert(liftvar >= 0 && liftvar < nvars);
3777 assert(SCIPisFeasEQ(scip, solvals[liftvar], 0.0));
3778 assert(weight > 0);
3779 assert(capacity - weight >= 0);
3780 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
3781
3782 /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
3783 * if minweights_i[liftrhs] <= a_0 - a_{j_i}
3784 */
3785 if( minweights[*liftrhs] <= capacity - weight )
3786 {
3787 z = *liftrhs;
3788 }
3789 /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
3790 */
3791 else
3792 {
3793 int left;
3794 int right;
3795 int middle;
3796
3797 left = 0;
3798 right = (*liftrhs) + 1;
3799 while( left < right - 1)
3800 {
3801 middle = (left + right) / 2;
3802 assert(0 <= middle && middle < minweightslen);
3803 if( minweights[middle] <= capacity - weight )
3804 left = middle;
3805 else
3806 right = middle;
3807 }
3808 assert(left == right - 1);
3809 assert(0 <= left && left < minweightslen);
3810 assert(minweights[left] <= capacity - weight );
3811 assert(left == minweightslen - 1 || minweights[left+1] > capacity - weight);
3812
3813 /* now z = left */
3814 z = left;
3815 assert(z <= *liftrhs);
3816 }
3817
3818 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3819 liftcoef = (*liftrhs) - z;
3820 liftcoefs[liftvar] = liftcoef;
3821 assert(liftcoef >= 0 && liftcoef <= *liftrhs);
3822
3823 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3824 if( liftcoef == 0 )
3825 continue;
3826
3827 /* updates activity of current valid inequality */
3828 (*cutact) += liftcoef * solvals[liftvar];
3829
3830 /* updates minweight table: minweight_i+1[w] =
3831 * min{ minweight_i[w], a_{j_i}}, if w < alpha_j_i
3832 * min{ minweight_i[w], minweight_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3833 */
3834 for( w = *liftrhs; w >= 0; w-- )
3835 {
3836 SCIP_Longint min;
3837 if( w < liftcoef )
3838 {
3839 min = MIN(minweights[w], weight);
3840 minweights[w] = min;
3841 }
3842 else
3843 {
3844 assert(w >= liftcoef);
3845 min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3846 minweights[w] = min;
3847 }
3848 }
3849 }
3850
3851 /* frees temporary memory */
3852 SCIPfreeBufferArray(scip, &sortkeys);
3853 SCIPfreeBufferArray(scip, &minweights);
3854
3855 return SCIP_OKAY;
3856}
3857
3858/** adds two minweight values in a safe way, i.e,, ensures no overflow */
3859static
3861 SCIP_Longint val1, /**< first value to add */
3862 SCIP_Longint val2 /**< second value to add */
3863 )
3864{
3865 assert(val1 >= 0);
3866 assert(val2 >= 0);
3867
3868 if( val1 >= SCIP_LONGINT_MAX || val2 >= SCIP_LONGINT_MAX )
3869 return SCIP_LONGINT_MAX;
3870 else
3871 {
3872 assert(val1 <= SCIP_LONGINT_MAX - val2);
3873 return (val1 + val2);
3874 }
3875}
3876
3877/** computes minweights table for lifting with GUBs by combining unfished and fished tables */
3878static
3880 SCIP_Longint* minweights, /**< minweight table to compute */
3881 SCIP_Longint* finished, /**< given finished table */
3882 SCIP_Longint* unfinished, /**< given unfinished table */
3883 int minweightslen /**< length of minweight, finished, and unfinished tables */
3884 )
3885{
3886 int w1;
3887 int w2;
3888
3889 /* minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
3890 * note that finished and unfished arrays sorted by non-decreasing weight
3891 */
3892
3893 /* initialize minweight with w2 = 0 */
3894 w2 = 0;
3895 assert(unfinished[w2] == 0);
3896 for( w1 = 0; w1 < minweightslen; w1++ )
3897 minweights[w1] = finished[w1];
3898
3899 /* consider w2 = 1, ..., minweightslen-1 */
3900 for( w2 = 1; w2 < minweightslen; w2++ )
3901 {
3902 if( unfinished[w2] >= SCIP_LONGINT_MAX )
3903 break;
3904
3905 for( w1 = 0; w1 < minweightslen - w2; w1++ )
3906 {
3907 SCIP_Longint temp;
3908
3909 temp = safeAddMinweightsGUB(finished[w1], unfinished[w2]);
3910 if( temp <= minweights[w1+w2] )
3911 minweights[w1+w2] = temp;
3912 }
3913 }
3914}
3915
3916/** lifts given inequality
3917 * sum_{j in C_1} x_j <= alpha_0
3918 * valid for
3919 * 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;
3920 * sum_{j in Q_i} x_j <= 1, forall i in I }
3921 * to a valid inequality
3922 * 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
3923 * <= alpha_0 + sum_{j in C_2} alpha_j
3924 * for
3925 * 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 };
3926 * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
3927 * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
3928 * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
3929 */
3930static
3932 SCIP* scip, /**< SCIP data structure */
3933 SCIP_GUBSET* gubset, /**< GUB set data structure */
3934 SCIP_VAR** vars, /**< variables in knapsack constraint */
3935 int ngubconscapexceed, /**< number of GUBs with only capacity exceeding variables */
3936 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3937 SCIP_Longint capacity, /**< capacity of knapsack */
3938 SCIP_Real* solvals, /**< solution values of all knapsack variables */
3939 int* gubconsGC1, /**< GUBs in GC1(GNC1+GOC1) */
3940 int* gubconsGC2, /**< GUBs in GC2 */
3941 int* gubconsGFC1, /**< GUBs in GFC1(GNC1+GF) */
3942 int* gubconsGR, /**< GUBs in GR */
3943 int ngubconsGC1, /**< number of GUBs in GC1(GNC1+GOC1) */
3944 int ngubconsGC2, /**< number of GUBs in GC2 */
3945 int ngubconsGFC1, /**< number of GUBs in GFC1(GNC1+GF) */
3946 int ngubconsGR, /**< number of GUBs in GR */
3947 int alpha0, /**< rights hand side of given valid inequality */
3948 int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3949 SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3950 int* liftrhs, /**< pointer to store right hand side of the lifted valid inequality */
3951 int maxgubvarssize /**< maximal size of GUB constraints */
3952 )
3953{
3954 SCIP_Longint* minweights;
3955 SCIP_Longint* finished;
3956 SCIP_Longint* unfinished;
3957 int* gubconsGOC1;
3958 int* gubconsGNC1;
3959 int* liftgubvars;
3960 SCIP_Longint fixedonesweight;
3961 SCIP_Longint weight;
3962 SCIP_Longint weightdiff1;
3963 SCIP_Longint weightdiff2;
3964 SCIP_Longint min;
3965 int minweightssize;
3966 int minweightslen;
3967 int nvars;
3968 int varidx;
3969 int liftgubconsidx;
3970 int liftvar;
3971 int sumliftcoef;
3972 int liftcoef;
3973 int ngubconsGOC1;
3974 int ngubconsGNC1;
3975 int left;
3976 int right;
3977 int middle;
3978 int nliftgubvars;
3979 int tmplen;
3980 int tmpsize;
3981 int j;
3982 int k;
3983 int w;
3984 int z;
3985#ifndef NDEBUG
3986 int ngubconss;
3987 int nliftgubC1;
3988
3989 assert(gubset != NULL);
3990 ngubconss = gubset->ngubconss;
3991#else
3992 assert(gubset != NULL);
3993#endif
3994
3995 nvars = gubset->nvars;
3996
3997 assert(scip != NULL);
3998 assert(vars != NULL);
3999 assert(nvars >= 0);
4000 assert(weights != NULL);
4001 assert(capacity >= 0);
4002 assert(solvals != NULL);
4003 assert(gubconsGC1 != NULL);
4004 assert(gubconsGC2 != NULL);
4005 assert(gubconsGFC1 != NULL);
4006 assert(gubconsGR != NULL);
4007 assert(ngubconsGC1 >= 0 && ngubconsGC1 <= ngubconss - ngubconscapexceed);
4008 assert(ngubconsGC2 >= 0 && ngubconsGC2 <= ngubconss - ngubconscapexceed);
4009 assert(ngubconsGFC1 >= 0 && ngubconsGFC1 <= ngubconss - ngubconscapexceed);
4010 assert(ngubconsGR >= 0 && ngubconsGR <= ngubconss - ngubconscapexceed);
4011 assert(alpha0 >= 0);
4012 assert(liftcoefs != NULL);
4013 assert(cutact != NULL);
4014 assert(liftrhs != NULL);
4015
4016 minweightssize = ngubconsGC1+1;
4017
4018 /* allocates temporary memory */
4019 SCIP_CALL( SCIPallocBufferArray(scip, &liftgubvars, maxgubvarssize) );
4020 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGOC1, ngubconsGC1) );
4021 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGNC1, ngubconsGC1) );
4022 SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
4023 SCIP_CALL( SCIPallocBufferArray(scip, &finished, minweightssize) );
4024 SCIP_CALL( SCIPallocBufferArray(scip, &unfinished, minweightssize) );
4025
4026 /* initializes data structures */
4027 BMSclearMemoryArray(liftcoefs, nvars);
4028 *cutact = 0.0;
4029
4030 /* gets GOC1 and GNC1 GUBs, sets lifting coefficient of variables in C1 and calculates activity of the current
4031 * valid inequality
4032 */
4033 ngubconsGOC1 = 0;
4034 ngubconsGNC1 = 0;
4035 for( j = 0; j < ngubconsGC1; j++ )
4036 {
4037 if( gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GOC1 )
4038 {
4039 gubconsGOC1[ngubconsGOC1] = gubconsGC1[j];
4040 ngubconsGOC1++;
4041 }
4042 else
4043 {
4044 assert(gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4045 gubconsGNC1[ngubconsGNC1] = gubconsGC1[j];
4046 ngubconsGNC1++;
4047 }
4048 for( k = 0; k < gubset->gubconss[gubconsGC1[j]]->ngubvars
4049 && gubset->gubconss[gubconsGC1[j]]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4050 {
4051 varidx = gubset->gubconss[gubconsGC1[j]]->gubvars[k];
4052 assert(varidx >= 0 && varidx < nvars);
4053 assert(liftcoefs[varidx] == 0);
4054
4055 liftcoefs[varidx] = 1;
4056 (*cutact) += solvals[varidx];
4057 }
4058 assert(k >= 1);
4059 }
4060 assert(ngubconsGOC1 + ngubconsGFC1 + ngubconsGC2 + ngubconsGR == ngubconss - ngubconscapexceed);
4061 assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4062
4063 /* initialize the minweight tables, defined as: for i = 1,...,m with m = |I| and w = 0,...,|gubconsGC1|;
4064 * - finished_i[w] =
4065 * min sum_{k = 1,2,...,i-1} sum_{j in Q_k} a_j x_j
4066 * s.t. sum_{k = 1,2,...,i-1} sum_{j in Q_k} alpha_j x_j >= w
4067 * sum_{j in Q_k} x_j <= 1
4068 * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4069 * - unfinished_i[w] =
4070 * min sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} a_j x_j
4071 * s.t. sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} x_j >= w
4072 * sum_{j in Q_k} x_j <= 1
4073 * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4074 * - minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
4075 */
4076
4077 /* initialize finished table; note that variables in GOC1 GUBs (includes C1 and capacity exceeding variables)
4078 * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4079 * 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
4080 * comes from the first variable in the GUB
4081 */
4082 assert(ngubconsGOC1 <= ngubconsGC1);
4083 finished[0] = 0;
4084 for( w = 1; w <= ngubconsGOC1; w++ )
4085 {
4086 liftgubconsidx = gubconsGOC1[w-1];
4087
4088 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1);
4089 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4090
4091 varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4092
4093 assert(varidx >= 0 && varidx < nvars);
4094 assert(liftcoefs[varidx] == 1);
4095
4096 min = weights[varidx];
4097 finished[w] = finished[w-1] + min;
4098
4099#ifndef NDEBUG
4100 for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4101 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4102 {
4103 varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4104 assert(varidx >= 0 && varidx < nvars);
4105 assert(liftcoefs[varidx] == 1);
4106 assert(weights[varidx] >= min);
4107 }
4108#endif
4109 }
4110 for( w = ngubconsGOC1+1; w <= ngubconsGC1; w++ )
4111 finished[w] = SCIP_LONGINT_MAX;
4112
4113 /* initialize unfinished table; note that variables in GNC1 GUBs
4114 * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4115 * 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
4116 * comes from the first variable in the GUB
4117 */
4118 assert(ngubconsGNC1 <= ngubconsGC1);
4119 unfinished[0] = 0;
4120 for( w = 1; w <= ngubconsGNC1; w++ )
4121 {
4122 liftgubconsidx = gubconsGNC1[w-1];
4123
4124 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4125 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4126
4127 varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4128
4129 assert(varidx >= 0 && varidx < nvars);
4130 assert(liftcoefs[varidx] == 1);
4131
4132 min = weights[varidx];
4133 unfinished[w] = unfinished[w-1] + min;
4134
4135#ifndef NDEBUG
4136 for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4137 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4138 {
4139 varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4140 assert(varidx >= 0 && varidx < nvars);
4141 assert(liftcoefs[varidx] == 1);
4142 assert(weights[varidx] >= min );
4143 }
4144#endif
4145 }
4146 for( w = ngubconsGNC1 + 1; w <= ngubconsGC1; w++ )
4147 unfinished[w] = SCIP_LONGINT_MAX;
4148
4149 /* initialize minweights table; note that variables in GC1 GUBs
4150 * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4151 * we can directly initialize minweights instead of computing it from finished and unfinished (which would be more time
4152 * consuming) because is it has to be build using weights from C1 only.
4153 */
4154 assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4155 minweights[0] = 0;
4156 for( w = 1; w <= ngubconsGC1; w++ )
4157 {
4158 liftgubconsidx = gubconsGC1[w-1];
4159
4160 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
4161 || gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4162 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4163
4164 varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4165
4166 assert(varidx >= 0 && varidx < nvars);
4167 assert(liftcoefs[varidx] == 1);
4168
4169 min = weights[varidx];
4170 minweights[w] = minweights[w-1] + min;
4171
4172#ifndef NDEBUG
4173 for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4174 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4175 {
4176 varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4177 assert(varidx >= 0 && varidx < nvars);
4178 assert(liftcoefs[varidx] == 1);
4179 assert(weights[varidx] >= min);
4180 }
4181#endif
4182 }
4183 minweightslen = ngubconsGC1 + 1;
4184
4185 /* gets sum of weights of variables fixed to one, i.e. sum of weights of C2 variables GC2 GUBs */
4186 fixedonesweight = 0;
4187 for( j = 0; j < ngubconsGC2; j++ )
4188 {
4189 varidx = gubset->gubconss[gubconsGC2[j]]->gubvars[0];
4190
4191 assert(gubset->gubconss[gubconsGC2[j]]->ngubvars == 1);
4192 assert(varidx >= 0 && varidx < nvars);
4193 assert(gubset->gubconss[gubconsGC2[j]]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4194
4195 fixedonesweight += weights[varidx];
4196 }
4197 assert(fixedonesweight >= 0);
4198
4199 /* initializes right hand side of lifted valid inequality */
4200 *liftrhs = alpha0;
4201
4202 /* sequentially up-lifts all variables in GFC1 GUBs */
4203 for( j = 0; j < ngubconsGFC1; j++ )
4204 {
4205 liftgubconsidx = gubconsGFC1[j];
4206 assert(liftgubconsidx >= 0 && liftgubconsidx < ngubconss);
4207
4208 /* GNC1 GUB: update unfinished table (remove current GUB, i.e., remove min weight of C1 vars in GUB) and
4209 * compute minweight table via updated unfinished table and aleady upto date finished table;
4210 */
4211 k = 0;
4212 if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4213 {
4214 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4215 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4216 assert(ngubconsGNC1 > 0);
4217
4218 /* get number of C1 variables of current GNC1 GUB and put them into array of variables in GUB that
4219 * are considered for the lifting, i.e., not capacity exceeding
4220 */
4221 for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars
4222 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4223 liftgubvars[k] = gubset->gubconss[liftgubconsidx]->gubvars[k];
4224 assert(k >= 1);
4225
4226 /* update unfinished table by removing current GNC1 GUB, i.e, remove C1 variable with minimal weight
4227 * unfinished[w] = MAX{unfinished[w], unfinished[w+1] - weight}, "weight" is the minimal weight of current GUB
4228 */
4229 weight = weights[liftgubvars[0]];
4230
4231 weightdiff2 = unfinished[ngubconsGNC1] - weight;
4232 unfinished[ngubconsGNC1] = SCIP_LONGINT_MAX;
4233 for( w = ngubconsGNC1-1; w >= 1; w-- )
4234 {
4235 weightdiff1 = weightdiff2;
4236 weightdiff2 = unfinished[w] - weight;
4237
4238 if( unfinished[w] < weightdiff1 )
4239 unfinished[w] = weightdiff1;
4240 else
4241 break;
4242 }
4243 ngubconsGNC1--;
4244
4245 /* computes minweights table by combining unfished and fished tables */
4246 computeMinweightsGUB(minweights, finished, unfinished, minweightslen);
4247 assert(minweights[0] == 0);
4248 }
4249 /* GF GUB: no update of unfinished table (and minweight table) required because GF GUBs have no C1 variables and
4250 * are therefore not in the unfinished table
4251 */
4252 else
4253 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4254
4255#ifndef NDEBUG
4256 nliftgubC1 = k;
4257#endif
4258 nliftgubvars = k;
4259 sumliftcoef = 0;
4260
4261 /* compute lifting coefficient of F and R variables in GNC1 and GF GUBs (C1 vars have already liftcoef 1) */
4262 for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4263 {
4264 if( gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_F
4265 || gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4266 {
4267 liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4268 weight = weights[liftvar];
4269 assert(weight > 0);
4270 assert(liftvar >= 0 && liftvar < nvars);
4271 assert(capacity - weight >= 0);
4272
4273 /* put variable into array of variables in GUB that are considered for the lifting,
4274 * i.e., not capacity exceeding
4275 */
4276 liftgubvars[nliftgubvars] = liftvar;
4277 nliftgubvars++;
4278
4279 /* knapsack problem is infeasible:
4280 * sets z = 0
4281 */
4282 if( capacity - fixedonesweight - weight < 0 )
4283 {
4284 z = 0;
4285 }
4286 /* knapsack problem is feasible:
4287 * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
4288 * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
4289 */
4290 else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
4291 {
4292 z = *liftrhs;
4293 }
4294 /* knapsack problem is feasible:
4295 * binary search to find z = max {w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i}}
4296 */
4297 else
4298 {
4299 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
4300 left = 0;
4301 right = (*liftrhs) + 1;
4302 while( left < right - 1 )
4303 {
4304 middle = (left + right) / 2;
4305 assert(0 <= middle && middle < minweightslen);
4306 if( minweights[middle] <= capacity - fixedonesweight - weight )
4307 left = middle;
4308 else
4309 right = middle;
4310 }
4311 assert(left == right - 1);
4312 assert(0 <= left && left < minweightslen);
4313 assert(minweights[left] <= capacity - fixedonesweight - weight);
4314 assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
4315
4316 /* now z = left */
4317 z = left;
4318 assert(z <= *liftrhs);
4319 }
4320
4321 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4322 liftcoef = (*liftrhs) - z;
4323 liftcoefs[liftvar] = liftcoef;
4324 assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4325
4326 /* updates activity of current valid inequality */
4327 (*cutact) += liftcoef * solvals[liftvar];
4328
4329 /* updates sum of all lifting coefficients in GUB */
4330 sumliftcoef += liftcoefs[liftvar];
4331 }
4332 else
4333 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4334 }
4335 /* at least one variable is in F or R (j = number of C1 variables in current GUB) */
4336 assert(nliftgubvars > nliftgubC1);
4337
4338 /* activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0
4339 * and finished and minweight table can be updated easily as only C1 variables need to be considered;
4340 * not needed for GF GUBs
4341 */
4342 if( sumliftcoef == 0 )
4343 {
4344 if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4345 {
4346 weight = weights[liftgubvars[0]];
4347 /* update finished table and minweights table by applying special case of
4348 * finished[w] = MIN{finished[w], finished[w-1] + weight}, "weight" is the minimal weight of current GUB
4349 * minweights[w] = MIN{minweights[w], minweights[w-1] + weight}, "weight" is the minimal weight of current GUB
4350 */
4351 for( w = minweightslen-1; w >= 1; w-- )
4352 {
4353 SCIP_Longint tmpval;
4354
4355 tmpval = safeAddMinweightsGUB(finished[w-1], weight);
4356 finished[w] = MIN(finished[w], tmpval);
4357
4358 tmpval = safeAddMinweightsGUB(minweights[w-1], weight);
4359 minweights[w] = MIN(minweights[w], tmpval);
4360 }
4361 }
4362 else
4363 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4364
4365 continue;
4366 }
4367
4368 /* enlarges current minweights tables(finished, unfinished, minweights):
4369 * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4370 * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4371 * and sets minweights_i[w] = infinity for
4372 * 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
4373 */
4374 tmplen = minweightslen; /* will be updated in enlargeMinweights() */
4375 tmpsize = minweightssize;
4376 SCIP_CALL( enlargeMinweights(scip, &unfinished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4377 tmplen = minweightslen;
4378 tmpsize = minweightssize;
4379 SCIP_CALL( enlargeMinweights(scip, &finished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4380 SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + sumliftcoef) );
4381
4382 /* update finished table and minweight table;
4383 * note that instead of computing minweight table from updated finished and updated unfinished table again
4384 * (for the lifting coefficient, we had to update unfinished table and compute minweight table), we here
4385 * only need to update the minweight table and the updated finished in the same way (i.e., computing for minweight
4386 * not needed because only finished table changed at this point and the change was "adding" one weight)
4387 *
4388 * update formular for minweight table is: minweight_i+1[w] =
4389 * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4390 * formular for finished table has the same pattern.
4391 */
4392 for( w = minweightslen-1; w >= 0; w-- )
4393 {
4394 SCIP_Longint minminweight;
4395 SCIP_Longint minfinished;
4396
4397 for( k = 0; k < nliftgubvars; k++ )
4398 {
4399 liftcoef = liftcoefs[liftgubvars[k]];
4400 weight = weights[liftgubvars[k]];
4401
4402 if( w < liftcoef )
4403 {
4404 minfinished = MIN(finished[w], weight);
4405 minminweight = MIN(minweights[w], weight);
4406
4407 finished[w] = minfinished;
4408 minweights[w] = minminweight;
4409 }
4410 else
4411 {
4412 SCIP_Longint tmpval;
4413
4414 assert(w >= liftcoef);
4415
4416 tmpval = safeAddMinweightsGUB(finished[w-liftcoef], weight);
4417 minfinished = MIN(finished[w], tmpval);
4418
4419 tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4420 minminweight = MIN(minweights[w], tmpval);
4421
4422 finished[w] = minfinished;
4423 minweights[w] = minminweight;
4424 }
4425 }
4426 }
4427 assert(minweights[0] == 0);
4428 }
4429 assert(ngubconsGNC1 == 0);
4430
4431 /* note: now the unfinished table no longer exists, i.e., it is "0, MAX, MAX, ..." and minweight equals to finished;
4432 * therefore, only work with minweight table from here on
4433 */
4434
4435 /* sequentially down-lifts C2 variables contained in trivial GC2 GUBs */
4436 for( j = 0; j < ngubconsGC2; j++ )
4437 {
4438 liftgubconsidx = gubconsGC2[j];
4439
4440 assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4441 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GC2);
4442 assert(gubset->gubconss[liftgubconsidx]->ngubvars == 1);
4443 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4444
4445 liftvar = gubset->gubconss[liftgubconsidx]->gubvars[0]; /* C2 GUBs contain only one variable */
4446 weight = weights[liftvar];
4447
4448 assert(liftvar >= 0 && liftvar < nvars);
4449 assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
4450 assert(weight > 0);
4451
4452 /* uses binary search to find
4453 * z = max { w : 0 <= w <= |C_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
4454 */
4455 left = 0;
4456 right = minweightslen;
4457 while( left < right - 1 )
4458 {
4459 middle = (left + right) / 2;
4460 assert(0 <= middle && middle < minweightslen);
4461 if( minweights[middle] <= capacity - fixedonesweight + weight )
4462 left = middle;
4463 else
4464 right = middle;
4465 }
4466 assert(left == right - 1);
4467 assert(0 <= left && left < minweightslen);
4468 assert(minweights[left] <= capacity - fixedonesweight + weight);
4469 assert(left == minweightslen - 1 || minweights[left + 1] > capacity - fixedonesweight + weight);
4470
4471 /* now z = left */
4472 z = left;
4473 assert(z >= *liftrhs);
4474
4475 /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
4476 liftcoef = z - (*liftrhs);
4477 liftcoefs[liftvar] = liftcoef;
4478 assert(liftcoef >= 0);
4479
4480 /* updates sum of weights of variables fixed to one */
4481 fixedonesweight -= weight;
4482
4483 /* updates right-hand side of current valid inequality */
4484 (*liftrhs) += liftcoef;
4485 assert(*liftrhs >= alpha0);
4486
4487 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
4488 if( liftcoef == 0 )
4489 continue;
4490
4491 /* updates activity of current valid inequality */
4492 (*cutact) += liftcoef * solvals[liftvar];
4493
4494 /* enlarges current minweight table:
4495 * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4496 * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4497 * and sets minweights_i[w] = infinity for
4498 * 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
4499 */
4500 SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
4501
4502 /* updates minweight table: minweight_i+1[w] =
4503 * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
4504 * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
4505 */
4506 for( w = minweightslen - 1; w >= 0; w-- )
4507 {
4508 if( w < liftcoef )
4509 {
4510 min = MIN(minweights[w], weight);
4511 minweights[w] = min;
4512 }
4513 else
4514 {
4515 SCIP_Longint tmpval;
4516
4517 assert(w >= liftcoef);
4518
4519 tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4520 min = MIN(minweights[w], tmpval);
4521 minweights[w] = min;
4522 }
4523 }
4524 }
4525 assert(fixedonesweight == 0);
4526 assert(*liftrhs >= alpha0);
4527
4528 /* sequentially up-lifts variables in GUB constraints in GR GUBs */
4529 for( j = 0; j < ngubconsGR; j++ )
4530 {
4531 liftgubconsidx = gubconsGR[j];
4532
4533 assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4534 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR);
4535
4536 sumliftcoef = 0;
4537 nliftgubvars = 0;
4538 for( k = 0; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4539 {
4540 if(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4541 {
4542 liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4543 weight = weights[liftvar];
4544 assert(weight > 0);
4545 assert(liftvar >= 0 && liftvar < nvars);
4546 assert(capacity - weight >= 0);
4547 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
4548
4549 /* put variable into array of variables in GUB that are considered for the lifting,
4550 * i.e., not capacity exceeding
4551 */
4552 liftgubvars[nliftgubvars] = liftvar;
4553 nliftgubvars++;
4554
4555 /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
4556 * if minweights_i[liftrhs] <= a_0 - a_{j_i}
4557 */
4558 if( minweights[*liftrhs] <= capacity - weight )
4559 {
4560 z = *liftrhs;
4561 }
4562 /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
4563 */
4564 else
4565 {
4566 left = 0;
4567 right = (*liftrhs) + 1;
4568 while( left < right - 1 )
4569 {
4570 middle = (left + right) / 2;
4571 assert(0 <= middle && middle < minweightslen);
4572 if( minweights[middle] <= capacity - weight )
4573 left = middle;
4574 else
4575 right = middle;
4576 }
4577 assert(left == right - 1);
4578 assert(0 <= left && left < minweightslen);
4579 assert(minweights[left] <= capacity - weight);
4580 assert(left == minweightslen - 1 || minweights[left + 1] > capacity - weight);
4581
4582 /* now z = left */
4583 z = left;
4584 assert(z <= *liftrhs);
4585 }
4586 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4587 liftcoef = (*liftrhs) - z;
4588 liftcoefs[liftvar] = liftcoef;
4589 assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4590
4591 /* updates activity of current valid inequality */
4592 (*cutact) += liftcoef * solvals[liftvar];
4593
4594 /* updates sum of all lifting coefficients in GUB */
4595 sumliftcoef += liftcoefs[liftvar];
4596 }
4597 else
4598 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4599 }
4600 assert(nliftgubvars >= 1); /* at least one variable is in R */
4601
4602 /* minweight table and activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0 */
4603 if( sumliftcoef == 0 )
4604 continue;
4605
4606 /* updates minweight table: minweight_i+1[w] =
4607 * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4608 */
4609 for( w = *liftrhs; w >= 0; w-- )
4610 {
4611 for( k = 0; k < nliftgubvars; k++ )
4612 {
4613 liftcoef = liftcoefs[liftgubvars[k]];
4614 weight = weights[liftgubvars[k]];
4615
4616 if( w < liftcoef )
4617 {
4618 min = MIN(minweights[w], weight);
4619 minweights[w] = min;
4620 }
4621 else
4622 {
4623 SCIP_Longint tmpval;
4624
4625 assert(w >= liftcoef);
4626
4627 tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4628 min = MIN(minweights[w], tmpval);
4629 minweights[w] = min;
4630 }
4631 }
4632 }
4633 assert(minweights[0] == 0);
4634 }
4635
4636 /* frees temporary memory */
4637 SCIPfreeBufferArray(scip, &minweights);
4638 SCIPfreeBufferArray(scip, &finished);
4639 SCIPfreeBufferArray(scip, &unfinished);
4640 SCIPfreeBufferArray(scip, &liftgubvars);
4641 SCIPfreeBufferArray(scip, &gubconsGOC1 );
4642 SCIPfreeBufferArray(scip, &gubconsGNC1);
4643
4644 return SCIP_OKAY;
4645}
4646
4647/** lifts given minimal cover inequality
4648 * \f[
4649 * \sum_{j \in C} x_j \leq |C| - 1
4650 * \f]
4651 * valid for
4652 * \f[
4653 * S^0 = \{ x \in {0,1}^{|C|} : \sum_{j \in C} a_j x_j \leq a_0 \}
4654 * \f]
4655 * to a valid inequality
4656 * \f[
4657 * \sum_{j \in C} x_j + \sum_{j \in N \setminus C} \alpha_j x_j \leq |C| - 1
4658 * \f]
4659 * for
4660 * \f[
4661 * S = \{ x \in {0,1}^{|N|} : \sum_{j \in N} a_j x_j \leq a_0 \};
4662 * \f]
4663 * uses superadditive up-lifting for the variables in \f$N \setminus C\f$.
4664 */
4665static
4667 SCIP* scip, /**< SCIP data structure */
4668 SCIP_VAR** vars, /**< variables in knapsack constraint */
4669 int nvars, /**< number of variables in knapsack constraint */
4670 int ntightened, /**< number of variables with tightened upper bound */
4671 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4672 SCIP_Longint capacity, /**< capacity of knapsack */
4673 SCIP_Real* solvals, /**< solution values of all problem variables */
4674 int* covervars, /**< cover variables */
4675 int* noncovervars, /**< noncover variables */
4676 int ncovervars, /**< number of cover variables */
4677 int nnoncovervars, /**< number of noncover variables */
4678 SCIP_Longint coverweight, /**< weight of cover */
4679 SCIP_Real* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
4680 SCIP_Real* cutact /**< pointer to store activity of lifted valid inequality */
4681 )
4682{
4683 SCIP_Longint* maxweightsums;
4684 SCIP_Longint* intervalends;
4685 SCIP_Longint* rhos;
4686 SCIP_Real* sortkeys;
4687 SCIP_Longint lambda;
4688 int j;
4689 int h;
4690
4691 assert(scip != NULL);
4692 assert(vars != NULL);
4693 assert(nvars >= 0);
4694 assert(weights != NULL);
4695 assert(capacity >= 0);
4696 assert(solvals != NULL);
4697 assert(covervars != NULL);
4698 assert(noncovervars != NULL);
4699 assert(ncovervars > 0 && ncovervars <= nvars);
4700 assert(nnoncovervars >= 0 && nnoncovervars <= nvars - ntightened);
4701 assert(ncovervars + nnoncovervars == nvars - ntightened);
4702 assert(liftcoefs != NULL);
4703 assert(cutact != NULL);
4704
4705 /* allocates temporary memory */
4706 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, ncovervars) );
4707 SCIP_CALL( SCIPallocBufferArray(scip, &maxweightsums, ncovervars + 1) );
4708 SCIP_CALL( SCIPallocBufferArray(scip, &intervalends, ncovervars) );
4709 SCIP_CALL( SCIPallocBufferArray(scip, &rhos, ncovervars) );
4710
4711 /* initializes data structures */
4712 BMSclearMemoryArray(liftcoefs, nvars);
4713 *cutact = 0.0;
4714
4715 /* sets lifting coefficient of variables in C, sorts variables in C such that a_1 >= a_2 >= ... >= a_|C|
4716 * and calculates activity of current valid inequality
4717 */
4718 for( j = 0; j < ncovervars; j++ )
4719 {
4720 assert(liftcoefs[covervars[j]] == 0.0);
4721 liftcoefs[covervars[j]] = 1.0;
4722 sortkeys[j] = (SCIP_Real) weights[covervars[j]];
4723 (*cutact) += solvals[covervars[j]];
4724 }
4725 SCIPsortDownRealInt(sortkeys, covervars, ncovervars);
4726
4727 /* calculates weight excess of cover C */
4728 lambda = coverweight - capacity;
4729 assert(lambda > 0);
4730
4731 /* calculates A_h for h = 0,...,|C|, I_h for h = 1,...,|C| and rho_h for h = 1,...,|C| */
4732 maxweightsums[0] = 0;
4733 for( h = 1; h <= ncovervars; h++ )
4734 {
4735 maxweightsums[h] = maxweightsums[h-1] + weights[covervars[h-1]];
4736 intervalends[h-1] = maxweightsums[h] - lambda;
4737 rhos[h-1] = MAX(0, weights[covervars[h-1]] - weights[covervars[0]] + lambda);
4738 }
4739
4740 /* sorts variables in N\C such that a_{j_1} <= a_{j_2} <= ... <= a_{j_t} */
4741 for( j = 0; j < nnoncovervars; j++ )
4742 sortkeys[j] = (SCIP_Real) (weights[noncovervars[j]]);
4743 SCIPsortRealInt(sortkeys, noncovervars, nnoncovervars);
4744
4745 /* calculates lifting coefficient for all variables in N\C */
4746 h = 0;
4747 for( j = 0; j < nnoncovervars; j++ )
4748 {
4749 int liftvar;
4750 SCIP_Longint weight;
4751 SCIP_Real liftcoef;
4752
4753 liftvar = noncovervars[j];
4754 weight = weights[liftvar];
4755
4756 while( intervalends[h] < weight )
4757 h++;
4758
4759 if( h == 0 )
4760 liftcoef = h;
4761 else
4762 {
4763 if( weight <= intervalends[h-1] + rhos[h] )
4764 {
4765 SCIP_Real tmp1;
4766 SCIP_Real tmp2;
4767 tmp1 = (SCIP_Real) (intervalends[h-1] + rhos[h] - weight);
4768 tmp2 = (SCIP_Real) rhos[1];
4769 liftcoef = h - ( tmp1 / tmp2 );
4770 }
4771 else
4772 liftcoef = h;
4773 }
4774
4775 /* sets lifting coefficient */
4776 assert(liftcoefs[liftvar] == 0.0);
4777 liftcoefs[liftvar] = liftcoef;
4778
4779 /* updates activity of current valid inequality */
4780 (*cutact) += liftcoef * solvals[liftvar];
4781 }
4782
4783 /* frees temporary memory */
4784 SCIPfreeBufferArray(scip, &rhos);
4785 SCIPfreeBufferArray(scip, &intervalends);
4786 SCIPfreeBufferArray(scip, &maxweightsums);
4787 SCIPfreeBufferArray(scip, &sortkeys);
4788
4789 return SCIP_OKAY;
4790}
4791
4792
4793/** separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information, if wanted, for
4794 * given knapsack problem
4795*/
4796static
4798 SCIP* scip, /**< SCIP data structure */
4799 SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
4800 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
4801 SCIP_VAR** vars, /**< variables in knapsack constraint */
4802 int nvars, /**< number of variables in knapsack constraint */
4803 int ntightened, /**< number of variables with tightened upper bound */
4804 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4805 SCIP_Longint capacity, /**< capacity of knapsack */
4806 SCIP_Real* solvals, /**< solution values of all problem variables */
4807 int* mincovervars, /**< mincover variables */
4808 int* nonmincovervars, /**< nonmincover variables */
4809 int nmincovervars, /**< number of mincover variables */
4810 int nnonmincovervars, /**< number of nonmincover variables */
4811 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
4812 SCIP_GUBSET* gubset, /**< GUB set data structure, NULL if no GUB information should be used */
4813 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
4814 int* ncuts /**< pointer to add up the number of found cuts */
4815 )
4816{
4817 int* varsC1;
4818 int* varsC2;
4819 int* varsF;
4820 int* varsR;
4821 int nvarsC1;
4822 int nvarsC2;
4823 int nvarsF;
4824 int nvarsR;
4825 SCIP_Real cutact;
4826 int* liftcoefs;
4827 int liftrhs;
4828
4829 assert( cutoff != NULL );
4830 *cutoff = FALSE;
4831
4832 /* allocates temporary memory */
4837 SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
4838
4839 /* 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
4840 * as follows
4841 * C_2 = { j in C : x*_j = 1 } and
4842 * C_1 = C\C_2
4843 */
4844 getPartitionCovervars(scip, solvals, mincovervars, nmincovervars, varsC1, varsC2, &nvarsC1, &nvarsC2);
4845 assert(nvarsC1 + nvarsC2 == nmincovervars);
4846 assert(nmincovervars > 0);
4847 assert(nvarsC1 >= 0); /* nvarsC1 > 0 does not always hold, because relaxed knapsack conss may already be violated */
4848
4849 /* changes partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one variable from C2 to C1 */
4850 if( nvarsC1 < 2 && nvarsC2 > 0)
4851 {
4852 SCIP_CALL( changePartitionCovervars(scip, weights, varsC1, varsC2, &nvarsC1, &nvarsC2) );
4853 assert(nvarsC1 >= 1);
4854 }
4855 assert(nvarsC2 == 0 || nvarsC1 >= 1);
4856
4857 /* gets partition (F,R) of N\C, i.e. F & R = N\C and F cap R = emptyset; chooses partition as follows
4858 * R = { j in N\C : x*_j = 0 } and
4859 * F = (N\C)\F
4860 */
4861 getPartitionNoncovervars(scip, solvals, nonmincovervars, nnonmincovervars, varsF, varsR, &nvarsF, &nvarsR);
4862 assert(nvarsF + nvarsR == nnonmincovervars);
4863 assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4864
4865 /* lift cuts without GUB information */
4866 if( gubset == NULL )
4867 {
4868 /* sorts variables in F, C_2, R according to the second level lifting sequence that will be used in the sequential
4869 * lifting procedure
4870 */
4871 SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsC2, varsR, nvarsF, nvarsC2, nvarsR) );
4872
4873 /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4874 *
4875 * 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 }
4876 *
4877 * 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
4878 *
4879 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
4880 *
4881 * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in C_2 and sequential
4882 * up-lifting for the variables in R according to the second level lifting sequence
4883 */
4884 SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsC1, varsC2,
4885 varsF, varsR, nvarsC1, nvarsC2, nvarsF, nvarsR, nvarsC1 - 1, liftcoefs, &cutact, &liftrhs) );
4886 }
4887 /* lift cuts with GUB information */
4888 else
4889 {
4890 int* gubconsGC1;
4891 int* gubconsGC2;
4892 int* gubconsGFC1;
4893 int* gubconsGR;
4894 int ngubconsGC1;
4895 int ngubconsGC2;
4896 int ngubconsGFC1;
4897 int ngubconsGR;
4898 int ngubconss;
4899 int nconstightened;
4900 int maxgubvarssize;
4901
4902 assert(nvars == gubset->nvars);
4903
4904 ngubconsGC1 = 0;
4905 ngubconsGC2 = 0;
4906 ngubconsGFC1 = 0;
4907 ngubconsGR = 0;
4908 ngubconss = gubset->ngubconss;
4909 nconstightened = 0;
4910 maxgubvarssize = 0;
4911
4912 /* allocates temporary memory */
4913 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC1, ngubconss) );
4914 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC2, ngubconss) );
4915 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGFC1, ngubconss) );
4917
4918 /* categorizies GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of
4919 * the GUBs for the sequential GUB wise lifting procedure
4920 */
4921 SCIP_CALL( getLiftingSequenceGUB(scip, gubset, solvals, weights, varsC1, varsC2, varsF, varsR, nvarsC1,
4922 nvarsC2, nvarsF, nvarsR, gubconsGC1, gubconsGC2, gubconsGFC1, gubconsGR, &ngubconsGC1, &ngubconsGC2,
4923 &ngubconsGFC1, &ngubconsGR, &nconstightened, &maxgubvarssize) );
4924
4925 /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4926 *
4927 * 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,
4928 * sum_{j in Q_i} x_j <= 1, forall i in I }
4929 *
4930 * 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
4931 *
4932 * 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 },
4933 *
4934 * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
4935 * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
4936 * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
4937 */
4938 SCIP_CALL( sequentialUpAndDownLiftingGUB(scip, gubset, vars, nconstightened, weights, capacity, solvals, gubconsGC1,
4939 gubconsGC2, gubconsGFC1, gubconsGR, ngubconsGC1, ngubconsGC2, ngubconsGFC1, ngubconsGR,
4940 MIN(nvarsC1 - 1, ngubconsGC1), liftcoefs, &cutact, &liftrhs, maxgubvarssize) );
4941
4942 /* frees temporary memory */
4943 SCIPfreeBufferArray(scip, &gubconsGR);
4944 SCIPfreeBufferArray(scip, &gubconsGFC1);
4945 SCIPfreeBufferArray(scip, &gubconsGC2);
4946 SCIPfreeBufferArray(scip, &gubconsGC1);
4947 }
4948
4949 /* checks, if lifting yielded a violated cut */
4950 if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
4951 {
4952 SCIP_ROW* row;
4953 char name[SCIP_MAXSTRLEN];
4954 int j;
4955
4956 /* creates LP row */
4957 assert( cons == NULL || sepa == NULL );
4958 if ( cons != NULL )
4959 {
4961 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
4962 cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
4963 cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
4964 }
4965 else if ( sepa != NULL )
4966 {
4967 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
4968 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4969 }
4970 else
4971 {
4972 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcseq_%d", *ncuts);
4974 }
4975
4976 /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
4978 assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4979 for( j = 0; j < nvarsC1; j++ )
4980 {
4981 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC1[j]], 1.0) );
4982 }
4983 for( j = 0; j < nvarsC2; j++ )
4984 {
4985 if( liftcoefs[varsC2[j]] > 0 )
4986 {
4987 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC2[j]], (SCIP_Real)liftcoefs[varsC2[j]]) );
4988 }
4989 }
4990 for( j = 0; j < nvarsF; j++ )
4991 {
4992 if( liftcoefs[varsF[j]] > 0 )
4993 {
4994 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
4995 }
4996 }
4997 for( j = 0; j < nvarsR; j++ )
4998 {
4999 if( liftcoefs[varsR[j]] > 0 )
5000 {
5001 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
5002 }
5003 }
5005
5006 /* checks, if cut is violated enough */
5007 if( SCIPisCutEfficacious(scip, sol, row) )
5008 {
5009 if( cons != NULL )
5010 {
5012 }
5013 SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5014 (*ncuts)++;
5015 }
5016 SCIP_CALL( SCIPreleaseRow(scip, &row) );
5017 }
5018
5019 /* frees temporary memory */
5020 SCIPfreeBufferArray(scip, &liftcoefs);
5021 SCIPfreeBufferArray(scip, &varsR);
5022 SCIPfreeBufferArray(scip, &varsF);
5023 SCIPfreeBufferArray(scip, &varsC2);
5024 SCIPfreeBufferArray(scip, &varsC1);
5025
5026 return SCIP_OKAY;
5027}
5028
5029/** separates lifted extended weight inequalities using sequential up- and down-lifting for given knapsack problem */
5030static
5032 SCIP* scip, /**< SCIP data structure */
5033 SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5034 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5035 SCIP_VAR** vars, /**< variables in knapsack constraint */
5036 int nvars, /**< number of variables in knapsack constraint */
5037 int ntightened, /**< number of variables with tightened upper bound */
5038 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5039 SCIP_Longint capacity, /**< capacity of knapsack */
5040 SCIP_Real* solvals, /**< solution values of all problem variables */
5041 int* feassetvars, /**< variables in feasible set */
5042 int* nonfeassetvars, /**< variables not in feasible set */
5043 int nfeassetvars, /**< number of variables in feasible set */
5044 int nnonfeassetvars, /**< number of variables not in feasible set */
5045 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5046 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5047 int* ncuts /**< pointer to add up the number of found cuts */
5048 )
5049{
5050 int* varsT1;
5051 int* varsT2;
5052 int* varsF;
5053 int* varsR;
5054 int* liftcoefs;
5055 SCIP_Real cutact;
5056 int nvarsT1;
5057 int nvarsT2;
5058 int nvarsF;
5059 int nvarsR;
5060 int liftrhs;
5061 int j;
5062
5063 assert( cutoff != NULL );
5064 *cutoff = FALSE;
5065
5066 /* allocates temporary memory */
5071 SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
5072
5073 /* 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
5074 * as follows
5075 * T_2 = { j in T : x*_j = 1 } and
5076 * T_1 = T\T_2
5077 */
5078 getPartitionCovervars(scip, solvals, feassetvars, nfeassetvars, varsT1, varsT2, &nvarsT1, &nvarsT2);
5079 assert(nvarsT1 + nvarsT2 == nfeassetvars);
5080
5081 /* changes partition (T_1,T_2) of feasible set T, if |T1| = 0, by moving one variable from T2 to T1 */
5082 if( nvarsT1 == 0 && nvarsT2 > 0)
5083 {
5084 SCIP_CALL( changePartitionFeasiblesetvars(scip, weights, varsT1, varsT2, &nvarsT1, &nvarsT2) );
5085 assert(nvarsT1 == 1);
5086 }
5087 assert(nvarsT2 == 0 || nvarsT1 > 0);
5088
5089 /* gets partition (F,R) of N\T, i.e. F & R = N\T and F cap R = emptyset; chooses partition as follows
5090 * R = { j in N\T : x*_j = 0 } and
5091 * F = (N\T)\F
5092 */
5093 getPartitionNoncovervars(scip, solvals, nonfeassetvars, nnonfeassetvars, varsF, varsR, &nvarsF, &nvarsR);
5094 assert(nvarsF + nvarsR == nnonfeassetvars);
5095 assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5096
5097 /* sorts variables in F, T_2, and R according to the second level lifting sequence that will be used in the sequential
5098 * lifting procedure (the variable removed last from the initial cover does not have to be lifted first, therefore it
5099 * is included in the sorting routine)
5100 */
5101 SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsT2, varsR, nvarsF, nvarsT2, nvarsR) );
5102
5103 /* lifts extended weight inequality sum_{j in T_1} x_j <= |T_1| valid for
5104 *
5105 * 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 }
5106 *
5107 * 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
5108 *
5109 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5110 *
5111 * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in T_2 and sequential
5112 * up-lifting for the variabels in R according to the second level lifting sequence
5113 */
5114 SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsT1, varsT2, varsF, varsR,
5115 nvarsT1, nvarsT2, nvarsF, nvarsR, nvarsT1, liftcoefs, &cutact, &liftrhs) );
5116
5117 /* checks, if lifting yielded a violated cut */
5118 if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5119 {
5120 SCIP_ROW* row;
5121 char name[SCIP_MAXSTRLEN];
5122
5123 /* creates LP row */
5124 assert( cons == NULL || sepa == NULL );
5125 if( cons != NULL )
5126 {
5129 cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5130 cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5131 }
5132 else if ( sepa != NULL )
5133 {
5134 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5135 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5136 }
5137 else
5138 {
5139 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_ewseq_%d", *ncuts);
5141 }
5142
5143 /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5145 assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5146 for( j = 0; j < nvarsT1; j++ )
5147 {
5148 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT1[j]], 1.0) );
5149 }
5150 for( j = 0; j < nvarsT2; j++ )
5151 {
5152 if( liftcoefs[varsT2[j]] > 0 )
5153 {
5154 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT2[j]], (SCIP_Real)liftcoefs[varsT2[j]]) );
5155 }
5156 }
5157 for( j = 0; j < nvarsF; j++ )
5158 {
5159 if( liftcoefs[varsF[j]] > 0 )
5160 {
5161 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
5162 }
5163 }
5164 for( j = 0; j < nvarsR; j++ )
5165 {
5166 if( liftcoefs[varsR[j]] > 0 )
5167 {
5168 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
5169 }
5170 }
5172
5173 /* checks, if cut is violated enough */
5174 if( SCIPisCutEfficacious(scip, sol, row) )
5175 {
5176 if( cons != NULL )
5177 {
5179 }
5180 SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5181 (*ncuts)++;
5182 }
5183 SCIP_CALL( SCIPreleaseRow(scip, &row) );
5184 }
5185
5186 /* frees temporary memory */
5187 SCIPfreeBufferArray(scip, &liftcoefs);
5188 SCIPfreeBufferArray(scip, &varsR);
5189 SCIPfreeBufferArray(scip, &varsF);
5190 SCIPfreeBufferArray(scip, &varsT2);
5191 SCIPfreeBufferArray(scip, &varsT1);
5192
5193 return SCIP_OKAY;
5194}
5195
5196/** separates lifted minimal cover inequalities using superadditive up-lifting for given knapsack problem */
5197static
5199 SCIP* scip, /**< SCIP data structure */
5200 SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5201 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5202 SCIP_VAR** vars, /**< variables in knapsack constraint */
5203 int nvars, /**< number of variables in knapsack constraint */
5204 int ntightened, /**< number of variables with tightened upper bound */
5205 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5206 SCIP_Longint capacity, /**< capacity of knapsack */
5207 SCIP_Real* solvals, /**< solution values of all problem variables */
5208 int* mincovervars, /**< mincover variables */
5209 int* nonmincovervars, /**< nonmincover variables */
5210 int nmincovervars, /**< number of mincover variables */
5211 int nnonmincovervars, /**< number of nonmincover variables */
5212 SCIP_Longint mincoverweight, /**< weight of minimal cover */
5213 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5214 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5215 int* ncuts /**< pointer to add up the number of found cuts */
5216 )
5217{
5218 SCIP_Real* realliftcoefs;
5219 SCIP_Real cutact;
5220 int liftrhs;
5221
5222 assert( cutoff != NULL );
5223 *cutoff = FALSE;
5224 cutact = 0.0;
5225
5226 /* allocates temporary memory */
5227 SCIP_CALL( SCIPallocBufferArray(scip, &realliftcoefs, nvars) );
5228
5229 /* lifts minimal cover inequality sum_{j in C} x_j <= |C| - 1 valid for
5230 *
5231 * S^0 = { x in {0,1}^|C| : sum_{j in C} a_j x_j <= a_0 }
5232 *
5233 * to a valid inequality sum_{j in C} x_j + sum_{j in N\C} alpha_j x_j <= |C| - 1 for
5234 *
5235 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5236 *
5237 * uses superadditive up-lifting for the variables in N\C.
5238 */
5239 SCIP_CALL( superadditiveUpLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, mincovervars,
5240 nonmincovervars, nmincovervars, nnonmincovervars, mincoverweight, realliftcoefs, &cutact) );
5241 liftrhs = nmincovervars - 1;
5242
5243 /* checks, if lifting yielded a violated cut */
5244 if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5245 {
5246 SCIP_ROW* row;
5247 char name[SCIP_MAXSTRLEN];
5248 int j;
5249
5250 /* creates LP row */
5251 assert( cons == NULL || sepa == NULL );
5252 if ( cons != NULL )
5253 {
5256 cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5257 cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5258 }
5259 else if ( sepa != NULL )
5260 {
5261 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5262 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5263 }
5264 else
5265 {
5266 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcsup_%d", *ncuts);
5268 }
5269
5270 /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5272 assert(nmincovervars + nnonmincovervars == nvars - ntightened);
5273 for( j = 0; j < nmincovervars; j++ )
5274 {
5275 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[mincovervars[j]], 1.0) );
5276 }
5277 for( j = 0; j < nnonmincovervars; j++ )
5278 {
5279 assert(SCIPisFeasGE(scip, realliftcoefs[nonmincovervars[j]], 0.0));
5280 if( SCIPisFeasGT(scip, realliftcoefs[nonmincovervars[j]], 0.0) )
5281 {
5282 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[nonmincovervars[j]], realliftcoefs[nonmincovervars[j]]) );
5283 }
5284 }
5286
5287 /* checks, if cut is violated enough */
5288 if( SCIPisCutEfficacious(scip, sol, row) )
5289 {
5290 if( cons != NULL )
5291 {
5293 }
5294 SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5295 (*ncuts)++;
5296 }
5297 SCIP_CALL( SCIPreleaseRow(scip, &row) );
5298 }
5299
5300 /* frees temporary memory */
5301 SCIPfreeBufferArray(scip, &realliftcoefs);
5302
5303 return SCIP_OKAY;
5304}
5305
5306/** converts given cover C to a minimal cover by removing variables in the reverse order in which the variables were chosen
5307 * 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
5308 * C and in the order of non-increasing (1 - x*_j), if the modified transformed separation problem was used to find C;
5309 * note that all variables with x*_j = 1 will be removed last
5310 */
5311static
5313 SCIP* scip, /**< SCIP data structure */
5314 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5315 SCIP_Longint capacity, /**< capacity of knapsack */
5316 SCIP_Real* solvals, /**< solution values of all problem variables */
5317 int* covervars, /**< pointer to store cover variables */
5318 int* noncovervars, /**< pointer to store noncover variables */
5319 int* ncovervars, /**< pointer to store number of cover variables */
5320 int* nnoncovervars, /**< pointer to store number of noncover variables */
5321 SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5322 SCIP_Bool modtransused /**< TRUE if mod trans sepa prob was used to find cover */
5323 )
5324{
5325 SORTKEYPAIR** sortkeypairs;
5326 SORTKEYPAIR** sortkeypairssorted;
5327 SCIP_Longint minweight;
5328 int nsortkeypairs;
5329 int minweightidx;
5330 int j;
5331 int k;
5332
5333 assert(scip != NULL);
5334 assert(covervars != NULL);
5335 assert(noncovervars != NULL);
5336 assert(ncovervars != NULL);
5337 assert(*ncovervars > 0);
5338 assert(nnoncovervars != NULL);
5339 assert(*nnoncovervars >= 0);
5340 assert(coverweight != NULL);
5341 assert(*coverweight > 0);
5342 assert(*coverweight > capacity);
5343
5344 /* allocates temporary memory; we need two arrays for the keypairs in order to be able to free them in the correct
5345 * order */
5346 nsortkeypairs = *ncovervars;
5347 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairs, nsortkeypairs) );
5348 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairssorted, nsortkeypairs) );
5349
5350 /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5351 * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5352 * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5353 * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5354 */
5355 assert(*ncovervars == nsortkeypairs);
5356 if( modtransused )
5357 {
5358 for( j = 0; j < *ncovervars; j++ )
5359 {
5360 SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5361 sortkeypairssorted[j] = sortkeypairs[j];
5362
5363 sortkeypairs[j]->key1 = solvals[covervars[j]];
5364 sortkeypairs[j]->key2 = (SCIP_Real) weights[covervars[j]];
5365 }
5366 }
5367 else
5368 {
5369 for( j = 0; j < *ncovervars; j++ )
5370 {
5371 SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5372 sortkeypairssorted[j] = sortkeypairs[j];
5373
5374 sortkeypairs[j]->key1 = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5375 sortkeypairs[j]->key2 = (SCIP_Real) (-weights[covervars[j]]);
5376 }
5377 }
5378 SCIPsortPtrInt((void**)sortkeypairssorted, covervars, compSortkeypairs, *ncovervars);
5379
5380 /* gets j' with a_j' = min{ a_j : j in C } */
5381 minweightidx = 0;
5382 minweight = weights[covervars[minweightidx]];
5383 for( j = 1; j < *ncovervars; j++ )
5384 {
5385 if( weights[covervars[j]] <= minweight )
5386 {
5387 minweightidx = j;
5388 minweight = weights[covervars[minweightidx]];
5389 }
5390 }
5391 assert(minweightidx >= 0 && minweightidx < *ncovervars);
5392 assert(minweight > 0 && minweight <= *coverweight);
5393
5394 j = 0;
5395 /* removes variables from C until the remaining variables form a minimal cover */
5396 while( j < *ncovervars && ((*coverweight) - minweight > capacity) )
5397 {
5398 assert(minweightidx >= j);
5399 assert(checkMinweightidx(weights, capacity, covervars, *ncovervars, *coverweight, minweightidx, j));
5400
5401 /* if sum_{i in C} a_i - a_j <= a_0, j cannot be removed from C */
5402 if( (*coverweight) - weights[covervars[j]] <= capacity )
5403 {
5404 ++j;
5405 continue;
5406 }
5407
5408 /* adds j to N\C */
5409 noncovervars[*nnoncovervars] = covervars[j];
5410 (*nnoncovervars)++;
5411
5412 /* removes j from C */
5413 (*coverweight) -= weights[covervars[j]];
5414 for( k = j; k < (*ncovervars) - 1; k++ )
5415 covervars[k] = covervars[k+1];
5416 (*ncovervars)--;
5417
5418 /* updates j' with a_j' = min{ a_j : j in C } */
5419 if( j == minweightidx )
5420 {
5421 minweightidx = 0;
5422 minweight = weights[covervars[minweightidx]];
5423 for( k = 1; k < *ncovervars; k++ )
5424 {
5425 if( weights[covervars[k]] <= minweight )
5426 {
5427 minweightidx = k;
5428 minweight = weights[covervars[minweightidx]];
5429 }
5430 }
5431 assert(minweight > 0 && minweight <= *coverweight);
5432 assert(minweightidx >= 0 && minweightidx < *ncovervars);
5433 }
5434 else
5435 {
5436 assert(minweightidx > j);
5437 minweightidx--;
5438 }
5439 /* j needs to stay the same */
5440 }
5441 assert((*coverweight) > capacity);
5442 assert((*coverweight) - minweight <= capacity);
5443
5444 /* frees temporary memory */
5445 for( j = nsortkeypairs-1; j >= 0; j-- )
5446 SCIPfreeBuffer(scip, &(sortkeypairs[j])); /*lint !e866 */
5447 SCIPfreeBufferArray(scip, &sortkeypairssorted);
5448 SCIPfreeBufferArray(scip, &sortkeypairs);
5449
5450 return SCIP_OKAY;
5451}
5452
5453/** converts given initial cover C_init to a feasible set by removing variables in the reverse order in which
5454 * they were chosen to be in C_init:
5455 * non-increasing (1 - x*_j)/a_j, if transformed separation problem was used to find C_init
5456 * non-increasing (1 - x*_j), if modified transformed separation problem was used to find C_init.
5457 * separates lifted extended weight inequalities using sequential up- and down-lifting for this feasible set
5458 * and all subsequent feasible sets.
5459 */
5460static
5462 SCIP* scip, /**< SCIP data structure */
5463 SCIP_CONS* cons, /**< constraint that originates the knapsack problem */
5464 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5465 SCIP_VAR** vars, /**< variables in knapsack constraint */
5466 int nvars, /**< number of variables in knapsack constraint */
5467 int ntightened, /**< number of variables with tightened upper bound */
5468 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5469 SCIP_Longint capacity, /**< capacity of knapsack */
5470 SCIP_Real* solvals, /**< solution values of all problem variables */
5471 int* covervars, /**< pointer to store cover variables */
5472 int* noncovervars, /**< pointer to store noncover variables */
5473 int* ncovervars, /**< pointer to store number of cover variables */
5474 int* nnoncovervars, /**< pointer to store number of noncover variables */
5475 SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5476 SCIP_Bool modtransused, /**< TRUE if mod trans sepa prob was used to find cover */
5477 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5478 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5479 int* ncuts /**< pointer to add up the number of found cuts */
5480 )
5481{
5482 SCIP_Real* sortkeys;
5483 int j;
5484 int k;
5485
5486 assert(scip != NULL);
5487 assert(covervars != NULL);
5488 assert(noncovervars != NULL);
5489 assert(ncovervars != NULL);
5490 assert(*ncovervars > 0);
5491 assert(nnoncovervars != NULL);
5492 assert(*nnoncovervars >= 0);
5493 assert(coverweight != NULL);
5494 assert(*coverweight > 0);
5495 assert(*coverweight > capacity);
5496 assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5497 assert(cutoff != NULL);
5498
5499 *cutoff = FALSE;
5500
5501 /* allocates temporary memory */
5502 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, *ncovervars) );
5503
5504 /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5505 * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5506 * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5507 * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5508 */
5509 if( modtransused )
5510 {
5511 for( j = 0; j < *ncovervars; j++ )
5512 {
5513 sortkeys[j] = solvals[covervars[j]];
5514 assert(SCIPisFeasGE(scip, sortkeys[j], 0.0));
5515 }
5516 }
5517 else
5518 {
5519 for( j = 0; j < *ncovervars; j++ )
5520 {
5521 sortkeys[j] = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5522 assert(SCIPisFeasLE(scip, sortkeys[j], 0.0));
5523 }
5524 }
5525 SCIPsortRealInt(sortkeys, covervars, *ncovervars);
5526
5527 /* removes variables from C_init and separates lifted extended weight inequalities using sequential up- and down-lifting;
5528 * in addition to an extended weight inequality this gives cardinality inequalities */
5529 while( *ncovervars >= 2 )
5530 {
5531 /* adds first element of C_init to N\C_init */
5532 noncovervars[*nnoncovervars] = covervars[0];
5533 (*nnoncovervars)++;
5534
5535 /* removes first element from C_init */
5536 (*coverweight) -= weights[covervars[0]];
5537 for( k = 0; k < (*ncovervars) - 1; k++ )
5538 covervars[k] = covervars[k+1];
5539 (*ncovervars)--;
5540
5541 assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5542 if( (*coverweight) <= capacity )
5543 {
5544 SCIP_CALL( separateSequLiftedExtendedWeightInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals,
5545 covervars, noncovervars, *ncovervars, *nnoncovervars, sol, cutoff, ncuts) );
5546 }
5547
5548 /* stop if cover is too large */
5549 if ( *ncovervars >= MAXCOVERSIZEITERLEWI )
5550 break;
5551 }
5552
5553 /* frees temporary memory */
5554 SCIPfreeBufferArray(scip, &sortkeys);
5555
5556 return SCIP_OKAY;
5557}
5558
5559/** separates different classes of valid inequalities for the 0-1 knapsack problem */
5561 SCIP* scip, /**< SCIP data structure */
5562 SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5563 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5564 SCIP_VAR** vars, /**< variables in knapsack constraint */
5565 int nvars, /**< number of variables in knapsack constraint */
5566 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5567 SCIP_Longint capacity, /**< capacity of knapsack */
5568 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5569 SCIP_Bool usegubs, /**< should GUB information be used for separation? */
5570 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
5571 int* ncuts /**< pointer to add up the number of found cuts */
5572 )
5573{
5574 SCIP_Real* solvals;
5575 int* covervars;
5576 int* noncovervars;
5577 SCIP_Bool coverfound;
5578 SCIP_Bool fractional;
5579 SCIP_Bool modtransused;
5580 SCIP_Longint coverweight;
5581 int ncovervars;
5582 int nnoncovervars;
5583 int ntightened;
5584
5585 assert(scip != NULL);
5586 assert(capacity >= 0);
5587 assert(cutoff != NULL);
5588 assert(ncuts != NULL);
5589
5590 *cutoff = FALSE;
5591
5592 if( nvars == 0 )
5593 return SCIP_OKAY;
5594
5595 assert(vars != NULL);
5596 assert(nvars > 0);
5597 assert(weights != NULL);
5598
5599 /* increase age of constraint (age is reset to zero, if a cut was found) */
5600 if( cons != NULL )
5601 {
5602 SCIP_CALL( SCIPincConsAge(scip, cons) );
5603 }
5604
5605 /* allocates temporary memory */
5607 SCIP_CALL( SCIPallocBufferArray(scip, &covervars, nvars) );
5608 SCIP_CALL( SCIPallocBufferArray(scip, &noncovervars, nvars) );
5609
5610 /* gets solution values of all problem variables */
5611 SCIP_CALL( SCIPgetSolVals(scip, sol, nvars, vars, solvals) );
5612
5613#ifdef SCIP_DEBUG
5614 {
5615 int i;
5616
5617 SCIPdebugMsg(scip, "separate cuts for knapsack constraint originated by cons <%s>:\n",
5618 cons == NULL ? "-" : SCIPconsGetName(cons));
5619 for( i = 0; i < nvars; ++i )
5620 {
5621 SCIPdebugMsgPrint(scip, "%+" SCIP_LONGINT_FORMAT "<%s>(%g)", weights[i], SCIPvarGetName(vars[i]), solvals[i]);
5622 }
5623 SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT "\n", capacity);
5624 }
5625#endif
5626
5627 /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting) using GUB information
5628 */
5629 if( usegubs )
5630 {
5631 SCIP_GUBSET* gubset;
5632
5633 SCIPdebugMsg(scip, "separate LMCI1-GUB cuts:\n");
5634
5635 /* initializes partion of knapsack variables into nonoverlapping GUB constraints */
5636 SCIP_CALL( GUBsetCreate(scip, &gubset, nvars, weights, capacity) );
5637
5638 /* constructs sophisticated partition of knapsack variables into nonoverlapping GUBs */
5639 SCIP_CALL( GUBsetGetCliquePartition(scip, gubset, vars, solvals) );
5640 assert(gubset->ngubconss <= nvars);
5641
5642 /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5643 * MODIFIED transformed separation problem and taking into account the following fixing:
5644 * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5645 * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5646 * if one exists
5647 */
5648 modtransused = TRUE;
5649 SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5650 &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5651
5652 assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5653
5654 /* if x* is not fractional we stop the separation routine */
5655 if( !fractional )
5656 {
5657 SCIPdebugMsg(scip, " LMCI1-GUB terminated by no variable with fractional LP value.\n");
5658
5659 /* frees memory for GUB set data structure */
5660 GUBsetFree(scip, &gubset);
5661
5662 goto TERMINATE;
5663 }
5664
5665 /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5666 if( coverfound )
5667 {
5668 /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5669 * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5670 */
5671 SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5672 &nnoncovervars, &coverweight, modtransused) );
5673
5674 /* only separate with GUB information if we have at least one nontrivial GUB (with more than one variable) */
5675 if( gubset->ngubconss < nvars )
5676 {
5677 /* separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information */
5678 SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5679 solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, gubset, cutoff, ncuts) );
5680 }
5681 else
5682 {
5683 /* separates lifted minimal cover inequalities using sequential up- and down-lifting, but do not use trivial
5684 * GUB information
5685 */
5686 SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5687 solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5688 }
5689 }
5690
5691 /* frees memory for GUB set data structure */
5692 GUBsetFree(scip, &gubset);
5693 }
5694 else
5695 {
5696 /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting)
5697 * (and LMCI2 (lifted minimal cover inequalities using superadditive up-lifting))
5698 */
5699
5700 /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5701 * MODIFIED transformed separation problem and taking into account the following fixing:
5702 * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5703 * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5704 * if one exists
5705 */
5706 SCIPdebugMsg(scip, "separate LMCI1 cuts:\n");
5707 modtransused = TRUE;
5708 SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5709 &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5710 assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5711
5712 /* if x* is not fractional we stop the separation routine */
5713 if( !fractional )
5714 goto TERMINATE;
5715
5716 /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5717 if( coverfound )
5718 {
5719 /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5720 * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5721 */
5722 SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5723 &nnoncovervars, &coverweight, modtransused) );
5724
5725 /* separates lifted minimal cover inequalities using sequential up- and down-lifting */
5726 SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5727 solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5728
5729 if( USESUPADDLIFT ) /*lint !e506 !e774*/
5730 {
5731 SCIPdebugMsg(scip, "separate LMCI2 cuts:\n");
5732 /* separates lifted minimal cover inequalities using superadditive up-lifting */
5733 SCIP_CALL( separateSupLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5734 solvals, covervars, noncovervars, ncovervars, nnoncovervars, coverweight, sol, cutoff, ncuts) );
5735 }
5736 }
5737 }
5738
5739 /* LEWI (lifted extended weight inequalities using sequential up- and down-lifting) */
5740 if ( ! (*cutoff) )
5741 {
5742 /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5743 * transformed separation problem and taking into account the following fixing:
5744 * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5745 * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5746 * if one exists
5747 */
5748 SCIPdebugMsg(scip, "separate LEWI cuts:\n");
5749 modtransused = FALSE;
5750 SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5751 &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5752 assert(fractional);
5753 assert(!coverfound || ncovervars + nnoncovervars == nvars - ntightened);
5754
5755 /* if no cover was found we stop the separation routine */
5756 if( coverfound )
5757 {
5758 /* converts initial cover C_init to a feasible set by removing variables in the reverse order in which
5759 * they were chosen to be in C_init and separates lifted extended weight inequalities using sequential
5760 * up- and down-lifting for this feasible set and all subsequent feasible sets.
5761 */
5762 SCIP_CALL( getFeasibleSet(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals, covervars, noncovervars,
5763 &ncovervars, &nnoncovervars, &coverweight, modtransused, sol, cutoff, ncuts) );
5764 }
5765 }
5766
5767 TERMINATE:
5768 /* frees temporary memory */
5769 SCIPfreeBufferArray(scip, &noncovervars);
5770 SCIPfreeBufferArray(scip, &covervars);
5771 SCIPfreeBufferArray(scip, &solvals);
5772
5773 return SCIP_OKAY;
5774}
5775
5776/* relaxes given general linear constraint into a knapsack constraint and separates lifted knapsack cover inequalities */
5778 SCIP* scip, /**< SCIP data structure */
5779 SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5780 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5781 int nknapvars, /**< number of variables in the continuous knapsack constraint */
5782 SCIP_VAR** knapvars, /**< variables in the continuous knapsack constraint */
5783 SCIP_Real* knapvals, /**< coefficients of the variables in the continuous knapsack constraint */
5784 SCIP_Real valscale, /**< -1.0 if lhs of row is used as rhs of c. k. constraint, +1.0 otherwise */
5785 SCIP_Real rhs, /**< right hand side of the continuous knapsack constraint */
5786 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
5787 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff was found */
5788 int* ncuts /**< pointer to add up the number of found cuts */
5789 )
5790{
5791 SCIP_VAR** binvars;
5792 SCIP_VAR** consvars;
5793 SCIP_Real* binvals;
5794 SCIP_Longint* consvals;
5795 SCIP_Longint minact;
5796 SCIP_Longint maxact;
5797 SCIP_Real intscalar;
5798 SCIP_Bool success;
5799 int nbinvars;
5800 int nconsvars;
5801 int i;
5802
5803 int* tmpindices;
5804 int tmp;
5805 SCIP_CONSHDLR* conshdlr;
5806 SCIP_CONSHDLRDATA* conshdlrdata;
5807 SCIP_Bool noknapsackconshdlr;
5808 SCIP_Bool usegubs;
5809
5810 assert(nknapvars > 0);
5811 assert(knapvars != NULL);
5812 assert(cutoff != NULL);
5813
5814 tmpindices = NULL;
5815
5816 SCIPdebugMsg(scip, "separate linear constraint <%s> relaxed to knapsack\n", cons != NULL ? SCIPconsGetName(cons) : "-");
5817 SCIPdebug( if( cons != NULL ) { SCIPdebugPrintCons(scip, cons, NULL); } );
5818
5819 binvars = SCIPgetVars(scip);
5820
5821 /* all variables which are of integral type can be potentially of binary type; this can be checked via the method SCIPvarIsBinary(var) */
5822 nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
5823
5824 *cutoff = FALSE;
5825
5826 if( nbinvars == 0 )
5827 return SCIP_OKAY;
5828
5829 /* set up data structures */
5830 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nbinvars) );
5831 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nbinvars) );
5832
5833 /* get conshdlrdata to use cleared memory */
5834 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
5835 if( conshdlr == NULL )
5836 {
5837 noknapsackconshdlr = TRUE;
5838 usegubs = DEFAULT_USEGUBS;
5839
5840 SCIP_CALL( SCIPallocBufferArray(scip, &binvals, nbinvars) );
5841 BMSclearMemoryArray(binvals, nbinvars);
5842 }
5843 else
5844 {
5845 noknapsackconshdlr = FALSE;
5846 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5847 assert(conshdlrdata != NULL);
5848 usegubs = conshdlrdata->usegubs;
5849
5850 SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, nknapvars) );
5851
5852 /* increase array size to avoid an endless loop in the next block; this might happen if continuous variables
5853 * change their types to SCIP_VARTYPE_BINARY during presolving
5854 */
5855 if( conshdlrdata->reals1size == 0 )
5856 {
5857 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, conshdlrdata->reals1size, 1) );
5858 conshdlrdata->reals1size = 1;
5859 conshdlrdata->reals1[0] = 0.0;
5860 }
5861
5862 assert(conshdlrdata->reals1size > 0);
5863
5864 /* next if condition should normally not be true, because it means that presolving has created more binary
5865 * variables than binary + integer variables existed at the constraint initialization method, but for example if you would
5866 * transform all integers into their binary representation then it maybe happens
5867 */
5868 if( conshdlrdata->reals1size < nbinvars )
5869 {
5870 int oldsize = conshdlrdata->reals1size;
5871
5872 conshdlrdata->reals1size = nbinvars;
5873 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, oldsize, conshdlrdata->reals1size) );
5874 BMSclearMemoryArray(&(conshdlrdata->reals1[oldsize]), conshdlrdata->reals1size - oldsize); /*lint !e866 */
5875 }
5876 binvals = conshdlrdata->reals1;
5877
5878 /* check for cleared array, all entries have to be zero */
5879#ifndef NDEBUG
5880 for( tmp = nbinvars - 1; tmp >= 0; --tmp )
5881 {
5882 assert(binvals[tmp] == 0);
5883 }
5884#endif
5885 }
5886
5887 tmp = 0;
5888
5889 /* relax continuous knapsack constraint:
5890 * 1. make all variables binary:
5891 * if x_j is continuous or integer variable substitute:
5892 * - a_j < 0: x_j = lb or x_j = b*z + d with variable lower bound b*z + d with binary variable z
5893 * - a_j > 0: x_j = ub or x_j = b*z + d with variable upper bound b*z + d with binary variable z
5894 * 2. convert coefficients of all variables to positive integers:
5895 * - scale all coefficients a_j to a~_j integral
5896 * - substitute x~_j = 1 - x_j if a~_j < 0
5897 */
5898
5899 /* replace integer and continuous variables with binary variables */
5900 for( i = 0; i < nknapvars; i++ )
5901 {
5902 SCIP_VAR* var;
5903
5904 var = knapvars[i];
5905
5906 if( SCIPvarIsBinary(var) && SCIPvarIsActive(var) )
5907 {
5908 SCIP_Real solval;
5909 assert(0 <= SCIPvarGetProbindex(var) && SCIPvarGetProbindex(var) < nbinvars);
5910
5911 solval = SCIPgetSolVal(scip, sol, var);
5912
5913 /* knapsack relaxation assumes solution values between 0.0 and 1.0 for binary variables */
5914 if( SCIPisFeasLT(scip, solval, 0.0 )
5915 || SCIPisFeasGT(scip, solval, 1.0) )
5916 {
5917 SCIPdebugMsg(scip, "Solution value %.15g <%s> outside domain [0.0, 1.0]\n",
5918 solval, SCIPvarGetName(var));
5919 goto TERMINATE;
5920 }
5921
5922 binvals[SCIPvarGetProbindex(var)] += valscale * knapvals[i];
5923 if( !noknapsackconshdlr )
5924 {
5925 assert(tmpindices != NULL);
5926
5927 tmpindices[tmp] = SCIPvarGetProbindex(var);
5928 ++tmp;
5929 }
5930 SCIPdebugMsg(scip, " -> binary variable %+.15g<%s>(%.15g)\n", valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var));
5931 }
5932 else if( valscale * knapvals[i] > 0.0 )
5933 {
5934 SCIP_VAR** zvlb;
5935 SCIP_Real* bvlb;
5936 SCIP_Real* dvlb;
5937 SCIP_Real bestlbsol;
5938 int bestlbtype;
5939 int nvlb;
5940 int j;
5941
5942 /* a_j > 0: substitution with lb or vlb */
5943 nvlb = SCIPvarGetNVlbs(var);
5944 zvlb = SCIPvarGetVlbVars(var);
5945 bvlb = SCIPvarGetVlbCoefs(var);
5946 dvlb = SCIPvarGetVlbConstants(var);
5947
5948 /* search for lb or vlb with maximal bound value */
5949 bestlbsol = SCIPvarGetLbGlobal(var);
5950 bestlbtype = -1;
5951 for( j = 0; j < nvlb; j++ )
5952 {
5953 /* use only numerical stable vlb with binary variable z */
5954 if( SCIPvarIsBinary(zvlb[j]) && SCIPvarIsActive(zvlb[j]) && REALABS(bvlb[j]) <= MAXABSVBCOEF )
5955 {
5956 SCIP_Real vlbsol;
5957
5958 if( (bvlb[j] >= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetLbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) ||
5959 (bvlb[j] <= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetUbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) )
5960 {
5961 *cutoff = TRUE;
5962 SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] >= %g<%s>[%g,%g] + %g implies local cutoff\n",
5964 bvlb[j], SCIPvarGetName(zvlb[j]), SCIPvarGetLbLocal(zvlb[j]), SCIPvarGetUbLocal(zvlb[j]), dvlb[j]);
5965 goto TERMINATE;
5966 }
5967
5968 assert(0 <= SCIPvarGetProbindex(zvlb[j]) && SCIPvarGetProbindex(zvlb[j]) < nbinvars);
5969 vlbsol = bvlb[j] * SCIPgetSolVal(scip, sol, zvlb[j]) + dvlb[j];
5970 if( SCIPisGE(scip, vlbsol, bestlbsol) )
5971 {
5972 bestlbsol = vlbsol;
5973 bestlbtype = j;
5974 }
5975 }
5976 }
5977
5978 /* if no lb or vlb with binary variable was found, we have to abort */
5979 if( SCIPisInfinity(scip, -bestlbsol) )
5980 goto TERMINATE;
5981
5982 if( bestlbtype == -1 )
5983 {
5984 rhs -= valscale * knapvals[i] * bestlbsol;
5985 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with lower bound %.15g (rhs=%.15g)\n",
5986 valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetLbGlobal(var), rhs);
5987 }
5988 else
5989 {
5990 assert(0 <= SCIPvarGetProbindex(zvlb[bestlbtype]) && SCIPvarGetProbindex(zvlb[bestlbtype]) < nbinvars);
5991 rhs -= valscale * knapvals[i] * dvlb[bestlbtype];
5992 binvals[SCIPvarGetProbindex(zvlb[bestlbtype])] += valscale * knapvals[i] * bvlb[bestlbtype];
5993
5994 if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvlb[bestlbtype])])) )
5995 goto TERMINATE;
5996
5997 if( !noknapsackconshdlr )
5998 {
5999 assert(tmpindices != NULL);
6000
6001 tmpindices[tmp] = SCIPvarGetProbindex(zvlb[bestlbtype]);
6002 ++tmp;
6003 }
6004 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable lower bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
6005 valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
6006 bvlb[bestlbtype], SCIPvarGetName(zvlb[bestlbtype]),
6007 SCIPgetSolVal(scip, sol, zvlb[bestlbtype]), dvlb[bestlbtype], rhs);
6008 }
6009 }
6010 else
6011 {
6012 SCIP_VAR** zvub;
6013 SCIP_Real* bvub;
6014 SCIP_Real* dvub;
6015 SCIP_Real bestubsol;
6016 int bestubtype;
6017 int nvub;
6018 int j;
6019
6020 assert(valscale * knapvals[i] < 0.0);
6021
6022 /* a_j < 0: substitution with ub or vub */
6023 nvub = SCIPvarGetNVubs(var);
6024 zvub = SCIPvarGetVubVars(var);
6025 bvub = SCIPvarGetVubCoefs(var);
6026 dvub = SCIPvarGetVubConstants(var);
6027
6028 /* search for ub or vub with minimal bound value */
6029 bestubsol = SCIPvarGetUbGlobal(var);
6030 bestubtype = -1;
6031 for( j = 0; j < nvub; j++ )
6032 {
6033 /* use only numerical stable vub with active binary variable z */
6034 if( SCIPvarIsBinary(zvub[j]) && SCIPvarIsActive(zvub[j]) && REALABS(bvub[j]) <= MAXABSVBCOEF )
6035 {
6036 SCIP_Real vubsol;
6037
6038 if( (bvub[j] >= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetUbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) ||
6039 (bvub[j] <= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetLbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) )
6040 {
6041 *cutoff = TRUE;
6042 SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] <= %g<%s>[%g,%g] + %g implies local cutoff\n",
6044 bvub[j], SCIPvarGetName(zvub[j]), SCIPvarGetLbLocal(zvub[j]), SCIPvarGetUbLocal(zvub[j]), dvub[j]);
6045 goto TERMINATE;
6046 }
6047
6048 assert(0 <= SCIPvarGetProbindex(zvub[j]) && SCIPvarGetProbindex(zvub[j]) < nbinvars);
6049 vubsol = bvub[j] * SCIPgetSolVal(scip, sol, zvub[j]) + dvub[j];
6050 if( SCIPisLE(scip, vubsol, bestubsol) )
6051 {
6052 bestubsol = vubsol;
6053 bestubtype = j;
6054 }
6055 }
6056 }
6057
6058 /* if no ub or vub with binary variable was found, we have to abort */
6059 if( SCIPisInfinity(scip, bestubsol) )
6060 goto TERMINATE;
6061
6062 if( bestubtype == -1 )
6063 {
6064 rhs -= valscale * knapvals[i] * bestubsol;
6065 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with upper bound %.15g (rhs=%.15g)\n",
6066 valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetUbGlobal(var), rhs);
6067 }
6068 else
6069 {
6070 assert(0 <= SCIPvarGetProbindex(zvub[bestubtype]) && SCIPvarGetProbindex(zvub[bestubtype]) < nbinvars);
6071 rhs -= valscale * knapvals[i] * dvub[bestubtype];
6072 binvals[SCIPvarGetProbindex(zvub[bestubtype])] += valscale * knapvals[i] * bvub[bestubtype];
6073
6074 if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvub[bestubtype])])) )
6075 goto TERMINATE;
6076
6077 if( !noknapsackconshdlr )
6078 {
6079 assert(tmpindices != NULL);
6080
6081 tmpindices[tmp] = SCIPvarGetProbindex(zvub[bestubtype]);
6082 ++tmp;
6083 }
6084 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable upper bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
6085 valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
6086 bvub[bestubtype], SCIPvarGetName(zvub[bestubtype]),
6087 SCIPgetSolVal(scip, sol, zvub[bestubtype]), dvub[bestubtype], rhs);
6088 }
6089 }
6090 }
6091
6092 /* convert coefficients of all (now binary) variables to positive integers:
6093 * - make all coefficients integral
6094 * - make all coefficients positive (substitute negated variable)
6095 */
6096 nconsvars = 0;
6097
6098 /* calculate scalar which makes all coefficients integral in relative allowed difference in between
6099 * -SCIPepsilon(scip) and KNAPSACKRELAX_MAXDELTA
6100 */
6102 KNAPSACKRELAX_MAXDNOM, KNAPSACKRELAX_MAXSCALE, &intscalar, &success) );
6103 SCIPdebugMsg(scip, " -> intscalar = %.15g\n", intscalar);
6104
6105 /* if coefficients cannot be made integral, we have to use a scalar of 1.0 and only round fractional coefficients down */
6106 if( !success )
6107 intscalar = 1.0;
6108
6109 /* make all coefficients integral and positive:
6110 * - scale a~_j = a_j * intscalar
6111 * - substitute x~_j = 1 - x_j if a~_j < 0
6112 */
6113 rhs = rhs * intscalar;
6114
6115 SCIPdebugMsg(scip, " -> rhs = %.15g\n", rhs);
6116 minact = 0;
6117 maxact = 0;
6118 for( i = 0; i < nbinvars; i++ )
6119 {
6120 SCIP_VAR* var;
6121 SCIP_Longint val;
6122
6123 val = (SCIP_Longint)SCIPfloor(scip, binvals[i] * intscalar);
6124 if( val == 0 )
6125 continue;
6126
6127 if( val > 0 )
6128 {
6129 var = binvars[i];
6130 SCIPdebugMsg(scip, " -> positive scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): not changed (rhs=%.15g)\n",
6131 val, SCIPvarGetName(var), binvals[i], rhs);
6132 }
6133 else
6134 {
6135 assert(val < 0);
6136
6137 SCIP_CALL( SCIPgetNegatedVar(scip, binvars[i], &var) );
6138 val = -val; /*lint !e2704*/
6139 rhs += val;
6140 SCIPdebugMsg(scip, " -> negative scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): substituted by (1 - <%s>) (rhs=%.15g)\n",
6141 -val, SCIPvarGetName(binvars[i]), binvals[i], SCIPvarGetName(var), rhs);
6142 }
6143
6144 if( SCIPvarGetLbLocal(var) > 0.5 )
6145 minact += val;
6146 if( SCIPvarGetUbLocal(var) > 0.5 )
6147 maxact += val;
6148 consvals[nconsvars] = val;
6149 consvars[nconsvars] = var;
6150 nconsvars++;
6151 }
6152
6153 if( nconsvars > 0 )
6154 {
6155 SCIP_Longint capacity;
6156
6157 assert(consvars != NULL);
6158 assert(consvals != NULL);
6159 capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
6160
6161#ifdef SCIP_DEBUG
6162 {
6163 SCIP_Real act;
6164
6165 SCIPdebugMsg(scip, " -> linear constraint <%s> relaxed to knapsack:", cons != NULL ? SCIPconsGetName(cons) : "-");
6166 act = 0.0;
6167 for( i = 0; i < nconsvars; ++i )
6168 {
6169 SCIPdebugMsgPrint(scip, " %+" SCIP_LONGINT_FORMAT "<%s>(%.15g)", consvals[i], SCIPvarGetName(consvars[i]),
6170 SCIPgetSolVal(scip, sol, consvars[i]));
6171 act += consvals[i] * SCIPgetSolVal(scip, sol, consvars[i]);
6172 }
6173 SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT " (%.15g) [act: %.15g, min: %" SCIP_LONGINT_FORMAT " max: %" SCIP_LONGINT_FORMAT "]\n",
6174 capacity, rhs, act, minact, maxact);
6175 }
6176#endif
6177
6178 if( minact > capacity )
6179 {
6180 SCIPdebugMsg(scip, "minactivity of knapsack relaxation implies local cutoff\n");
6181 *cutoff = TRUE;
6182 goto TERMINATE;
6183 }
6184
6185 if( maxact > capacity )
6186 {
6187 /* separate lifted cut from relaxed knapsack constraint */
6188 SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, sepa, consvars, nconsvars, consvals, capacity, sol, usegubs, cutoff, ncuts) );
6189 }
6190 }
6191
6192 TERMINATE:
6193 /* free data structures */
6194 if( noknapsackconshdlr)
6195 {
6196 SCIPfreeBufferArray(scip, &binvals);
6197 }
6198 else
6199 {
6200 /* clear binvals */
6201 for( --tmp; tmp >= 0; --tmp)
6202 {
6203 assert(tmpindices != NULL);
6204 binvals[tmpindices[tmp]] = 0;
6205 }
6206 SCIPfreeBufferArray(scip, &tmpindices);
6207 }
6208 SCIPfreeBufferArray(scip, &consvals);
6209 SCIPfreeBufferArray(scip, &consvars);
6210
6211 return SCIP_OKAY;
6212}
6213
6214/** separates given knapsack constraint */
6215static
6217 SCIP* scip, /**< SCIP data structure */
6218 SCIP_CONS* cons, /**< knapsack constraint */
6219 SCIP_SOL* sol, /**< primal SCIP solution, NULL for current LP solution */
6220 SCIP_Bool sepacuts, /**< should knapsack cuts be separated? */
6221 SCIP_Bool usegubs, /**< should GUB information be used for separation? */
6222 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
6223 int* ncuts /**< pointer to add up the number of found cuts */
6224 )
6225{
6226 SCIP_CONSDATA* consdata;
6227 SCIP_Bool violated;
6228
6229 assert(ncuts != NULL);
6230 assert(cutoff != NULL);
6231 *cutoff = FALSE;
6232
6233 consdata = SCIPconsGetData(cons);
6234 assert(consdata != NULL);
6235
6236 SCIPdebugMsg(scip, "separating knapsack constraint <%s>\n", SCIPconsGetName(cons));
6237
6238 /* check knapsack constraint itself for feasibility */
6239 SCIP_CALL( checkCons(scip, cons, sol, (sol != NULL), FALSE, &violated) );
6240
6241 if( violated )
6242 {
6243 /* add knapsack constraint as LP row to the LP */
6244 SCIP_CALL( addRelaxation(scip, cons, cutoff) );
6245 (*ncuts)++;
6246 }
6247 else if( sepacuts )
6248 {
6249 SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, NULL, consdata->vars, consdata->nvars, consdata->weights,
6250 consdata->capacity, sol, usegubs, cutoff, ncuts) );
6251 }
6252
6253 return SCIP_OKAY;
6254}
6255
6256/** adds coefficient to constraint data */
6257static
6259 SCIP* scip, /**< SCIP data structure */
6260 SCIP_CONS* cons, /**< knapsack constraint */
6261 SCIP_VAR* var, /**< variable to add to knapsack */
6262 SCIP_Longint weight /**< weight of variable in knapsack */
6263 )
6264{
6265 SCIP_CONSDATA* consdata;
6266
6267 consdata = SCIPconsGetData(cons);
6268 assert(consdata != NULL);
6269 assert(SCIPvarIsBinary(var));
6270 assert(weight > 0);
6271
6272 /* add the new coefficient to the LP row */
6273 if( consdata->row != NULL )
6274 {
6275 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, (SCIP_Real)weight) );
6276 }
6277
6278 /* check for fixed variable */
6279 if( SCIPvarGetLbGlobal(var) > 0.5 )
6280 {
6281 /* variable is fixed to one: reduce capacity */
6282 consdata->capacity -= weight;
6283 }
6284 else if( SCIPvarGetUbGlobal(var) > 0.5 )
6285 {
6286 SCIP_Bool negated;
6287
6288 /* get binary representative of variable */
6289 SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &var, &negated) );
6290
6291 /* insert coefficient */
6292 SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1, SCIPconsIsTransformed(cons)) );
6293 consdata->vars[consdata->nvars] = var;
6294 consdata->weights[consdata->nvars] = weight;
6295 consdata->nvars++;
6296
6297 /* capture variable */
6298 SCIP_CALL( SCIPcaptureVar(scip, var) );
6299
6300 /* install the rounding locks of variable */
6301 SCIP_CALL( lockRounding(scip, cons, var) );
6302
6303 /* catch events */
6304 if( SCIPconsIsTransformed(cons) )
6305 {
6306 SCIP_CONSHDLRDATA* conshdlrdata;
6307
6308 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6309 assert(conshdlrdata != NULL);
6310 SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[consdata->nvars-1], cons, weight) );
6312 conshdlrdata->eventhdlr, consdata->eventdata[consdata->nvars-1],
6313 &consdata->eventdata[consdata->nvars-1]->filterpos) );
6314
6315 if( !consdata->existmultaggr && SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR )
6316 consdata->existmultaggr = TRUE;
6317
6318 /* mark constraint to be propagated and presolved */
6320 consdata->presolvedtiming = 0;
6321 consdata->cliquesadded = FALSE; /* new coefficient might lead to larger cliques */
6322 }
6323
6324 /* update weight sums */
6325 updateWeightSums(consdata, var, weight);
6326
6327 consdata->sorted = FALSE;
6328 consdata->cliquepartitioned = FALSE;
6329 consdata->negcliquepartitioned = FALSE;
6330 consdata->merged = FALSE;
6331 }
6332
6333 return SCIP_OKAY;
6334}
6335
6336/** deletes coefficient at given position from constraint data */
6337static
6339 SCIP* scip, /**< SCIP data structure */
6340 SCIP_CONS* cons, /**< knapsack constraint */
6341 int pos /**< position of coefficient to delete */
6342 )
6343{
6344 SCIP_CONSDATA* consdata;
6345 SCIP_VAR* var;
6346
6347 consdata = SCIPconsGetData(cons);
6348 assert(consdata != NULL);
6349 assert(0 <= pos && pos < consdata->nvars);
6350
6351 var = consdata->vars[pos];
6352 assert(var != NULL);
6353 assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
6354
6355 /* delete the coefficient from the LP row */
6356 if( consdata->row != NULL )
6357 {
6358 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, -(SCIP_Real)consdata->weights[pos]) );
6359 }
6360
6361 /* remove the rounding locks of variable */
6362 SCIP_CALL( unlockRounding(scip, cons, var) );
6363
6364 /* drop events and mark constraint to be propagated and presolved */
6365 if( SCIPconsIsTransformed(cons) )
6366 {
6367 SCIP_CONSHDLRDATA* conshdlrdata;
6368
6369 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6370 assert(conshdlrdata != NULL);
6372 conshdlrdata->eventhdlr, consdata->eventdata[pos], consdata->eventdata[pos]->filterpos) );
6373 SCIP_CALL( eventdataFree(scip, &consdata->eventdata[pos]) );
6374
6376 consdata->presolvedtiming = 0;
6377 consdata->sorted = (consdata->sorted && pos == consdata->nvars - 1);
6378 }
6379
6380 /* decrease weight sums */
6381 updateWeightSums(consdata, var, -consdata->weights[pos]);
6382
6383 /* move the last variable to the free slot */
6384 consdata->vars[pos] = consdata->vars[consdata->nvars-1];
6385 consdata->weights[pos] = consdata->weights[consdata->nvars-1];
6386 if( consdata->eventdata != NULL )
6387 consdata->eventdata[pos] = consdata->eventdata[consdata->nvars-1];
6388
6389 /* release variable */
6390 SCIP_CALL( SCIPreleaseVar(scip, &var) );
6391
6392 /* try to use old clique partitions */
6393 if( consdata->cliquepartitioned )
6394 {
6395 assert(consdata->cliquepartition != NULL);
6396 /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6397 * change the clique number */
6398 if( consdata->cliquepartition[consdata->nvars - 1] != consdata->nvars - 1 )
6399 {
6400 int oldcliqenum;
6401
6402 oldcliqenum = consdata->cliquepartition[pos];
6403 consdata->cliquepartition[pos] = consdata->cliquepartition[consdata->nvars-1];
6404
6405 /* the following if and else cases assure that we have increasing clique numbers */
6406 if( consdata->cliquepartition[pos] > pos )
6407 consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6408 else
6409 {
6410 int i;
6411 int cliquenumbefore;
6412
6413 /* if the old clique number was greater than the new one we have to check that before a bigger clique number
6414 * occurs the same as the old one is still in the cliquepartition */
6415 if( oldcliqenum > consdata->cliquepartition[pos] )
6416 {
6417 for( i = 0; i < consdata->nvars; ++i )
6418 if( oldcliqenum == consdata->cliquepartition[i] )
6419 break;
6420 else if( oldcliqenum < consdata->cliquepartition[i] )
6421 {
6422 consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6423 break;
6424 }
6425 /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6426 * the biggest index, so decrease the number of cliques
6427 */
6428 if( i == consdata->nvars )
6429 --(consdata->ncliques);
6430 }
6431 /* if the old clique number was smaller than the new one we have to check the front for an element with
6432 * clique number minus 1 */
6433 else if( oldcliqenum < consdata->cliquepartition[pos] )
6434 {
6435 cliquenumbefore = consdata->cliquepartition[pos] - 1;
6436 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6437
6438 if( i < cliquenumbefore )
6439 consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6440 }
6441 /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6442 else if( pos == consdata->nvars - 1)
6443 {
6444 cliquenumbefore = consdata->cliquepartition[pos];
6445 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6446
6447 if( i < cliquenumbefore )
6448 --(consdata->ncliques);
6449 }
6450 /* if the old clique number is equal to the new one the cliquepartition should be ok */
6451 }
6452 }
6453 else
6454 --(consdata->ncliques);
6455 }
6456
6457 if( consdata->negcliquepartitioned )
6458 {
6459 assert(consdata->negcliquepartition != NULL);
6460 /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6461 * change the clique number */
6462 if( consdata->negcliquepartition[consdata->nvars-1] != consdata->nvars - 1 )
6463 {
6464 int oldcliqenum;
6465
6466 oldcliqenum = consdata->negcliquepartition[pos];
6467 consdata->negcliquepartition[pos] = consdata->negcliquepartition[consdata->nvars-1];
6468
6469 /* the following if and else cases assure that we have increasing clique numbers */
6470 if( consdata->negcliquepartition[pos] > pos )
6471 consdata->negcliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6472 else
6473 {
6474 int i;
6475 int cliquenumbefore;
6476
6477 /* if the old clique number was greater than the new one we have to check that, before a bigger clique number
6478 * occurs, the same as the old one occurs */
6479 if( oldcliqenum > consdata->negcliquepartition[pos] )
6480 {
6481 for( i = 0; i < consdata->nvars; ++i )
6482 if( oldcliqenum == consdata->negcliquepartition[i] )
6483 break;
6484 else if( oldcliqenum < consdata->negcliquepartition[i] )
6485 {
6486 consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6487 break;
6488 }
6489 /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6490 * the biggest index, so decrease the number of negated cliques
6491 */
6492 if( i == consdata->nvars )
6493 --(consdata->nnegcliques);
6494 }
6495 /* if the old clique number was smaller than the new one we have to check the front for an element with
6496 * clique number minus 1 */
6497 else if( oldcliqenum < consdata->negcliquepartition[pos] )
6498 {
6499 cliquenumbefore = consdata->negcliquepartition[pos] - 1;
6500 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6501
6502 if( i < cliquenumbefore )
6503 consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6504 }
6505 /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6506 else if( pos == consdata->nvars - 1)
6507 {
6508 cliquenumbefore = consdata->negcliquepartition[pos];
6509 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6510
6511 if( i < cliquenumbefore )
6512 --(consdata->nnegcliques);
6513 }
6514 /* otherwise if the old clique number is equal to the new one the cliquepartition should be ok */
6515 }
6516 }
6517 else
6518 --(consdata->nnegcliques);
6519 }
6520
6521 --(consdata->nvars);
6522
6523 return SCIP_OKAY;
6524}
6525
6526/** removes all items with weight zero from knapsack constraint */
6527static
6529 SCIP* scip, /**< SCIP data structure */
6530 SCIP_CONS* cons /**< knapsack constraint */
6531 )
6532{
6533 SCIP_CONSDATA* consdata;
6534 int v;
6535
6536 consdata = SCIPconsGetData(cons);
6537 assert(consdata != NULL);
6538
6539 for( v = consdata->nvars-1; v >= 0; --v )
6540 {
6541 if( consdata->weights[v] == 0 )
6542 {
6543 SCIP_CALL( delCoefPos(scip, cons, v) );
6544 }
6545 }
6546
6547 return SCIP_OKAY;
6548}
6549
6550/* perform deletion of variables in all constraints of the constraint handler */
6551static
6553 SCIP* scip, /**< SCIP data structure */
6554 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6555 SCIP_CONS** conss, /**< array of constraints */
6556 int nconss /**< number of constraints */
6557 )
6558{
6559 SCIP_CONSDATA* consdata;
6560 int i;
6561 int v;
6562
6563 assert(scip != NULL);
6564 assert(conshdlr != NULL);
6565 assert(conss != NULL);
6566 assert(nconss >= 0);
6567 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
6568
6569 /* iterate over all constraints */
6570 for( i = 0; i < nconss; i++ )
6571 {
6572 consdata = SCIPconsGetData(conss[i]);
6573
6574 /* constraint is marked, that some of its variables were deleted */
6575 if( consdata->varsdeleted )
6576 {
6577 /* iterate over all variables of the constraint and delete them from the constraint */
6578 for( v = consdata->nvars - 1; v >= 0; --v )
6579 {
6580 if( SCIPvarIsDeleted(consdata->vars[v]) )
6581 {
6582 SCIP_CALL( delCoefPos(scip, conss[i], v) );
6583 }
6584 }
6585 consdata->varsdeleted = FALSE;
6586 }
6587 }
6588
6589 return SCIP_OKAY;
6590}
6591
6592/** replaces multiple occurrences of a variable or its negation by a single coefficient */
6593static
6595 SCIP* scip, /**< SCIP data structure */
6596 SCIP_CONS* cons, /**< knapsack constraint */
6597 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
6598 )
6599{
6600 SCIP_CONSDATA* consdata;
6601 int v;
6602 int prev;
6603
6604 assert(scip != NULL);
6605 assert(cons != NULL);
6606 assert(cutoff != NULL);
6607
6608 consdata = SCIPconsGetData(cons);
6609 assert(consdata != NULL);
6610
6611 *cutoff = FALSE;
6612
6613 if( consdata->merged )
6614 return SCIP_OKAY;
6615
6616 if( consdata->nvars <= 1 )
6617 {
6618 consdata->merged = TRUE;
6619 return SCIP_OKAY;
6620 }
6621
6622 assert(consdata->vars != NULL || consdata->nvars == 0);
6623
6624 /* sorting array after indices of variables, that's only for faster merging */
6625 SCIPsortPtrPtrLongIntInt((void**)consdata->vars, (void**)consdata->eventdata, consdata->weights,
6626 consdata->cliquepartition, consdata->negcliquepartition, SCIPvarCompActiveAndNegated, consdata->nvars);
6627
6628 /* knapsack-sorting (decreasing weights) now lost */
6629 consdata->sorted = FALSE;
6630
6631 v = consdata->nvars - 1;
6632 prev = v - 1;
6633 /* loop backwards through the items: deletion only affects rear items */
6634 while( prev >= 0 )
6635 {
6636 SCIP_VAR* var1;
6637 SCIP_VAR* var2;
6638 SCIP_Bool negated1;
6639 SCIP_Bool negated2;
6640
6641 negated1 = FALSE;
6642 negated2 = FALSE;
6643
6644 var1 = consdata->vars[v];
6645 assert(SCIPvarIsBinary(var1));
6648 {
6649 var1 = SCIPvarGetNegatedVar(var1);
6650 negated1 = TRUE;
6651 }
6652 assert(var1 != NULL);
6653
6654 var2 = consdata->vars[prev];
6655 assert(SCIPvarIsBinary(var2));
6658 {
6659 var2 = SCIPvarGetNegatedVar(var2);
6660 negated2 = TRUE;
6661 }
6662 assert(var2 != NULL);
6663
6664 if( var1 == var2 )
6665 {
6666 /* both variables are either active or negated */
6667 if( negated1 == negated2 )
6668 {
6669 /* variables var1 and var2 are equal: add weight of var1 to var2, and delete var1 */
6670 consdataChgWeight(consdata, prev, consdata->weights[v] + consdata->weights[prev]);
6671 SCIP_CALL( delCoefPos(scip, cons, v) );
6672 }
6673 /* variables var1 and var2 are opposite: subtract smaller weight from larger weight, reduce capacity,
6674 * and delete item of smaller weight
6675 */
6676 else if( consdata->weights[v] == consdata->weights[prev] )
6677 {
6678 /* both variables eliminate themselves: w*x + w*(1-x) == w */
6679 consdata->capacity -= consdata->weights[v];
6680 SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6681 SCIP_CALL( delCoefPos(scip, cons, prev) );
6682
6683 --prev;
6684 }
6685 else if( consdata->weights[v] < consdata->weights[prev] )
6686 {
6687 consdata->capacity -= consdata->weights[v];
6688 consdataChgWeight(consdata, prev, consdata->weights[prev] - consdata->weights[v]);
6689 assert(consdata->weights[prev] > 0);
6690 SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6691 }
6692 else
6693 {
6694 consdata->capacity -= consdata->weights[prev];
6695 consdataChgWeight(consdata, v, consdata->weights[v] - consdata->weights[prev]);
6696 assert(consdata->weights[v] > 0);
6697 SCIP_CALL( delCoefPos(scip, cons, prev) ); /* attention: normally we lose our order */
6698 /* restore order iff necessary */
6699 if( consdata->nvars != v ) /* otherwise the order still stands */
6700 {
6701 assert(prev == 0 || ((prev > 0) && (SCIPvarIsActive(consdata->vars[prev - 1]) || SCIPvarGetStatus(consdata->vars[prev - 1]) == SCIP_VARSTATUS_NEGATED)) );
6702 /* either that was the last pair or both, the negated and "normal" variable in front doesn't match var1, so the order is irrelevant */
6703 if( prev == 0 || (var1 != consdata->vars[prev - 1] && var1 != SCIPvarGetNegatedVar(consdata->vars[prev - 1])) )
6704 --prev;
6705 else /* we need to let v at the same position*/
6706 {
6707 consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6708 /* don't decrease v, the same variable may exist up front */
6709 --prev;
6710 continue;
6711 }
6712 }
6713 }
6714 consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6715 }
6716 v = prev;
6717 --prev;
6718 }
6719
6720 consdata->merged = TRUE;
6721
6722 /* check infeasibility */
6723 if( consdata->onesweightsum > consdata->capacity )
6724 {
6725 SCIPdebugMsg(scip, "merge multiples detected cutoff.\n");
6726 *cutoff = TRUE;
6727 return SCIP_OKAY;
6728 }
6729
6730 return SCIP_OKAY;
6731}
6732
6733/** in case the knapsack constraint is independent of every else, solve the knapsack problem (exactly) and apply the
6734 * fixings (dual reductions)
6735 */
6736static
6738 SCIP* scip, /**< SCIP data structure */
6739 SCIP_CONS* cons, /**< knapsack constraint */
6740 int* nfixedvars, /**< pointer to count number of fixings */
6741 int* ndelconss, /**< pointer to count number of deleted constraints */
6742 SCIP_Bool* deleted /**< pointer to store if the constraint is deleted */
6743 )
6744{
6745 SCIP_CONSDATA* consdata;
6746 SCIP_VAR** vars;
6747 SCIP_Real* profits;
6748 int* solitems;
6749 int* nonsolitems;
6750 int* items;
6751 SCIP_Real solval;
6752 SCIP_Bool infeasible;
6753 SCIP_Bool tightened;
6754 SCIP_Bool applicable;
6755 int nsolitems;
6756 int nnonsolitems;
6757 int nvars;
6758 int v;
6759
6760 assert(!SCIPconsIsModifiable(cons));
6761
6762 /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
6763 * use the locks to decide for a dual reduction using this constraint; for example after a restart the cuts which are
6764 * added to the problems have the check flag set to FALSE
6765 */
6766 if( !SCIPconsIsChecked(cons) )
6767 return SCIP_OKAY;
6768
6769 consdata = SCIPconsGetData(cons);
6770 assert(consdata != NULL);
6771
6772 nvars = consdata->nvars;
6773 vars = consdata->vars;
6774
6777 SCIP_CALL( SCIPallocBufferArray(scip, &solitems, nvars) );
6778 SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, nvars) );
6779
6780 applicable = TRUE;
6781
6782 /* check if we can apply the dual reduction; this can be done if the knapsack has the only locks on this constraint;
6783 * collect object values which are the profits of the knapsack problem
6784 */
6785 for( v = 0; v < nvars; ++v )
6786 {
6787 SCIP_VAR* var;
6788 SCIP_Bool negated;
6789
6790 var = vars[v];
6791 assert(var != NULL);
6792
6793 /* the variable should not be (globally) fixed */
6794 assert(SCIPvarGetLbGlobal(var) < 0.5 && SCIPvarGetUbGlobal(var) > 0.5);
6795
6798 {
6799 applicable = FALSE;
6800 break;
6801 }
6802
6803 negated = FALSE;
6804
6805 /* get the active variable */
6806 SCIP_CALL( SCIPvarGetProbvarBinary(&var, &negated) );
6807 assert(SCIPvarIsActive(var));
6808
6809 if( negated )
6810 profits[v] = SCIPvarGetObj(var);
6811 else
6812 profits[v] = -SCIPvarGetObj(var);
6813
6814 SCIPdebugMsg(scip, "variable <%s> -> item size %" SCIP_LONGINT_FORMAT ", profit <%g>\n",
6815 SCIPvarGetName(vars[v]), consdata->weights[v], profits[v]);
6816 items[v] = v;
6817 }
6818
6819 if( applicable )
6820 {
6821 SCIP_Bool success;
6822
6823 SCIPdebugMsg(scip, "the knapsack constraint <%s> is independent to rest of the problem\n", SCIPconsGetName(cons));
6825
6826 /* solve knapsack problem exactly */
6827 SCIP_CALL( SCIPsolveKnapsackExactly(scip, consdata->nvars, consdata->weights, profits, consdata->capacity,
6828 items, solitems, nonsolitems, &nsolitems, &nnonsolitems, &solval, &success) );
6829
6830 if( success )
6831 {
6832 SCIP_VAR* var;
6833
6834 /* apply solution of the knapsack as dual reductions */
6835 for( v = 0; v < nsolitems; ++v )
6836 {
6837 var = vars[solitems[v]];
6838 assert(var != NULL);
6839
6840 SCIPdebugMsg(scip, "variable <%s> only locked up in knapsack constraints: dual presolve <%s>[%.15g,%.15g] >= 1.0\n",
6842 SCIP_CALL( SCIPtightenVarLb(scip, var, 1.0, TRUE, &infeasible, &tightened) );
6843 assert(!infeasible);
6844 assert(tightened);
6845 (*nfixedvars)++;
6846 }
6847
6848 for( v = 0; v < nnonsolitems; ++v )
6849 {
6850 var = vars[nonsolitems[v]];
6851 assert(var != NULL);
6852
6853 SCIPdebugMsg(scip, "variable <%s> has no down locks: dual presolve <%s>[%.15g,%.15g] <= 0.0\n",
6855 SCIP_CALL( SCIPtightenVarUb(scip, var, 0.0, TRUE, &infeasible, &tightened) );
6856 assert(!infeasible);
6857 assert(tightened);
6858 (*nfixedvars)++;
6859 }
6860
6861 SCIP_CALL( SCIPdelCons(scip, cons) );
6862 (*ndelconss)++;
6863 (*deleted) = TRUE;
6864 }
6865 }
6866
6867 SCIPfreeBufferArray(scip, &nonsolitems);
6868 SCIPfreeBufferArray(scip, &solitems);
6869 SCIPfreeBufferArray(scip, &items);
6870 SCIPfreeBufferArray(scip, &profits);
6871
6872 return SCIP_OKAY;
6873}
6874
6875/** check if the knapsack constraint is parallel to objective function; if so update the cutoff bound and avoid that the
6876 * constraint enters the LP by setting the initial and separated flag to FALSE
6877 */
6878static
6880 SCIP* scip, /**< SCIP data structure */
6881 SCIP_CONS* cons, /**< knapsack constraint */
6882 SCIP_CONSHDLRDATA* conshdlrdata /**< knapsack constraint handler data */
6883 )
6884{
6885 SCIP_CONSDATA* consdata;
6886 SCIP_VAR** vars;
6887 SCIP_VAR* var;
6888 SCIP_Real offset;
6889 SCIP_Real scale;
6890 SCIP_Real objval;
6891 SCIP_Bool applicable;
6892 SCIP_Bool negated;
6893 int nobjvars;
6894 int nvars;
6895 int v;
6896
6897 assert(scip != NULL);
6898 assert(cons != NULL);
6899 assert(conshdlrdata != NULL);
6900
6901 consdata = SCIPconsGetData(cons);
6902 assert(consdata != NULL);
6903
6904 nvars = consdata->nvars;
6905 nobjvars = SCIPgetNObjVars(scip);
6906
6907 /* check if the knapsack constraints has the same number of variables as the objective function and if the initial
6908 * and/or separated flag is set to FALSE
6909 */
6910 if( nvars != nobjvars || (!SCIPconsIsInitial(cons) && !SCIPconsIsSeparated(cons)) )
6911 return SCIP_OKAY;
6912
6913 /* There are no variables in the ojective function and in the constraint. Thus, the constraint is redundant. Since we
6914 * have a pure feasibility problem, we do not want to set a cutoff or lower bound.
6915 */
6916 if( nobjvars == 0 )
6917 return SCIP_OKAY;
6918
6919 vars = consdata->vars;
6920 assert(vars != NULL);
6921
6922 applicable = TRUE;
6923 offset = 0.0;
6924 scale = 1.0;
6925
6926 for( v = 0; v < nvars && applicable; ++v )
6927 {
6928 negated = FALSE;
6929 var = vars[v];
6930 assert(var != NULL);
6931
6932 if( SCIPvarIsNegated(var) )
6933 {
6934 negated = TRUE;
6935 var = SCIPvarGetNegatedVar(var);
6936 assert(var != NULL);
6937 }
6938
6939 objval = SCIPvarGetObj(var);
6940
6941 /* if a variable has a zero objective coefficient the knapsack constraint is not parallel to objective function */
6942 if( SCIPisZero(scip, objval) )
6943 applicable = FALSE;
6944 else
6945 {
6946 SCIP_Real weight;
6947
6948 weight = (SCIP_Real)consdata->weights[v];
6949
6950 if( negated )
6951 {
6952 if( v == 0 )
6953 {
6954 /* the first variable defines the scale */
6955 scale = weight / -objval;
6956
6957 offset += weight;
6958 }
6959 else if( SCIPisEQ(scip, -objval * scale, weight) )
6960 offset += weight;
6961 else
6962 applicable = FALSE;
6963 }
6964 else if( v == 0 )
6965 {
6966 /* the first variable define the scale */
6967 scale = weight / objval;
6968 }
6969 else if( !SCIPisEQ(scip, objval * scale, weight) )
6970 applicable = FALSE;
6971 }
6972 }
6973
6974 if( applicable )
6975 {
6976 if( SCIPisPositive(scip, scale) && conshdlrdata->detectcutoffbound )
6977 {
6978 SCIP_Real cutoffbound;
6979
6980 /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
6983
6984 cutoffbound = (consdata->capacity - offset) / scale;
6985
6986 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
6987 SCIPconsGetName(cons), cutoffbound);
6988
6989 /* increase the cutoff bound value by an epsilon to ensue that solution with the value of the cutoff bound are
6990 * still excepted
6991 */
6992 cutoffbound += SCIPcutoffbounddelta(scip);
6993
6994 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
6995 SCIPconsGetName(cons), cutoffbound);
6996
6997 if( cutoffbound < SCIPgetCutoffbound(scip) )
6998 {
6999 SCIPdebugMsg(scip, "update cutoff bound <%g>\n", cutoffbound);
7000
7001 SCIP_CALL( SCIPupdateCutoffbound(scip, cutoffbound) );
7002 }
7003 else
7004 {
7005 /* in case the cutoff bound is worse then currently known one we avoid additionaly enforcement and
7006 * propagation
7007 */
7010 }
7011 }
7012 else if( SCIPisNegative(scip, scale) && conshdlrdata->detectlowerbound )
7013 {
7014 SCIP_Real lowerbound;
7015
7016 /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
7019
7020 lowerbound = (consdata->capacity - offset) / scale;
7021
7022 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a lower bound <%g>\n",
7023 SCIPconsGetName(cons), lowerbound);
7024
7026 }
7027 }
7028
7029 return SCIP_OKAY;
7030}
7031
7032/** sort the variables and weights w.r.t. the clique partition; thereby ensure the current order of the variables when a
7033 * weight of one variable is greater or equal another weight and both variables are in the same cliques */
7034static
7036 SCIP* scip, /**< SCIP data structure */
7037 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
7038 SCIP_VAR** vars, /**< array for sorted variables */
7039 SCIP_Longint* weights, /**< array for sorted weights */
7040 int* cliquestartposs, /**< starting position array for each clique */
7041 SCIP_Bool usenegatedclique /**< should negated or normal clique partition be used */
7042 )
7043{
7044 SCIP_VAR** origvars;
7045 int norigvars;
7046 SCIP_Longint* origweights;
7047 int* cliquepartition;
7048 int ncliques;
7049
7050 SCIP_VAR*** varpointers;
7051 SCIP_Longint** weightpointers;
7052 int* cliquecount;
7053
7054 int nextpos;
7055 int c;
7056 int v;
7057
7058 assert(scip != NULL);
7059 assert(consdata != NULL);
7060 assert(vars != NULL);
7061 assert(weights != NULL);
7062 assert(cliquestartposs != NULL);
7063
7064 origweights = consdata->weights;
7065 origvars = consdata->vars;
7066 norigvars = consdata->nvars;
7067
7068 assert(origvars != NULL || norigvars == 0);
7069 assert(origweights != NULL || norigvars == 0);
7070
7071 if( norigvars == 0 )
7072 return SCIP_OKAY;
7073
7074 if( usenegatedclique )
7075 {
7076 assert(consdata->negcliquepartitioned);
7077
7078 cliquepartition = consdata->negcliquepartition;
7079 ncliques = consdata->nnegcliques;
7080 }
7081 else
7082 {
7083 assert(consdata->cliquepartitioned);
7084
7085 cliquepartition = consdata->cliquepartition;
7086 ncliques = consdata->ncliques;
7087 }
7088
7089 assert(cliquepartition != NULL);
7090 assert(ncliques > 0);
7091
7092 /* we first count all clique items and alloc temporary memory for a bucket sort */
7093 SCIP_CALL( SCIPallocBufferArray(scip, &cliquecount, ncliques) );
7094 BMSclearMemoryArray(cliquecount, ncliques);
7095
7096 /* first we count for each clique the number of elements */
7097 for( v = norigvars - 1; v >= 0; --v )
7098 {
7099 assert(0 <= cliquepartition[v] && cliquepartition[v] < ncliques);
7100 ++(cliquecount[cliquepartition[v]]);
7101 }
7102
7103 /*@todo: maybe it is better to put largest cliques up front */
7104
7105#ifndef NDEBUG
7106 BMSclearMemoryArray(vars, norigvars);
7107 BMSclearMemoryArray(weights, norigvars);
7108#endif
7109 SCIP_CALL( SCIPallocBufferArray(scip, &varpointers, ncliques) );
7110 SCIP_CALL( SCIPallocBufferArray(scip, &weightpointers, ncliques) );
7111
7112 nextpos = 0;
7113 /* now we initialize all start pointers for each clique, so they will be ordered */
7114 for( c = 0; c < ncliques; ++c )
7115 {
7116 /* to reach the goal that all variables of each clique will be standing next to each other we will initialize the
7117 * starting pointers for each clique by adding the number of each clique to the last clique starting pointer
7118 * e.g. clique1 has 4 elements and clique2 has 3 elements the the starting pointer for clique1 will be the pointer
7119 * to vars[0], the starting pointer to clique2 will be the pointer to vars[4] and to clique3 it will be
7120 * vars[7]
7121 *
7122 */
7123 varpointers[c] = (SCIP_VAR**) (vars + nextpos);
7124 cliquestartposs[c] = nextpos;
7125 weightpointers[c] = (SCIP_Longint*) (weights + nextpos);
7126 assert(cliquecount[c] > 0);
7127 nextpos += cliquecount[c];
7128 assert(nextpos > 0);
7129 }
7130 assert(nextpos == norigvars);
7131 cliquestartposs[c] = nextpos;
7132
7133 /* now we copy all variable and weights to the right order */
7134 for( v = 0; v < norigvars; ++v )
7135 {
7136 *(varpointers[cliquepartition[v]]) = origvars[v]; /*lint !e613*/
7137 ++(varpointers[cliquepartition[v]]);
7138 *(weightpointers[cliquepartition[v]]) = origweights[v]; /*lint !e613*/
7139 ++(weightpointers[cliquepartition[v]]);
7140 }
7141#ifndef NDEBUG
7142 for( v = 0; v < norigvars; ++v )
7143 {
7144 assert(vars[v] != NULL);
7145 assert(weights[v] > 0);
7146 }
7147#endif
7148
7149 /* free temporary memory */
7150 SCIPfreeBufferArray(scip, &weightpointers);
7151 SCIPfreeBufferArray(scip, &varpointers);
7152 SCIPfreeBufferArray(scip, &cliquecount);
7153
7154 return SCIP_OKAY;
7155}
7156
7157/** deletes all fixed variables from knapsack constraint, and replaces variables with binary representatives */
7158static
7160 SCIP* scip, /**< SCIP data structure */
7161 SCIP_CONS* cons, /**< knapsack constraint */
7162 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off, or NULL if this
7163 * information is not needed; in this case, we apply all fixings
7164 * instead of stopping after the first infeasible one */
7165 )
7166{
7167 SCIP_CONSDATA* consdata;
7168 int v;
7169
7170 assert(scip != NULL);
7171 assert(cons != NULL);
7172
7173 consdata = SCIPconsGetData(cons);
7174 assert(consdata != NULL);
7175 assert(consdata->nvars == 0 || consdata->vars != NULL);
7176
7177 if( cutoff != NULL )
7178 *cutoff = FALSE;
7179
7180 SCIPdebugMsg(scip, "apply fixings:\n");
7182
7183 /* check infeasibility */
7184 if ( consdata->onesweightsum > consdata->capacity )
7185 {
7186 SCIPdebugMsg(scip, "apply fixings detected cutoff.\n");
7187
7188 if( cutoff != NULL )
7189 *cutoff = TRUE;
7190
7191 return SCIP_OKAY;
7192 }
7193
7194 /* all multi-aggregations should be resolved */
7195 consdata->existmultaggr = FALSE;
7196
7197 v = 0;
7198 while( v < consdata->nvars )
7199 {
7200 SCIP_VAR* var;
7201
7202 var = consdata->vars[v];
7203 assert(SCIPvarIsBinary(var));
7204
7205 if( SCIPvarGetLbGlobal(var) > 0.5 )
7206 {
7207 assert(SCIPisFeasEQ(scip, SCIPvarGetUbGlobal(var), 1.0));
7208 consdata->capacity -= consdata->weights[v];
7209 SCIP_CALL( delCoefPos(scip, cons, v) );
7210 consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
7211 }
7212 else if( SCIPvarGetUbGlobal(var) < 0.5 )
7213 {
7214 assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(var), 0.0));
7215 SCIP_CALL( delCoefPos(scip, cons, v) );
7216 }
7217 else
7218 {
7219 SCIP_VAR* repvar;
7220 SCIP_VAR* negvar;
7221 SCIP_VAR* workvar;
7222 SCIP_Longint weight;
7223 SCIP_Bool negated;
7224
7225 weight = consdata->weights[v];
7226
7227 /* get binary representative of variable */
7228 SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &repvar, &negated) );
7229 assert(repvar != NULL);
7230
7231 /* check for multi-aggregation */
7232 if( SCIPvarIsNegated(repvar) )
7233 {
7234 workvar = SCIPvarGetNegatedVar(repvar);
7235 assert(workvar != NULL);
7236 negated = TRUE;
7237 }
7238 else
7239 {
7240 workvar = repvar;
7241 negated = FALSE;
7242 }
7243
7244 /* @todo maybe resolve the problem that the eliminating of the multi-aggregation leads to a non-knapsack
7245 * constraint (converting into a linear constraint), for example the multi-aggregation consist of a non-binary
7246 * variable or due to resolving now their are non-integral coefficients or a non-integral capacity
7247 *
7248 * If repvar is not negated so workvar = repvar, otherwise workvar = 1 - repvar. This means,
7249 * weight * workvar = weight * (a_1*y_1 + ... + a_n*y_n + c)
7250 *
7251 * The explanation for the following block:
7252 * 1a) If repvar is a multi-aggregated variable weight * repvar should be replaced by
7253 * weight * (a_1*y_1 + ... + a_n*y_n + c).
7254 * 1b) If repvar is a negated variable of a multi-aggregated variable weight * repvar should be replaced by
7255 * weight - weight * (a_1*y_1 + ... + a_n*y_n + c), for better further use here we switch the sign of weight
7256 * so now we have the replacement -weight + weight * (a_1*y_1 + ... + a_n*y_n + c).
7257 * 2) For all replacement variable we check:
7258 * 2a) weight * a_i < 0 than we add -weight * a_i * y_i_neg to the constraint and adjust the capacity through
7259 * capacity -= weight * a_i caused by the negation of y_i.
7260 * 2b) weight * a_i >= 0 than we add weight * a_i * y_i to the constraint.
7261 * 3a) If repvar was not negated we need to subtract weight * c from capacity.
7262 * 3b) If repvar was negated we need to subtract weight * (c - 1) from capacity(note we switched the sign of
7263 * weight in this case.
7264 */
7266 {
7267 SCIP_VAR** aggrvars;
7268 SCIP_Real* aggrscalars;
7269 SCIP_Real aggrconst;
7270 int naggrvars;
7271 int i;
7272
7274 naggrvars = SCIPvarGetMultaggrNVars(workvar);
7275 aggrvars = SCIPvarGetMultaggrVars(workvar);
7276 aggrscalars = SCIPvarGetMultaggrScalars(workvar);
7277 aggrconst = SCIPvarGetMultaggrConstant(workvar);
7278 assert((aggrvars != NULL && aggrscalars != NULL) || naggrvars == 0);
7279
7280 if( !SCIPisIntegral(scip, weight * aggrconst) )
7281 {
7282 SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrconst = %g\n", weight*aggrconst);
7283 return SCIP_ERROR;
7284 }
7285
7286 /* if workvar was negated, we have to flip the weight */
7287 if( negated )
7288 weight *= -1;
7289
7290 for( i = naggrvars - 1; i >= 0; --i )
7291 {
7292 assert(aggrvars != NULL);
7293 assert(aggrscalars != NULL);
7294
7295 if( !SCIPvarIsBinary(aggrvars[i]) )
7296 {
7297 SCIPerrorMessage("try to resolve a multi-aggregation with a non-binary %svariable <%s> with bounds [%g,%g]\n",
7298 SCIPvarIsIntegral(aggrvars[i]) ? "integral " : "", SCIPvarGetName(aggrvars[i]), SCIPvarGetLbGlobal(aggrvars[i]), SCIPvarGetUbGlobal(aggrvars[i]));
7299 return SCIP_ERROR;
7300 }
7301 if( !SCIPisIntegral(scip, weight * aggrscalars[i]) )
7302 {
7303 SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrscalars = %g\n", weight*aggrscalars[i]);
7304 return SCIP_ERROR;
7305 }
7306 /* if the new coefficient is smaller than zero, we need to add the negated variable instead and adjust the capacity */
7307 if( SCIPisNegative(scip, weight * aggrscalars[i]) )
7308 {
7309 SCIP_CALL( SCIPgetNegatedVar(scip, aggrvars[i], &negvar));
7310 assert(negvar != NULL);
7311 SCIP_CALL( addCoef(scip, cons, negvar, (SCIP_Longint)(SCIPfloor(scip, -weight * aggrscalars[i] + 0.5))) );
7312 consdata->capacity -= (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5));
7313 }
7314 else
7315 {
7316 SCIP_CALL( addCoef(scip, cons, aggrvars[i], (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5))) );
7317 }
7318 }
7319 /* delete old coefficient */
7320 SCIP_CALL( delCoefPos(scip, cons, v) );
7321
7322 /* adjust the capacity with the aggregation constant and if necessary the extra weight through the negation */
7323 if( negated )
7324 consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * (aggrconst - 1) + 0.5);
7325 else
7326 consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * aggrconst + 0.5);
7327
7328 if( consdata->capacity < 0 )
7329 {
7330 if( cutoff != NULL )
7331 {
7332 *cutoff = TRUE;
7333 break;
7334 }
7335 }
7336 }
7337 /* check, if the variable should be replaced with the representative */
7338 else if( repvar != var )
7339 {
7340 /* delete old (aggregated) variable */
7341 SCIP_CALL( delCoefPos(scip, cons, v) );
7342
7343 /* add representative instead */
7344 SCIP_CALL( addCoef(scip, cons, repvar, weight) );
7345 }
7346 else
7347 ++v;
7348 }
7349 }
7350 assert(consdata->onesweightsum == 0);
7351
7352 SCIPdebugMsg(scip, "after applyFixings, before merging:\n");
7354
7355 /* if aggregated variables have been replaced, multiple entries of the same variable are possible and we have to
7356 * clean up the constraint
7357 */
7358 if( cutoff != NULL && !(*cutoff) )
7359 {
7360 SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
7361 SCIPdebugMsg(scip, "after applyFixings and merging:\n");
7363 }
7364
7365 return SCIP_OKAY;
7366}
7367
7368
7369/** propagation method for knapsack constraints */
7370static
7372 SCIP* scip, /**< SCIP data structure */
7373 SCIP_CONS* cons, /**< knapsack constraint */
7374 SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
7375 SCIP_Bool* redundant, /**< pointer to store whether constraint is redundant */
7376 int* nfixedvars, /**< pointer to count number of fixings */
7377 SCIP_Bool usenegatedclique /**< should negated clique information be used */
7378 )
7379{
7380 SCIP_CONSDATA* consdata;
7381 SCIP_Bool infeasible;
7382 SCIP_Bool tightened;
7383 SCIP_Longint* secondmaxweights;
7384 SCIP_Longint minweightsum;
7385 SCIP_Longint residualcapacity;
7386
7387 int nvars;
7388 int i;
7389 int nnegcliques;
7390
7391 SCIP_VAR** myvars;
7392 SCIP_Longint* myweights;
7393 int* cliquestartposs;
7394 int* cliqueendposs;
7395 SCIP_Longint localminweightsum;
7396 SCIP_Bool foundmax;
7397 int c;
7398
7399 assert(scip != NULL);
7400 assert(cons != NULL);
7401 assert(cutoff != NULL);
7402 assert(redundant != NULL);
7403 assert(nfixedvars != NULL);
7404
7405 consdata = SCIPconsGetData(cons);
7406 assert(consdata != NULL);
7407
7408 *cutoff = FALSE;
7409 *redundant = FALSE;
7410
7411 SCIPdebugMsg(scip, "propagating knapsack constraint <%s>\n", SCIPconsGetName(cons));
7412
7413 /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */
7415 {
7416 SCIP_CALL( SCIPincConsAge(scip, cons) );
7417 }
7418
7419#ifndef NDEBUG
7420 /* assert that only active or negated variables are present */
7421 for( i = 0; i < consdata->nvars && consdata->merged; ++i )
7422 {
7423 assert(SCIPvarIsActive(consdata->vars[i]) || SCIPvarIsNegated(consdata->vars[i]) || SCIPvarGetStatus(consdata->vars[i]) == SCIP_VARSTATUS_FIXED);
7424 }
7425#endif
7426
7427 usenegatedclique = usenegatedclique && consdata->merged;
7428
7429 /* init for debugging */
7430 myvars = NULL;
7431 myweights = NULL;
7432 cliquestartposs = NULL;
7433 secondmaxweights = NULL;
7434 minweightsum = 0;
7435 nvars = consdata->nvars;
7436 /* make sure, the items are sorted by non-increasing weight */
7437 sortItems(consdata);
7438
7439 do
7440 {
7441 localminweightsum = 0;
7442
7443 /* (1) compute the minimum weight of the knapsack constraint using negated clique information;
7444 * a negated clique means, that at most one of the clique variables can be zero
7445 * - minweightsum = sum_{negated cliques C} ( sum(wi : i \in C) - W_max(C) ), where W_max(C) is the maximal weight of C
7446 *
7447 * if for i \in C (a negated clique) oneweightsum + minweightsum - wi + W_max(C) > capacity => xi = 1
7448 * since replacing i with the element of maximal weight leads to infeasibility
7449 */
7450 if( usenegatedclique && nvars > 0 )
7451 {
7452 SCIP_CONSHDLRDATA* conshdlrdata;
7453 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7454 assert(conshdlrdata != NULL);
7455
7456 /* compute clique partitions */
7457 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
7458 nnegcliques = consdata->nnegcliques;
7459
7460 /* if we have no real negated cliques we can stop here */
7461 if( nnegcliques == nvars )
7462 {
7463 /* run the standard algorithm that does not involve cliques */
7464 usenegatedclique = FALSE;
7465 break;
7466 }
7467
7468 /* allocate temporary memory and initialize it */
7469 SCIP_CALL( SCIPduplicateBufferArray(scip, &myvars, consdata->vars, nvars) );
7470 SCIP_CALL( SCIPduplicateBufferArray(scip, &myweights, consdata->weights, nvars) ) ;
7471 SCIP_CALL( SCIPallocBufferArray(scip, &cliquestartposs, nnegcliques + 1) );
7472 SCIP_CALL( SCIPallocBufferArray(scip, &cliqueendposs, nnegcliques) );
7473 SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
7474 BMSclearMemoryArray(secondmaxweights, nnegcliques);
7475
7476 /* resort variables to avoid quadratic algorithm later on */
7477 SCIP_CALL( stableSort(scip, consdata, myvars, myweights, cliquestartposs, TRUE) );
7478
7479 /* save the end positions of the cliques because start positions are moved in the following loop */
7480 for( c = 0; c < nnegcliques; ++c )
7481 {
7482 cliqueendposs[c] = cliquestartposs[c+1] - 1;
7483 assert(cliqueendposs[c] - cliquestartposs[c] >= 0);
7484 }
7485
7486 c = 0;
7487 foundmax = FALSE;
7488 i = 0;
7489
7490 while( i < nvars )
7491 {
7492 /* ignore variables of the negated clique which are fixed to one since these are counted in
7493 * consdata->onesweightsum
7494 */
7495
7496 /* if there are only one variable negated cliques left we can stop */
7497 if( nnegcliques - c == nvars - i )
7498 {
7499 minweightsum += localminweightsum;
7500 localminweightsum = 0;
7501 break;
7502 }
7503
7504 /* for summing up the minimum active weights due to cliques we have to omit the biggest weights of each
7505 * clique, we can only skip this clique if this variables is not fixed to zero, otherwise we have to fix all
7506 * other clique variables to one
7507 */
7508 if( cliquestartposs[c] == i )
7509 {
7510 assert(myweights[i] > 0);
7511 ++c;
7512 minweightsum += localminweightsum;
7513 localminweightsum = 0;
7514 foundmax = TRUE;
7515
7516 if( SCIPvarGetLbLocal(myvars[i]) > 0.5 )
7517 foundmax = FALSE;
7518
7519 if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7520 {
7521 ++i;
7522 continue;
7523 }
7524 }
7525
7526 if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7527 {
7528 assert(myweights[i] > 0);
7529
7530 if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7531 {
7532 assert(myweights[i] <= myweights[cliquestartposs[c - 1]]);
7533
7534 if( !foundmax )
7535 {
7536 foundmax = TRUE;
7537
7538 /* overwrite cliquestartpos to the position of the first unfixed variable in this clique */
7539 cliquestartposs[c - 1] = i;
7540 ++i;
7541
7542 continue;
7543 }
7544 /* memorize second max weight for each clique */
7545 if( secondmaxweights[c - 1] == 0 )
7546 secondmaxweights[c - 1] = myweights[i];
7547
7548 localminweightsum += myweights[i];
7549 }
7550 /* we found a fixed variable to zero so all other variables in this negated clique have to be fixed to one */
7551 else
7552 {
7553 int v;
7554 /* fix all other variables of the negated clique to 1 */
7555 for( v = cliquestartposs[c - 1]; v < cliquestartposs[c]; ++v )
7556 {
7557 if( v != i && SCIPvarGetLbLocal(myvars[v]) < 0.5 )
7558 {
7559 SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[v]));
7560 SCIP_CALL( SCIPinferBinvarCons(scip, myvars[v], TRUE, cons, SCIPvarGetIndex(myvars[i]), &infeasible, &tightened) );
7561
7562 if( infeasible )
7563 {
7564 assert( SCIPvarGetUbLocal(myvars[v]) < 0.5 );
7565
7566 /* analyze the infeasibility if conflict analysis is applicable */
7568 {
7569 /* conflict analysis can only be applied in solving stage */
7571
7572 /* initialize the conflict analysis */
7574
7575 /* add the two variables which are fixed to zero within a negated clique */
7576 SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[i]) );
7577 SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[v]) );
7578
7579 /* start the conflict analysis */
7581 }
7582 *cutoff = TRUE;
7583 break;
7584 }
7585 assert(tightened);
7586 ++(*nfixedvars);
7588 }
7589 }
7590
7591 /* reset local minweightsum for clique because all fixed to one variables are now counted in consdata->onesweightsum */
7592 localminweightsum = 0;
7593 /* we can jump to the end of this clique */
7594 i = cliqueendposs[c - 1];
7595
7596 if( *cutoff )
7597 break;
7598 }
7599 }
7600 ++i;
7601 }
7602 /* add last clique minweightsum */
7603 minweightsum += localminweightsum;
7604
7605 SCIPdebugMsg(scip, "knapsack constraint <%s> has minimum weight sum of <%" SCIP_LONGINT_FORMAT ">\n",
7606 SCIPconsGetName(cons), minweightsum + consdata->onesweightsum );
7607
7608 /* check, if weights of fixed variables don't exceeds knapsack capacity */
7609 if( !(*cutoff) && consdata->capacity >= minweightsum + consdata->onesweightsum )
7610 {
7611 SCIP_Longint maxcliqueweight = -1LL;
7612
7613 /* loop over cliques */
7614 for( c = 0; c < nnegcliques; ++c )
7615 {
7616 SCIP_VAR* maxvar;
7617 SCIP_Bool maxvarfixed;
7618 int endvarposclique;
7619 int startvarposclique;
7620
7621 assert(myvars != NULL);
7622 assert(nnegcliques == consdata->nnegcliques);
7623 assert(myweights != NULL);
7624 assert(secondmaxweights != NULL);
7625 assert(cliquestartposs != NULL);
7626
7627 endvarposclique = cliqueendposs[c];
7628 startvarposclique = cliquestartposs[c];
7629
7630 maxvar = myvars[startvarposclique];
7631
7632 /* no need to process this negated clique because all variables are already fixed (which we detect from a fixed maxvar) */
7633 if( SCIPvarGetUbLocal(maxvar) - SCIPvarGetLbLocal(maxvar) < 0.5 )
7634 continue;
7635
7636 maxcliqueweight = myweights[startvarposclique];
7637 maxvarfixed = FALSE;
7638 /* if the sum of all weights of fixed variables to one plus the minimalweightsum (minimal weight which is already
7639 * used in this knapsack due to negated cliques) plus any weight minus the second largest weight in this clique
7640 * exceeds the capacity the maximum weight variable can be fixed to zero.
7641 */
7642 if( consdata->onesweightsum + minweightsum + (maxcliqueweight - secondmaxweights[c]) > consdata->capacity )
7643 {
7644#ifndef NDEBUG
7645 SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7646#endif
7647 assert(maxcliqueweight >= secondmaxweights[c]);
7648 assert(SCIPvarGetLbLocal(maxvar) < 0.5 && SCIPvarGetUbLocal(maxvar) > 0.5);
7649
7650 SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(maxvar));
7652 SCIP_CALL( SCIPinferBinvarCons(scip, maxvar, FALSE, cons, cliquestartposs[c], &infeasible, &tightened) );
7653 assert(consdata->onesweightsum == oldonesweightsum);
7654 assert(!infeasible);
7655 assert(tightened);
7656 (*nfixedvars)++;
7657 maxvarfixed = TRUE;
7658 }
7659 /* the remaining cliques are singletons such that all subsequent variables have a weight that
7660 * fits into the knapsack
7661 */
7662 else if( nnegcliques - c == nvars - startvarposclique )
7663 break;
7664 /* early termination of the remaining loop because no further variable fixings are possible:
7665 *
7666 * the gain in any of the following negated cliques (the additional term if the maximum weight variable was set to 1, and the second
7667 * largest was set to 0) does not suffice to infer additional variable fixings because
7668 *
7669 * - the cliques are sorted by decreasing maximum weight -> for all c' >= c: maxweights[c'] <= maxcliqueweight
7670 * - their second largest elements are at least as large as the smallest weight of the knapsack
7671 */
7672 else if( consdata->onesweightsum + minweightsum + (maxcliqueweight - consdata->weights[nvars - 1]) <= consdata->capacity )
7673 break;
7674
7675 /* loop over items with non-maximal weight (omitting the first position) */
7676 for( i = endvarposclique; i > startvarposclique; --i )
7677 {
7678 /* there should be no variable fixed to 0 between startvarposclique + 1 and endvarposclique unless we
7679 * messed up the clique preprocessing in the previous loop to filter those variables out */
7680 assert(SCIPvarGetUbLocal(myvars[i]) > 0.5);
7681
7682 /* only check variables of negated cliques for which no variable is locally fixed */
7683 if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7684 {
7685 assert(maxcliqueweight >= myweights[i]);
7686 assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
7687
7688 /* we fix the members of this clique with non-maximal weight in two cases to 1:
7689 *
7690 * the maxvar was already fixed to 0 because it has a huge gain.
7691 *
7692 * if for i \in C (a negated clique) onesweightsum - wi + W_max(c) > capacity => xi = 1
7693 * since replacing i with the element of maximal weight leads to infeasibility */
7694 if( maxvarfixed || consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity )
7695 {
7696#ifndef NDEBUG
7697 SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7698#endif
7699 SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[i]));
7700 SCIP_CALL( SCIPinferBinvarCons(scip, myvars[i], TRUE, cons, -i, &infeasible, &tightened) );
7701 assert(consdata->onesweightsum == oldonesweightsum + myweights[i]);
7702 assert(!infeasible);
7703 assert(tightened);
7704 ++(*nfixedvars);
7706
7707 /* update minweightsum because now the variable is fixed to one and its weight is counted by
7708 * consdata->onesweightsum
7709 */
7710 minweightsum -= myweights[i];
7711 assert(minweightsum >= 0);
7712 }
7713 else
7714 break;
7715 }
7716 }
7717#ifndef NDEBUG
7718 /* in debug mode, we assert that we did not miss possible fixings by the break above */
7719 for( ; i > startvarposclique; --i )
7720 {
7721 SCIP_Bool varisfixed = SCIPvarGetUbLocal(myvars[i]) - SCIPvarGetLbLocal(myvars[i]) < 0.5;
7722 SCIP_Bool exceedscapacity = consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity;
7723
7724 assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
7725 assert(varisfixed || !exceedscapacity);
7726 }
7727#endif
7728 }
7729 }
7730 SCIPfreeBufferArray(scip, &secondmaxweights);
7731 SCIPfreeBufferArray(scip, &cliqueendposs);
7732 SCIPfreeBufferArray(scip, &cliquestartposs);
7733 SCIPfreeBufferArray(scip, &myweights);
7734 SCIPfreeBufferArray(scip, &myvars);
7735 }
7736
7737 assert(consdata->negcliquepartitioned || minweightsum == 0);
7738 }
7739 while( FALSE );
7740
7741 assert(usenegatedclique || minweightsum == 0);
7742 /* check, if weights of fixed variables already exceed knapsack capacity */
7743 if( consdata->capacity < minweightsum + consdata->onesweightsum )
7744 {
7745 SCIPdebugMsg(scip, " -> cutoff - fixed weight: %" SCIP_LONGINT_FORMAT ", capacity: %" SCIP_LONGINT_FORMAT " \n",
7746 consdata->onesweightsum, consdata->capacity);
7747
7749 *cutoff = TRUE;
7750
7751 /* analyze the cutoff in SOLVING stage and if conflict analysis is turned on */
7753 {
7754 /* start conflict analysis with the fixed-to-one variables, add only as many as needed to exceed the capacity */
7755 SCIP_Longint weight;
7756
7757 weight = 0;
7758
7760
7761 for( i = 0; i < nvars && weight <= consdata->capacity; i++ )
7762 {
7763 if( SCIPvarGetLbLocal(consdata->vars[i]) > 0.5)
7764 {
7765 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
7766 weight += consdata->weights[i];
7767 }
7768 }
7769
7771 }
7772
7773 return SCIP_OKAY;
7774 }
7775
7776 /* the algorithm below is a special case of propagation involving negated cliques */
7777 if( !usenegatedclique )
7778 {
7779 assert(consdata->sorted);
7780 residualcapacity = consdata->capacity - consdata->onesweightsum;
7781
7782 /* fix all variables to zero, that don't fit into the knapsack anymore */
7783 for( i = 0; i < nvars && consdata->weights[i] > residualcapacity; ++i )
7784 {
7785 /* if all weights of fixed variables to one plus any weight exceeds the capacity the variables have to be fixed
7786 * to zero
7787 */
7788 if( SCIPvarGetLbLocal(consdata->vars[i]) < 0.5 )
7789 {
7790 if( SCIPvarGetUbLocal(consdata->vars[i]) > 0.5 )
7791 {
7792 assert(consdata->onesweightsum + consdata->weights[i] > consdata->capacity);
7793 SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(consdata->vars[i]));
7795 SCIP_CALL( SCIPinferBinvarCons(scip, consdata->vars[i], FALSE, cons, i, &infeasible, &tightened) );
7796 assert(!infeasible);
7797 assert(tightened);
7798 (*nfixedvars)++;
7799 }
7800 }
7801 }
7802 }
7803
7804 /* check if the knapsack is now redundant */
7805 if( !SCIPconsIsModifiable(cons) )
7806 {
7807 SCIP_Longint unfixedweightsum = consdata->onesweightsum;
7808
7809 /* sum up the weights of all unfixed variables, plus the weight sum of all variables fixed to one already */
7810 for( i = 0; i < nvars; ++i )
7811 {
7812 if( SCIPvarGetLbLocal(consdata->vars[i]) + 0.5 < SCIPvarGetUbLocal(consdata->vars[i]) )
7813 {
7814 unfixedweightsum += consdata->weights[i];
7815
7816 /* the weight sum is larger than the capacity, so the constraint is not redundant */
7817 if( unfixedweightsum > consdata->capacity )
7818 return SCIP_OKAY;
7819 }
7820 }
7821 /* we summed up all (unfixed and fixed to one) weights and did not exceed the capacity, so the constraint is redundant */
7822 SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", unfixedweightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
7823 SCIPconsGetName(cons), consdata->weightsum, unfixedweightsum, consdata->capacity);
7825 *redundant = TRUE;
7826 }
7827
7828 return SCIP_OKAY;
7829}
7830
7831/** all but one variable fit into the knapsack constraint, so we can upgrade this constraint to an logicor constraint
7832 * containing all negated variables of this knapsack constraint
7833 */
7834static
7836 SCIP* scip, /**< SCIP data structure */
7837 SCIP_CONS* cons, /**< knapsack constraint */
7838 int* ndelconss, /**< pointer to store the amount of deleted constraints */
7839 int* naddconss /**< pointer to count number of added constraints */
7840 )
7841{
7842 SCIP_CONS* newcons;
7843 SCIP_CONSDATA* consdata;
7844
7845 assert(scip != NULL);
7846 assert(cons != NULL);
7847 assert(ndelconss != NULL);
7848 assert(naddconss != NULL);
7849
7850 consdata = SCIPconsGetData(cons);
7851 assert(consdata != NULL);
7852 assert(consdata->nvars > 1);
7853
7854 /* if the knapsack constraint consists only of two variables, we can upgrade it to a set-packing constraint */
7855 if( consdata->nvars == 2 )
7856 {
7857 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
7858
7859 SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
7863 SCIPconsIsStickingAtNode(cons)) );
7864 }
7865 /* if the knapsack constraint consists of at least three variables, we can upgrade it to a logicor constraint
7866 * containing all negated variables of the knapsack
7867 */
7868 else
7869 {
7870 SCIP_VAR** consvars;
7871
7872 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a logicor constraint", SCIPconsGetName(cons));
7873
7874 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, consdata->nvars) );
7875 SCIP_CALL( SCIPgetNegatedVars(scip, consdata->nvars, consdata->vars, consvars) );
7876
7877 SCIP_CALL( SCIPcreateConsLogicor(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consvars,
7881 SCIPconsIsStickingAtNode(cons)) );
7882
7883 SCIPfreeBufferArray(scip, &consvars);
7884 }
7885
7886 SCIP_CALL( SCIPaddCons(scip, newcons) );
7887 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
7888 ++(*naddconss);
7889
7890 SCIP_CALL( SCIPdelCons(scip, cons) );
7891 ++(*ndelconss);
7892
7893 return SCIP_OKAY;
7894}
7895
7896/** delete redundant variables
7897 *
7898 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
7899 *
7900 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
7901 * => x4, x5 always fits into the knapsack, so we can delete them
7902 *
7903 * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
7904 * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
7905 */
7906static
7908 SCIP* scip, /**< SCIP data structure */
7909 SCIP_CONS* cons, /**< knapsack constraint */
7910 SCIP_Longint frontsum, /**< sum of front items which fit if we try to take from the first till the last */
7911 int splitpos, /**< split position till when all front items are fitting, splitpos is the
7912 * first which did not fit */
7913 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
7914 int* nchgsides, /**< pointer to store the amount of changed sides */
7915 int* naddconss /**< pointer to count number of added constraints */
7916 )
7917{
7918 SCIP_CONSHDLRDATA* conshdlrdata;
7919 SCIP_CONSDATA* consdata;
7920 SCIP_VAR** vars;
7921 SCIP_Longint* weights;
7922 SCIP_Longint capacity;
7923 SCIP_Longint gcd;
7924 int nvars;
7925 int w;
7926
7927 assert(scip != NULL);
7928 assert(cons != NULL);
7929 assert(nchgcoefs != NULL);
7930 assert(nchgsides != NULL);
7931 assert(naddconss != NULL);
7932
7933 consdata = SCIPconsGetData(cons);
7934 assert(consdata != NULL);
7935 assert(0 < frontsum && frontsum < consdata->weightsum);
7936 assert(0 < splitpos && splitpos < consdata->nvars);
7937
7938 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7939 assert(conshdlrdata != NULL);
7940
7941 vars = consdata->vars;
7942 weights = consdata->weights;
7943 nvars = consdata->nvars;
7944 capacity = consdata->capacity;
7945
7946 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
7947 * weight must not be sorted by their index
7948 */
7949#ifndef NDEBUG
7950 for( w = nvars - 1; w > 0; --w )
7951 assert(weights[w] <= weights[w-1]);
7952#endif
7953
7954 /* if there are no variables rear to splitpos, the constraint has no redundant variables */
7955 if( consdata->nvars - 1 == splitpos )
7956 return SCIP_OKAY;
7957
7958 assert(frontsum + weights[splitpos] > capacity);
7959
7960 /* detect redundant variables */
7961 if( consdata->weightsum - weights[splitpos] <= capacity )
7962 {
7963 /* all rear items are redundant, because leaving one item in front and incl. of splitpos out the rear itmes always
7964 * fit
7965 */
7966 SCIPdebugMsg(scip, "Found redundant variables in constraint <%s>.\n", SCIPconsGetName(cons));
7967
7968 /* delete items and update capacity */
7969 for( w = nvars - 1; w > splitpos; --w )
7970 {
7971 consdata->capacity -= weights[w];
7972 SCIP_CALL( delCoefPos(scip, cons, w) );
7973 }
7974 assert(w == splitpos);
7975
7976 ++(*nchgsides);
7977 *nchgcoefs += (nvars - splitpos);
7978
7979 /* division by greatest common divisor */
7980 gcd = weights[w];
7981 for( ; w >= 0 && gcd > 1; --w )
7982 {
7983 gcd = SCIPcalcGreComDiv(gcd, weights[w]);
7984 }
7985
7986 /* normalize if possible */
7987 if( gcd > 1 )
7988 {
7989 for( w = splitpos; w >= 0; --w )
7990 {
7991 consdataChgWeight(consdata, w, weights[w]/gcd);
7992 }
7993 (*nchgcoefs) += nvars;
7994
7995 consdata->capacity /= gcd;
7996 ++(*nchgsides);
7997 }
7998
7999 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8000 * weight must not be sorted by their index
8001 */
8002#ifndef NDEBUG
8003 for( w = consdata->nvars - 1; w > 0; --w )
8004 assert(weights[w] <= weights[w - 1]);
8005#endif
8006 }
8007 /* rear items can only be redundant, when the sum is smaller to the weight at splitpos and all rear items would
8008 * always fit into the knapsack, therefor the item directly after splitpos needs to be smaller than the one at
8009 * splitpos and needs to fit into the knapsack
8010 */
8011 else if( conshdlrdata->disaggregation && frontsum + weights[splitpos + 1] <= capacity )
8012 {
8013 int* clqpart;
8014 int nclq;
8015 int len;
8016
8017 len = nvars - (splitpos + 1);
8018 /* allocate temporary memory */
8019 SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
8020
8021 /* calculate clique partition */
8022 SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[splitpos+1]), len, clqpart, &nclq) );
8023
8024 /* check if we found at least one clique */
8025 if( nclq < len )
8026 {
8027 SCIP_Longint maxactduetoclq;
8028 int cliquenum;
8029
8030 maxactduetoclq = 0;
8031 cliquenum = 0;
8032
8033 /* calculate maximum activity due to cliques */
8034 for( w = 0; w < len; ++w )
8035 {
8036 assert(clqpart[w] >= 0 && clqpart[w] <= w);
8037 if( clqpart[w] == cliquenum )
8038 {
8039 maxactduetoclq += weights[w + splitpos + 1];
8040 ++cliquenum;
8041 }
8042 }
8043
8044 /* all rear items are redundant due to clique information, if maxactduetoclq is smaller than the weight before,
8045 * so delete them and create for all clique the corresponding clique constraints and update the capacity
8046 */
8047 if( frontsum + maxactduetoclq <= capacity )
8048 {
8049 SCIP_VAR** clqvars;
8050 int nclqvars;
8051 int c;
8052
8053 assert(maxactduetoclq < weights[splitpos]);
8054
8055 SCIPdebugMsg(scip, "Found redundant variables in constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8056
8057 /* allocate temporary memory */
8058 SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, len - nclq + 1) );
8059
8060 for( c = 0; c < nclq; ++c )
8061 {
8062 nclqvars = 0;
8063 for( w = 0; w < len; ++w )
8064 {
8065 if( clqpart[w] == c )
8066 {
8067 clqvars[nclqvars] = vars[w + splitpos + 1];
8068 ++nclqvars;
8069 }
8070 }
8071
8072 /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8073 if( nclqvars > 1 )
8074 {
8075 SCIP_CONS* cliquecons;
8076 char name[SCIP_MAXSTRLEN];
8077
8078 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8079 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8083 SCIPconsIsStickingAtNode(cons)) );
8084 SCIPdebugMsg(scip, " -> adding clique constraint: ");
8085 SCIPdebugPrintCons(scip, cliquecons, NULL);
8086 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8087 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8088 ++(*naddconss);
8089 }
8090 }
8091
8092 /* delete items and update capacity */
8093 for( w = nvars - 1; w > splitpos; --w )
8094 {
8095 SCIP_CALL( delCoefPos(scip, cons, w) );
8096 ++(*nchgcoefs);
8097 }
8098 consdata->capacity -= maxactduetoclq;
8099 assert(frontsum <= consdata->capacity);
8100 ++(*nchgsides);
8101
8102 assert(w == splitpos);
8103
8104 /* renew weights pointer */
8105 weights = consdata->weights;
8106
8107 /* division by greatest common divisor */
8108 gcd = weights[w];
8109 for( ; w >= 0 && gcd > 1; --w )
8110 {
8111 gcd = SCIPcalcGreComDiv(gcd, weights[w]);
8112 }
8113
8114 /* normalize if possible */
8115 if( gcd > 1 )
8116 {
8117 for( w = splitpos; w >= 0; --w )
8118 {
8119 consdataChgWeight(consdata, w, weights[w]/gcd);
8120 }
8121 (*nchgcoefs) += nvars;
8122
8123 consdata->capacity /= gcd;
8124 ++(*nchgsides);
8125 }
8126
8127 /* free temporary memory */
8128 SCIPfreeBufferArray(scip, &clqvars);
8129
8130 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8131 * weight must not be sorted by their index
8132 */
8133#ifndef NDEBUG
8134 for( w = consdata->nvars - 1; w > 0; --w )
8135 assert(weights[w] <= weights[w - 1]);
8136#endif
8137 }
8138 }
8139
8140 /* free temporary memory */
8141 SCIPfreeBufferArray(scip, &clqpart);
8142 }
8143
8144 return SCIP_OKAY;
8145}
8146
8147/* detect redundant variables which always fits into the knapsack
8148 *
8149 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
8150 *
8151 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
8152 * => x4, x5 always fits into the knapsack, so we can delete them
8153 *
8154 * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
8155 * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
8156 */
8157static
8159 SCIP* scip, /**< SCIP data structure */
8160 SCIP_CONS* cons, /**< knapsack constraint */
8161 int* ndelconss, /**< pointer to store the amount of deleted constraints */
8162 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8163 int* nchgsides, /**< pointer to store the amount of changed sides */
8164 int* naddconss /**< pointer to count number of added constraints */
8165 )
8166{
8167 SCIP_CONSHDLRDATA* conshdlrdata;
8168 SCIP_CONSDATA* consdata;
8169 SCIP_VAR** vars;
8170 SCIP_Longint* weights;
8171 SCIP_Longint capacity;
8172 SCIP_Longint sum;
8173 int noldchgcoefs;
8174 int nvars;
8175 int v;
8176 int w;
8177
8178 assert(scip != NULL);
8179 assert(cons != NULL);
8180 assert(ndelconss != NULL);
8181 assert(nchgcoefs != NULL);
8182 assert(nchgsides != NULL);
8183 assert(naddconss != NULL);
8184
8185 consdata = SCIPconsGetData(cons);
8186 assert(consdata != NULL);
8187 assert(consdata->nvars >= 2);
8188 assert(consdata->weightsum > consdata->capacity);
8189
8190 noldchgcoefs = *nchgcoefs;
8191 vars = consdata->vars;
8192 weights = consdata->weights;
8193 nvars = consdata->nvars;
8194 capacity = consdata->capacity;
8195 sum = 0;
8196
8197 /* search for maximal fitting items */
8198 for( v = 0; v < nvars && sum + weights[v] <= capacity; ++v )
8199 sum += weights[v];
8200
8201 assert(v < nvars);
8202
8203 /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8204 if( v == nvars - 1 )
8205 {
8206 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8207 assert(SCIPconsIsDeleted(cons));
8208
8209 return SCIP_OKAY;
8210 }
8211
8212 if( v < nvars - 1 )
8213 {
8214 /* try to delete variables */
8215 SCIP_CALL( deleteRedundantVars(scip, cons, sum, v, nchgcoefs, nchgsides, naddconss) );
8216 assert(consdata->nvars > 1);
8217
8218 /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8219 if( v == consdata->nvars - 1 )
8220 {
8221 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8222 assert(SCIPconsIsDeleted(cons));
8223 }
8224
8225 return SCIP_OKAY;
8226 }
8227
8228 /* if we already found some redundant variables, stop here */
8229 if( *nchgcoefs > noldchgcoefs )
8230 return SCIP_OKAY;
8231
8232 assert(vars == consdata->vars);
8233 assert(weights == consdata->weights);
8234 assert(nvars == consdata->nvars);
8235 assert(capacity == consdata->capacity);
8236
8237 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
8238 assert(conshdlrdata != NULL);
8239 /* calculate clique partition */
8240 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
8241
8242 /* check for real existing cliques */
8243 if( consdata->cliquepartition[v] < v )
8244 {
8245 SCIP_Longint sumfront;
8246 SCIP_Longint maxactduetoclqfront;
8247 int* clqpart;
8248 int cliquenum;
8249
8250 sumfront = 0;
8251 maxactduetoclqfront = 0;
8252
8253 clqpart = consdata->cliquepartition;
8254 cliquenum = 0;
8255
8256 /* calculate maximal activity due to cliques */
8257 for( w = 0; w < nvars; ++w )
8258 {
8259 assert(clqpart[w] >= 0 && clqpart[w] <= w);
8260 if( clqpart[w] == cliquenum )
8261 {
8262 if( maxactduetoclqfront + weights[w] <= capacity )
8263 {
8264 maxactduetoclqfront += weights[w];
8265 ++cliquenum;
8266 }
8267 else
8268 break;
8269 }
8270 sumfront += weights[w];
8271 }
8272 assert(w >= v);
8273
8274 /* if all items fit, then delete the whole constraint but create clique constraints which led to this
8275 * information
8276 */
8277 if( conshdlrdata->disaggregation && w == nvars )
8278 {
8279 SCIP_VAR** clqvars;
8280 int nclqvars;
8281 int c;
8282 int ncliques;
8283
8284 assert(maxactduetoclqfront <= capacity);
8285
8286 SCIPdebugMsg(scip, "Found redundant constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8287
8288 ncliques = consdata->ncliques;
8289
8290 /* allocate temporary memory */
8291 SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, nvars - ncliques + 1) );
8292
8293 for( c = 0; c < ncliques; ++c )
8294 {
8295 nclqvars = 0;
8296 for( w = 0; w < nvars; ++w )
8297 {
8298 if( clqpart[w] == c )
8299 {
8300 clqvars[nclqvars] = vars[w];
8301 ++nclqvars;
8302 }
8303 }
8304
8305 /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8306 if( nclqvars > 1 )
8307 {
8308 SCIP_CONS* cliquecons;
8309 char name[SCIP_MAXSTRLEN];
8310
8311 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8312 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8316 SCIPconsIsStickingAtNode(cons)) );
8317 SCIPdebugMsg(scip, " -> adding clique constraint: ");
8318 SCIPdebugPrintCons(scip, cliquecons, NULL);
8319 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8320 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8321 ++(*naddconss);
8322 }
8323 }
8324
8325 /* delete old constraint */
8327 ++(*ndelconss);
8328
8329 SCIPfreeBufferArray(scip, &clqvars);
8330
8331 return SCIP_OKAY;
8332 }
8333
8334 if( w > v && w < nvars - 1 )
8335 {
8336 /* try to delete variables */
8337 SCIP_CALL( deleteRedundantVars(scip, cons, sumfront, w, nchgcoefs, nchgsides, naddconss) );
8338 }
8339 }
8340
8341 return SCIP_OKAY;
8342}
8343
8344/** divides weights by their greatest common divisor and divides capacity by the same value, rounding down the result */
8345static
8347 SCIP_CONS* cons, /**< knapsack constraint */
8348 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
8349 int* nchgsides /**< pointer to count number of side changes */
8350 )
8351{
8352 SCIP_CONSDATA* consdata;
8353 SCIP_Longint gcd;
8354 int i;
8355
8356 assert(nchgcoefs != NULL);
8357 assert(nchgsides != NULL);
8358 assert(!SCIPconsIsModifiable(cons));
8359
8360 consdata = SCIPconsGetData(cons);
8361 assert(consdata != NULL);
8362 assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
8363 assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
8364 assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
8365 assert(consdata->nvars >= 1);
8366
8367 /* sort items, because we can stop earlier if the smaller weights are evaluated first */
8368 sortItems(consdata);
8369
8370 gcd = consdata->weights[consdata->nvars-1];
8371 for( i = consdata->nvars-2; i >= 0 && gcd >= 2; --i )
8372 {
8373 assert(SCIPvarGetLbLocal(consdata->vars[i]) < 0.5);
8374 assert(SCIPvarGetUbLocal(consdata->vars[i]) > 0.5); /* all fixed variables should have been removed */
8375
8376 gcd = SCIPcalcGreComDiv(gcd, consdata->weights[i]);
8377 }
8378
8379 if( gcd >= 2 )
8380 {
8381 SCIPdebugMessage("knapsack constraint <%s>: dividing weights by %" SCIP_LONGINT_FORMAT "\n", SCIPconsGetName(cons), gcd);
8382
8383 for( i = 0; i < consdata->nvars; ++i )
8384 {
8385 consdataChgWeight(consdata, i, consdata->weights[i]/gcd);
8386 }
8387 consdata->capacity /= gcd;
8388 (*nchgcoefs) += consdata->nvars;
8389 (*nchgsides)++;
8390
8391 /* weight should still be sorted, because the reduction preserves this */
8392#ifndef NDEBUG
8393 for( i = consdata->nvars - 1; i > 0; --i )
8394 assert(consdata->weights[i] <= consdata->weights[i - 1]);
8395#endif
8396 consdata->sorted = TRUE;
8397 }
8398}
8399
8400/** dual weights tightening for knapsack constraints
8401 *
8402 * 1. a) check if all two pairs exceed the capacity, then we can upgrade this constraint to a set-packing constraint
8403 * b) check if all but the smallest weight fit into the knapsack, then we can upgrade this constraint to a logicor
8404 * constraint
8405 *
8406 * 2. check if besides big coefficients, that fit only by itself, for a certain amount of variables all combination of
8407 * these are a minimal cover, then might reduce the weights and the capacity, e.g.
8408 *
8409 * +219y1 + 180y2 + 74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8410 *
8411 * 3. use the duality between a^Tx <= capacity <=> a^T~x >= weightsum - capacity to tighten weights, e.g.
8412 *
8413 * 11x1 + 10x2 + 7x3 + 7x4 + 5x5 <= 27 <=> 11~x1 + 10~x2 + 7~x3 + 7~x4 + 5~x5 >= 13
8414 *
8415 * the above constraint can be changed to 8~x1 + 8~x2 + 6.5~x3 + 6.5~x4 + 5~x5 >= 13
8416 *
8417 * 16~x1 + 16~x2 + 13~x3 + 13~x4 + 10~x5 >= 26 <=> 16x1 + 16x2 + 13x3 + 13x4 + 10x5 <= 42
8418 */
8419static
8421 SCIP* scip, /**< SCIP data structure */
8422 SCIP_CONS* cons, /**< knapsack constraint */
8423 int* ndelconss, /**< pointer to store the amount of deleted constraints */
8424 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8425 int* nchgsides, /**< pointer to store the amount of changed sides */
8426 int* naddconss /**< pointer to count number of added constraints */
8427 )
8428{
8429 SCIP_CONSDATA* consdata;
8430 SCIP_Longint* weights;
8431 SCIP_Longint dualcapacity;
8432 SCIP_Longint reductionsum;
8433 SCIP_Longint capacity;
8434 SCIP_Longint exceedsum;
8435 int oldnchgcoefs;
8436 int nvars;
8437 int vbig;
8438 int v;
8439 int w;
8440#ifndef NDEBUG
8441 int oldnchgsides;
8442#endif
8443
8444 assert(scip != NULL);
8445 assert(cons != NULL);
8446 assert(ndelconss != NULL);
8447 assert(nchgcoefs != NULL);
8448 assert(nchgsides != NULL);
8449 assert(naddconss != NULL);
8450
8451#ifndef NDEBUG
8452 oldnchgsides = *nchgsides;
8453#endif
8454
8455 consdata = SCIPconsGetData(cons);
8456 assert(consdata != NULL);
8457 assert(consdata->weightsum > consdata->capacity);
8458 assert(consdata->nvars >= 2);
8459 assert(consdata->sorted);
8460
8461 /* constraint should be merged */
8462 assert(consdata->merged);
8463
8464 nvars = consdata->nvars;
8465 weights = consdata->weights;
8466 capacity = consdata->capacity;
8467
8468 oldnchgcoefs = *nchgcoefs;
8469
8470 /* case 1. */
8471 if( weights[nvars - 1] + weights[nvars - 2] > capacity )
8472 {
8473 SCIP_CONS* newcons;
8474
8475 /* two variable are enough to exceed the constraint, so we can update it to a set-packing
8476 *
8477 * e.g. 5x1 + 4x2 + 3x3 <= 5 <=> x1 + x2 + x3 <= 1
8478 */
8479 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
8480
8481 SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
8485 SCIPconsIsStickingAtNode(cons)) );
8486
8487 SCIP_CALL( SCIPaddCons(scip, newcons) );
8488 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
8489 ++(*naddconss);
8490
8491 SCIP_CALL( SCIPdelCons(scip, cons) );
8492 ++(*ndelconss);
8493
8494 return SCIP_OKAY;
8495 }
8496
8497 /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8498 if( consdata->weightsum - weights[nvars - 1] <= consdata->capacity )
8499 {
8500 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8501 assert(SCIPconsIsDeleted(cons));
8502
8503 return SCIP_OKAY;
8504 }
8505
8506 /* early termination, if the pair with biggest coeffcients together does not exceed the dualcapacity */
8507 /* @todo might be changed/removed when improving the coeffcients tightening */
8508 if( consdata->weightsum - capacity > weights[0] + weights[1] )
8509 return SCIP_OKAY;
8510
8511 /* case 2. */
8512
8513 v = 0;
8514
8515 /* @todo generalize the following algorithm for several parts of the knapsack
8516 *
8517 * the following is done without looking at the dualcapacity; it is enough to check whether for a certain amount of
8518 * variables each combination is a minimal cover, some examples
8519 *
8520 * +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 74~x1 + 70~x2 + 63~x3 + 62~x4 + 53~x5 >= 103
8521 * <=> ~x1 + ~x2 + ~x3 + ~x4 + ~x5 >= 2
8522 * <=> x1 + x2 + x3 + x4 + x5 <= 3
8523 *
8524 * +219y1 + 180y_2 +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8525 *
8526 */
8527
8528 /* determine big weights that fit only by itself */
8529 while( v < nvars && weights[v] + weights[nvars - 1] > capacity )
8530 ++v;
8531
8532 vbig = v;
8533 assert(vbig < nvars - 1);
8534 exceedsum = 0;
8535
8536 /* determine the amount needed to exceed the capacity */
8537 while( v < nvars && exceedsum <= capacity )
8538 {
8539 exceedsum += weights[v];
8540 ++v;
8541 }
8542
8543 /* if we exceeded the capacity we might reduce the weights */
8544 if( exceedsum > capacity )
8545 {
8546 assert(vbig > 0 || v < nvars);
8547
8548 /* all small weights were needed to exceed the capacity */
8549 if( v == nvars )
8550 {
8551 SCIP_Longint newweight = (SCIP_Longint)nvars - vbig - 1;
8552 assert(newweight > 0);
8553
8554 /* reduce big weights */
8555 for( v = 0; v < vbig; ++v )
8556 {
8557 if( weights[v] > newweight )
8558 {
8559 consdataChgWeight(consdata, v, newweight);
8560 ++(*nchgcoefs);
8561 }
8562 }
8563
8564 /* reduce small weights */
8565 for( ; v < nvars; ++v )
8566 {
8567 if( weights[v] > 1 )
8568 {
8569 consdataChgWeight(consdata, v, 1LL);
8570 ++(*nchgcoefs);
8571 }
8572 }
8573
8574 consdata->capacity = newweight;
8575
8576 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8577 * weight must not be sorted by their index
8578 */
8579#ifndef NDEBUG
8580 for( v = nvars - 1; v > 0; --v )
8581 assert(weights[v] <= weights[v-1]);
8582#endif
8583
8584 return SCIP_OKAY;
8585 }
8586 /* a certain amount of small variables exceed the capacity, so check if this holds for all combinations of the
8587 * small weights
8588 */
8589 else
8590 {
8591 SCIP_Longint exceedsumback = 0;
8592 int nexceed = v - vbig;
8593
8594 assert(nexceed > 1);
8595
8596 /* determine weightsum of the same amount as before but of the smallest weight */
8597 for( w = nvars - 1; w >= nvars - nexceed; --w )
8598 exceedsumback += weights[w];
8599
8600 assert(w >= 0);
8601
8602 /* if the same amount but with the smallest possible weights also exceed the capacity, it holds for all
8603 * combinations of all small weights
8604 */
8605 if( exceedsumback > capacity )
8606 {
8607 SCIP_Longint newweight = nexceed - 1;
8608
8609 /* taking out the smallest element needs to fit */
8610 assert(exceedsumback - weights[nvars - 1] <= capacity);
8611
8612 /* reduce big weights */
8613 for( v = 0; v < vbig; ++v )
8614 {
8615 if( weights[v] > newweight )
8616 {
8617 consdataChgWeight(consdata, v, newweight);
8618 ++(*nchgcoefs);
8619 }
8620 }
8621
8622 /* reduce small weights */
8623 for( ; v < nvars; ++v )
8624 {
8625 if( weights[v] > 1 )
8626 {
8627 consdataChgWeight(consdata, v, 1LL);
8628 ++(*nchgcoefs);
8629 }
8630 }
8631
8632 consdata->capacity = newweight;
8633
8634 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8635 * weight must not be sorted by their index
8636 */
8637#ifndef NDEBUG
8638 for( v = nvars - 1; v > 0; --v )
8639 assert(weights[v] <= weights[v-1]);
8640#endif
8641 return SCIP_OKAY;
8642 }
8643 }
8644 }
8645 else
8646 {
8647 /* if the following assert fails we have either a redundant constraint or a set-packing constraint, this should
8648 * not happen here
8649 */
8650 assert(vbig > 0 && vbig < nvars);
8651
8652 /* either choose a big coefficients or all other variables
8653 *
8654 * 973x1 + 189x2 + 189x3 + 145x4 + 110x5 + 104x6 + 93x7 + 71x8 + 68x9 + 10x10 <= 979
8655 *
8656 * either choose x1, or all other variables (weightsum of x2 to x10 is 979 above), so we can tighten this
8657 * constraint to
8658 *
8659 * 9x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 <= 9
8660 */
8661
8662 if( weights[vbig - 1] > (SCIP_Longint)nvars - vbig || weights[vbig] > 1 )
8663 {
8664 SCIP_Longint newweight = (SCIP_Longint)nvars - vbig;
8665#ifndef NDEBUG
8666 SCIP_Longint resweightsum = consdata->weightsum;
8667
8668 for( v = 0; v < vbig; ++v )
8669 resweightsum -= weights[v];
8670
8671 assert(exceedsum == resweightsum);
8672#endif
8673 assert(newweight > 0);
8674
8675 /* reduce big weights */
8676 for( v = 0; v < vbig; ++v )
8677 {
8678 if( weights[v] > newweight )
8679 {
8680 consdataChgWeight(consdata, v, newweight);
8681 ++(*nchgcoefs);
8682 }
8683 }
8684
8685 /* reduce small weights */
8686 for( ; v < nvars; ++v )
8687 {
8688 if( weights[v] > 1 )
8689 {
8690 consdataChgWeight(consdata, v, 1LL);
8691 ++(*nchgcoefs);
8692 }
8693 }
8694
8695 consdata->capacity = newweight;
8696
8697 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8698 * weight must not be sorted by their index
8699 */
8700#ifndef NDEBUG
8701 for( v = nvars - 1; v > 0; --v )
8702 assert(weights[v] <= weights[v-1]);
8703#endif
8704 return SCIP_OKAY;
8705 }
8706 }
8707
8708 /* case 3. */
8709
8710 dualcapacity = consdata->weightsum - capacity;
8711 reductionsum = 0;
8712 v = 0;
8713
8714 /* reduce big weights
8715 *
8716 * e.g. 11x0 + 11x1 + 10x2 + 10x3 <= 32 <=> 11~x0 + 11~x1 + 10~x2 + 10~x3 >= 10
8717 * <=> 10~x0 + 10~x1 + 10~x2 + 10~x3 >= 10
8718 * <=> x0 + x1 + x2 + x3 <= 3
8719 */
8720 while( weights[v] > dualcapacity )
8721 {
8722 reductionsum += (weights[v] - dualcapacity);
8723 consdataChgWeight(consdata, v, dualcapacity);
8724 ++v;
8725 assert(v < nvars);
8726 }
8727 (*nchgcoefs) += v;
8728
8729 /* skip weights equal to the dualcapacity, because we cannot change them */
8730 while( v < nvars && weights[v] == dualcapacity )
8731 ++v;
8732
8733 /* any negated variable out of the first n - 1 items is enough to fulfill the constraint, so we can update it to a logicor
8734 * after a possible removal of the last, redundant item
8735 *
8736 * e.g. 10x1 + 10x2 + 10x3 <= 20 <=> 10~x1 + 10~x2 + 10~x3 >= 10 <=> ~x1 + ~x2 + ~x3 >= 1
8737 */
8738 if( v >= nvars - 1 )
8739 {
8740 /* the last weight is not enough to satisfy the dual capacity -> remove this redundant item */
8741 if( v == nvars - 1 )
8742 {
8743 SCIP_CALL( delCoefPos(scip, cons, nvars - 1) );
8744 }
8745 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8746 assert(SCIPconsIsDeleted(cons));
8747
8748 return SCIP_OKAY;
8749 }
8750 else /* v < nvars - 1 <=> at least two items with weight smaller than the dual capacity */
8751 {
8752 /* @todo generalize the following algorithm for more than two variables */
8753
8754 if( weights[nvars - 1] + weights[nvars - 2] >= dualcapacity )
8755 {
8756 /* we have a dual-knapsack constraint where we either need to choose one variable out of a subset (big
8757 * coefficients) of all or two variables of the rest
8758 *
8759 * e.g. 9x1 + 9x2 + 6x3 + 4x4 <= 19 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 >= 9
8760 * <=> 2~x1 + 2~x2 + ~x3 + ~x4 >= 2
8761 * <=> 2x1 + 2x2 + x3 + x4 <= 4
8762 *
8763 * 3x1 + 3x2 + 2x3 + 2x4 + 2x5 + 2x6 + x7 <= 12 <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + 2~x5 + 2~x6 + ~x7 >= 3
8764 * <=> 2~x1 + 2~x2 + ~x3 + ~x4 + ~x5 + ~x6 + ~x7 >= 2
8765 * <=> 2 x1 + 2 x2 + x3 + x4 + x5 + x6 + x7 <= 7
8766 *
8767 */
8768 if( v > 0 && weights[nvars - 2] > 1 )
8769 {
8770 int ncoefchg = 0;
8771
8772 /* reduce all bigger weights */
8773 for( w = 0; w < v; ++w )
8774 {
8775 if( weights[w] > 2 )
8776 {
8777 consdataChgWeight(consdata, w, 2LL);
8778 ++ncoefchg;
8779 }
8780 else
8781 {
8782 assert(weights[0] == 2);
8783 assert(weights[v - 1] == 2);
8784 break;
8785 }
8786 }
8787
8788 /* reduce all smaller weights */
8789 for( w = v; w < nvars; ++w )
8790 {
8791 if( weights[w] > 1 )
8792 {
8793 consdataChgWeight(consdata, w, 1LL);
8794 ++ncoefchg;
8795 }
8796 }
8797 assert(ncoefchg > 0);
8798
8799 (*nchgcoefs) += ncoefchg;
8800
8801 /* correct the capacity */
8802 consdata->capacity = (-2 + v * 2 + nvars - v); /*lint !e647*/
8803 assert(consdata->capacity > 0);
8804 assert(weights[0] <= consdata->capacity);
8805 assert(consdata->weightsum > consdata->capacity);
8806 /* reset the reductionsum */
8807 reductionsum = 0;
8808 }
8809 else if( v == 0 )
8810 {
8811 assert(weights[nvars - 2] == 1);
8812 }
8813 }
8814 else
8815 {
8816 SCIP_Longint minweight = weights[nvars - 1];
8817 SCIP_Longint newweight = dualcapacity - minweight;
8818 SCIP_Longint restsumweights = 0;
8819 SCIP_Longint sumcoef;
8820 SCIP_Bool sumcoefcase = FALSE;
8821 int startv = v;
8822 int end;
8823 int k;
8824
8825 assert(weights[nvars - 1] + weights[nvars - 2] <= capacity);
8826
8827 /* reduce big weights of pairs that exceed the dualcapacity
8828 *
8829 * e.g. 9x1 + 9x2 + 6x3 + 4x4 + 4x5 + 4x6 <= 27 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8830 * <=> 9~x1 + 9~x2 + 5~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8831 * <=> 9x1 + 9x2 + 5x3 + 4x4 + 4x5 + 4x6 <= 27
8832 */
8833 while( weights[v] > newweight )
8834 {
8835 reductionsum += (weights[v] - newweight);
8836 consdataChgWeight(consdata, v, newweight);
8837 ++v;
8838 assert(v < nvars);
8839 }
8840 (*nchgcoefs) += (v - startv);
8841
8842 /* skip equal weights */
8843 while( weights[v] == newweight )
8844 ++v;
8845
8846 if( v > 0 )
8847 {
8848 for( w = v; w < nvars; ++w )
8849 restsumweights += weights[w];
8850 }
8851 else
8852 restsumweights = consdata->weightsum;
8853
8854 if( restsumweights < dualcapacity )
8855 {
8856 /* we found redundant variables, which does not influence the feasibility of any integral solution, e.g.
8857 *
8858 * +61x1 + 61x2 + 61x3 + 61x4 + 61x5 + 61x6 + 35x7 + 10x8 <= 350 <=>
8859 * +61~x1 + 61~x2 + 61~x3 + 61~x4 + 61~x5 + 61~x6 + 35~x7 + 10~x8 >= 61
8860 */
8861 if( startv == v )
8862 {
8863 /* remove redundant variables */
8864 for( w = nvars - 1; w >= v; --w )
8865 {
8866 SCIP_CALL( delCoefPos(scip, cons, v) );
8867 ++(*nchgcoefs);
8868 }
8869
8870#ifndef NDEBUG
8871 /* each coefficients should exceed the dualcapacity by itself */
8872 for( ; w >= 0; --w )
8873 assert(weights[w] == dualcapacity);
8874#endif
8875 /* for performance reasons we do not update the capacity(, i.e. reduce it by reductionsum) and directly
8876 * upgrade this constraint
8877 */
8878 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8879 assert(SCIPconsIsDeleted(cons));
8880
8881 return SCIP_OKAY;
8882 }
8883
8884 /* special case where we have three different coefficient types
8885 *
8886 * e.g. 9x1 + 9x2 + 6x3 + 6x4 + 4x5 + 4x6 <= 29 <=> 9~x1 + 9~x2 + 6~x3 + 6~x4 + 4~x5 + 4~x6 >= 9
8887 * <=> 9~x1 + 9~x2 + 5~x3 + 5~x4 + 4~x5 + 4~x6 >= 9
8888 * <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + ~x5 + ~x6 >= 3
8889 * <=> 3x1 + 3x2 + 2x3 + 2x4 + x5 + x6 <= 9
8890 */
8891 if( weights[v] > 1 || (weights[startv] > (SCIP_Longint)nvars - v) || (startv > 0 && weights[0] == (SCIP_Longint)nvars - v + 1) )
8892 {
8893 SCIP_Longint newcap;
8894
8895 /* adjust smallest coefficients, which all together do not exceed the dualcapacity */
8896 for( w = nvars - 1; w >= v; --w )
8897 {
8898 if( weights[w] > 1 )
8899 {
8900 consdataChgWeight(consdata, w, 1LL);
8901 ++(*nchgcoefs);
8902 }
8903 }
8904
8905 /* adjust middle sized coefficients, which when choosing also one small coefficients exceed the
8906 * dualcapacity
8907 */
8908 newweight = (SCIP_Longint)nvars - v;
8909 assert(newweight > 1);
8910 for( ; w >= startv; --w )
8911 {
8912 if( weights[w] > newweight )
8913 {
8914 consdataChgWeight(consdata, w, newweight);
8915 ++(*nchgcoefs);
8916 }
8917 else
8918 assert(weights[w] == newweight);
8919 }
8920
8921 /* adjust big sized coefficients, where each of them exceeds the dualcapacity by itself */
8922 ++newweight;
8923 assert(newweight > 2);
8924 for( ; w >= 0; --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 /* update the capacity */
8936 newcap = ((SCIP_Longint)startv - 1) * newweight + ((SCIP_Longint)v - startv) * (newweight - 1) + ((SCIP_Longint)nvars - v);
8937 if( consdata->capacity > newcap )
8938 {
8939 consdata->capacity = newcap;
8940 ++(*nchgsides);
8941 }
8942 else
8943 assert(consdata->capacity == newcap);
8944 }
8945 assert(weights[v] == 1 && (weights[startv] == (SCIP_Longint)nvars - v) && (startv == 0 || weights[0] == (SCIP_Longint)nvars - v + 1));
8946
8947 /* the new dualcapacity should still be equal to the (nvars - v + 1) */
8948 assert(consdata->weightsum - consdata->capacity == (SCIP_Longint)nvars - v + 1);
8949
8950 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8951 * weight must not be sorted by their index
8952 */
8953#ifndef NDEBUG
8954 for( w = nvars - 1; w > 0; --w )
8955 assert(weights[w] <= weights[w - 1]);
8956#endif
8957 return SCIP_OKAY;
8958 }
8959
8960 /* check if all rear items have the same weight as the last one, so we cannot tighten the constraint further */
8961 end = nvars - 2;
8962 while( end >= 0 && weights[end] == weights[end + 1] )
8963 {
8964 assert(end >= v);
8965 --end;
8966 }
8967
8968 if( v >= end )
8969 goto TERMINATE;
8970
8971 end = nvars - 2;
8972
8973 /* can we stop early, another special reduction case might exist */
8974 if( 2 * weights[end] > dualcapacity )
8975 {
8976 restsumweights = 0;
8977
8978 /* determine capacity of the small items */
8979 for( w = end + 1; w < nvars; ++w )
8980 restsumweights += weights[w];
8981
8982 if( restsumweights * 2 <= dualcapacity )
8983 {
8984 /* check for further posssible reductions in the middle */
8985 while( v < end && restsumweights + weights[v] >= dualcapacity )
8986 ++v;
8987
8988 if( v >= end )
8989 goto TERMINATE;
8990
8991 /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
8992 if( (dualcapacity & 1) == 0 )
8993 {
8994 newweight = dualcapacity / 2;
8995
8996 /* set all middle coefficients */
8997 for( ; v <= end; ++v )
8998 {
8999 if( weights[v] > newweight )
9000 {
9001 reductionsum += (weights[v] - newweight);
9002 consdataChgWeight(consdata, v, newweight);
9003 ++(*nchgcoefs);
9004 }
9005 }
9006 }
9007 /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
9008 * other coefficients by 2
9009 */
9010 else
9011 {
9012 /* correct the reductionsum */
9013 reductionsum *= 2;
9014
9015 /* multiply big coefficients by 2 */
9016 for( w = 0; w < v; ++w )
9017 {
9018 consdataChgWeight(consdata, w, weights[w] * 2);
9019 }
9020
9021 newweight = dualcapacity;
9022 /* set all middle coefficients */
9023 for( ; v <= end; ++v )
9024 {
9025 reductionsum += (2 * weights[v] - newweight);
9026 consdataChgWeight(consdata, v, newweight);
9027 }
9028
9029 /* multiply small coefficients by 2 */
9030 for( w = end + 1; w < nvars; ++w )
9031 {
9032 consdataChgWeight(consdata, w, weights[w] * 2);
9033 }
9034 (*nchgcoefs) += nvars;
9035
9036 dualcapacity *= 2;
9037 consdata->capacity *= 2;
9038 ++(*nchgsides);
9039 }
9040 }
9041
9042 goto TERMINATE;
9043 }
9044
9045 /* further reductions using the next possible coefficient sum
9046 *
9047 * e.g. 9x1 + 8x2 + 7x3 + 3x4 + x5 <= 19 <=> 9~x1 + 8~x2 + 7~x3 + 3~x4 + ~x5 >= 9
9048 * <=> 9~x1 + 8~x2 + 6~x3 + 3~x4 + ~x5 >= 9
9049 * <=> 9x1 + 8x2 + 6x3 + 3x4 + x5 <= 18
9050 */
9051 /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
9052 for( k = 0; k < 4; ++k )
9053 {
9054 /* determine next minimal coefficient sum */
9055 switch( k )
9056 {
9057 case 0:
9058 sumcoef = weights[nvars - 1] + weights[nvars - 2];
9059 break;
9060 case 1:
9061 assert(nvars >= 3);
9062 sumcoef = weights[nvars - 1] + weights[nvars - 3];
9063 break;
9064 case 2:
9065 assert(nvars >= 4);
9066 if( weights[nvars - 1] + weights[nvars - 4] < weights[nvars - 2] + weights[nvars - 3] )
9067 {
9068 sumcoefcase = TRUE;
9069 sumcoef = weights[nvars - 1] + weights[nvars - 4];
9070 }
9071 else
9072 {
9073 sumcoefcase = FALSE;
9074 sumcoef = weights[nvars - 2] + weights[nvars - 3];
9075 }
9076 break;
9077 case 3:
9078 assert(nvars >= 5);
9079 if( sumcoefcase )
9080 {
9081 sumcoef = MIN(weights[nvars - 1] + weights[nvars - 5], weights[nvars - 2] + weights[nvars - 3]);
9082 }
9083 else
9084 {
9085 sumcoef = MIN(weights[nvars - 1] + weights[nvars - 4], weights[nvars - 1] + weights[nvars - 2] + weights[nvars - 3]);
9086 }
9087 break;
9088 default:
9089 return SCIP_ERROR;
9090 }
9091
9092 /* tighten next coefficients that, pair with the current small coefficient, exceed the dualcapacity */
9093 minweight = weights[end];
9094 while( minweight <= sumcoef )
9095 {
9096 newweight = dualcapacity - minweight;
9097 startv = v;
9098 assert(v < nvars);
9099
9100 /* @todo check for further reductions, when two times the minweight exceeds the dualcapacity */
9101 /* shrink big coefficients */
9102 while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9103 {
9104 reductionsum += (weights[v] - newweight);
9105 consdataChgWeight(consdata, v, newweight);
9106 ++v;
9107 assert(v < nvars);
9108 }
9109 (*nchgcoefs) += (v - startv);
9110
9111 /* skip unchangable weights */
9112 while( weights[v] + minweight == dualcapacity )
9113 {
9114 assert(v < nvars);
9115 ++v;
9116 }
9117
9118 --end;
9119 /* skip same end weights */
9120 while( end >= 0 && weights[end] == weights[end + 1] )
9121 --end;
9122
9123 if( v >= end )
9124 goto TERMINATE;
9125
9126 minweight = weights[end];
9127 }
9128
9129 if( v >= end )
9130 goto TERMINATE;
9131
9132 /* now check if a combination of small coefficients allows us to tighten big coefficients further */
9133 if( sumcoef < minweight )
9134 {
9135 minweight = sumcoef;
9136 newweight = dualcapacity - minweight;
9137 startv = v;
9138 assert(v < nvars);
9139
9140 /* shrink big coefficients */
9141 while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9142 {
9143 reductionsum += (weights[v] - newweight);
9144 consdataChgWeight(consdata, v, newweight);
9145 ++v;
9146 assert(v < nvars);
9147 }
9148 (*nchgcoefs) += (v - startv);
9149
9150 /* skip unchangable weights */
9151 while( weights[v] + minweight == dualcapacity )
9152 {
9153 assert(v < nvars);
9154 ++v;
9155 }
9156 }
9157
9158 if( v >= end )
9159 goto TERMINATE;
9160
9161 /* can we stop early, another special reduction case might exist */
9162 if( 2 * weights[end] > dualcapacity )
9163 {
9164 restsumweights = 0;
9165
9166 /* determine capacity of the small items */
9167 for( w = end + 1; w < nvars; ++w )
9168 restsumweights += weights[w];
9169
9170 if( restsumweights * 2 <= dualcapacity )
9171 {
9172 /* check for further posssible reductions in the middle */
9173 while( v < end && restsumweights + weights[v] >= dualcapacity )
9174 ++v;
9175
9176 if( v >= end )
9177 goto TERMINATE;
9178
9179 /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
9180 if( (dualcapacity & 1) == 0 )
9181 {
9182 newweight = dualcapacity / 2;
9183
9184 /* set all middle coefficients */
9185 for( ; v <= end; ++v )
9186 {
9187 if( weights[v] > newweight )
9188 {
9189 reductionsum += (weights[v] - newweight);
9190 consdataChgWeight(consdata, v, newweight);
9191 ++(*nchgcoefs);
9192 }
9193 }
9194 }
9195 /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
9196 * other coefficients by 2
9197 */
9198 else
9199 {
9200 /* correct the reductionsum */
9201 reductionsum *= 2;
9202
9203 /* multiply big coefficients by 2 */
9204 for( w = 0; w < v; ++w )
9205 {
9206 consdataChgWeight(consdata, w, weights[w] * 2);
9207 }
9208
9209 newweight = dualcapacity;
9210 /* set all middle coefficients */
9211 for( ; v <= end; ++v )
9212 {
9213 reductionsum += (2 * weights[v] - newweight);
9214 consdataChgWeight(consdata, v, newweight);
9215 }
9216
9217 /* multiply small coefficients by 2 */
9218 for( w = end + 1; w < nvars; ++w )
9219 {
9220 consdataChgWeight(consdata, w, weights[w] * 2);
9221 }
9222 (*nchgcoefs) += nvars;
9223
9224 dualcapacity *= 2;
9225 consdata->capacity *= 2;
9226 ++(*nchgsides);
9227 }
9228 }
9229
9230 goto TERMINATE;
9231 }
9232
9233 /* cannot tighten any further */
9234 if( 2 * sumcoef > dualcapacity )
9235 goto TERMINATE;
9236 }
9237 }
9238 }
9239
9240 TERMINATE:
9241 /* correct capacity */
9242 if( reductionsum > 0 )
9243 {
9244 assert(v > 0);
9245
9246 consdata->capacity -= reductionsum;
9247 ++(*nchgsides);
9248
9249 assert(consdata->weightsum - dualcapacity == consdata->capacity);
9250 }
9251 assert(weights[0] <= consdata->capacity);
9252
9253 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
9254 * weight must not be sorted by their index
9255 */
9256#ifndef NDEBUG
9257 for( w = nvars - 1; w > 0; --w )
9258 assert(weights[w] <= weights[w - 1]);
9259#endif
9260
9261 if( oldnchgcoefs < *nchgcoefs )
9262 {
9263 assert(!SCIPconsIsDeleted(cons));
9264
9265 /* it might be that we can divide the weights by their greatest common divisor */
9266 normalizeWeights(cons, nchgcoefs, nchgsides);
9267 }
9268 else
9269 {
9270 assert(oldnchgcoefs == *nchgcoefs);
9271 assert(oldnchgsides == *nchgsides);
9272 }
9273
9274 return SCIP_OKAY;
9275}
9276
9277
9278/** fixes variables with weights bigger than the capacity and delete redundant constraints, also sort weights */
9279static
9281 SCIP* scip, /**< SCIP data structure */
9282 SCIP_CONS* cons, /**< knapsack constraint */
9283 int* nfixedvars, /**< pointer to store the amount of fixed variables */
9284 int* ndelconss, /**< pointer to store the amount of deleted constraints */
9285 int* nchgcoefs /**< pointer to store the amount of changed coefficients */
9286 )
9287{
9288 SCIP_VAR** vars;
9289 SCIP_CONSDATA* consdata;
9290 SCIP_Longint* weights;
9291 SCIP_Longint capacity;
9292 SCIP_Bool infeasible;
9293 SCIP_Bool fixed;
9294 int nvars;
9295 int v;
9296
9297 assert(scip != NULL);
9298 assert(cons != NULL);
9299 assert(nfixedvars != NULL);
9300 assert(ndelconss != NULL);
9301 assert(nchgcoefs != NULL);
9302
9303 consdata = SCIPconsGetData(cons);
9304 assert(consdata != NULL);
9305
9306 nvars = consdata->nvars;
9307
9308 /* no variables left, then delete constraint */
9309 if( nvars == 0 )
9310 {
9311 assert(consdata->capacity >= 0);
9312
9313 SCIP_CALL( SCIPdelCons(scip, cons) );
9314 ++(*ndelconss);
9315
9316 return SCIP_OKAY;
9317 }
9318
9319 /* sort items */
9320 sortItems(consdata);
9321
9322 vars = consdata->vars;
9323 weights = consdata->weights;
9324 capacity = consdata->capacity;
9325 v = 0;
9326
9327 /* check for weights bigger than the capacity */
9328 while( v < nvars && weights[v] > capacity )
9329 {
9330 SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, &infeasible, &fixed) );
9331 assert(!infeasible);
9332
9333 if( fixed )
9334 ++(*nfixedvars);
9335
9336 ++v;
9337 }
9338
9339 /* if we fixed at least one variable we need to delete them from the constraint */
9340 if( v > 0 )
9341 {
9342 if( v == nvars )
9343 {
9344 SCIP_CALL( SCIPdelCons(scip, cons) );
9345 ++(*ndelconss);
9346
9347 return SCIP_OKAY;
9348 }
9349
9350 /* delete all position from back to front */
9351 for( --v; v >= 0; --v )
9352 {
9353 SCIP_CALL( delCoefPos(scip, cons, v) );
9354 ++(*nchgcoefs);
9355 }
9356
9357 /* sort items again because of deletion */
9358 sortItems(consdata);
9359 assert(vars == consdata->vars);
9360 assert(weights == consdata->weights);
9361 }
9362 assert(consdata->sorted);
9363 assert(weights[0] <= capacity);
9364
9365 if( !SCIPisHugeValue(scip, (SCIP_Real) capacity) && consdata->weightsum <= capacity )
9366 {
9367 SCIP_CALL( SCIPdelCons(scip, cons) );
9368 ++(*ndelconss);
9369 }
9370
9371 return SCIP_OKAY;
9372}
9373
9374
9375/** tries to simplify weights and delete redundant variables in knapsack a^Tx <= capacity
9376 *
9377 * 1. use the duality between a^Tx <= capacity <=> -a^T~x <= capacity - weightsum to tighten weights, e.g.
9378 *
9379 * 11x1 + 10x2 + 7x3 + 5x4 + 5x5 <= 25 <=> -10~x1 - 10~x2 - 7~x3 - 5~x4 - 5~x5 <= -13
9380 *
9381 * the above constraint can be changed to
9382 *
9383 * -8~x1 - 8~x2 - 7~x3 - 5~x4 - 5~x5 <= -12 <=> 8x1 + 8x2 + 7x3 + 5x4 + 5x5 <= 20
9384 *
9385 * 2. if variables in a constraint do not affect the (in-)feasibility of the constraint, we can delete them, e.g.
9386 *
9387 * 7x1 + 6x2 + 5x3 + 5x4 + x5 + x6 <= 20 => x5 and x6 are redundant and can be removed
9388 *
9389 * 3. Tries to use gcd information an all but one weight to change this not-included weight and normalize the
9390 * constraint further, e.g.
9391 *
9392 * 9x1 + 6x2 + 6x3 + 5x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => 3x1 + 2x2 + 2x3 + 2x4 <= 4 => 4x1 + 2x2 + 2x3 + 2x4 <= 4
9393 * => 2x1 + x2 + x3 + x4 <= 2
9394 * 9x1 + 6x2 + 6x3 + 7x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => see above
9395 */
9396static
9398 SCIP* scip, /**< SCIP data structure */
9399 SCIP_CONS* cons, /**< knapsack constraint */
9400 int* nfixedvars, /**< pointer to store the amount of fixed variables */
9401 int* ndelconss, /**< pointer to store the amount of deleted constraints */
9402 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
9403 int* nchgsides, /**< pointer to store the amount of changed sides */
9404 int* naddconss, /**< pointer to count number of added constraints */
9405 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9406 )
9407{
9408 SCIP_VAR** vars;
9409 SCIP_CONSDATA* consdata;
9410 SCIP_Longint* weights;
9411 SCIP_Longint restweight;
9412 SCIP_Longint newweight;
9413 SCIP_Longint weight;
9414 SCIP_Longint oldgcd;
9415 SCIP_Longint rest;
9416 SCIP_Longint gcd;
9417 int oldnchgcoefs;
9418 int oldnchgsides;
9419 int candpos;
9420 int candpos2;
9421 int offsetv;
9422 int nvars;
9423 int v;
9424
9425 assert(scip != NULL);
9426 assert(cons != NULL);
9427 assert(nfixedvars != NULL);
9428 assert(ndelconss != NULL);
9429 assert(nchgcoefs != NULL);
9430 assert(nchgsides != NULL);
9431 assert(naddconss != NULL);
9432 assert(cutoff != NULL);
9433 assert(!SCIPconsIsModifiable(cons));
9434
9435 consdata = SCIPconsGetData(cons);
9436 assert( consdata != NULL );
9437
9438 *cutoff = FALSE;
9439
9440 /* remove double enties and also combinations of active and negated variables */
9441 SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
9442 assert(consdata->merged);
9443 if( *cutoff )
9444 return SCIP_OKAY;
9445
9446 assert(consdata->capacity >= 0);
9447
9448 /* fix variables with big coefficients and remove redundant constraints, sort weights */
9449 SCIP_CALL( prepareCons(scip, cons, nfixedvars, ndelconss, nchgcoefs) );
9450
9451 if( SCIPconsIsDeleted(cons) )
9452 return SCIP_OKAY;
9453
9454 if( !SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
9455 {
9456 /* 1. dual weights tightening */
9457 SCIP_CALL( dualWeightsTightening(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9458
9459 if( SCIPconsIsDeleted(cons) )
9460 return SCIP_OKAY;
9461 /* 2. delete redundant variables */
9462 SCIP_CALL( detectRedundantVars(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9463
9464 if( SCIPconsIsDeleted(cons) )
9465 return SCIP_OKAY;
9466 }
9467
9468 weights = consdata->weights;
9469 nvars = consdata->nvars;
9470
9471#ifndef NDEBUG
9472 /* constraint might not be sorted, but the weights are already sorted */
9473 for( v = nvars - 1; v > 0; --v )
9474 assert(weights[v] <= weights[v-1]);
9475#endif
9476
9477 /* determine greatest common divisor */
9478 gcd = weights[nvars - 1];
9479 for( v = nvars - 2; v >= 0 && gcd > 1; --v )
9480 {
9481 gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9482 }
9483
9484 /* divide the constraint by their greatest common divisor */
9485 if( gcd >= 2 )
9486 {
9487 for( v = nvars - 1; v >= 0; --v )
9488 {
9489 consdataChgWeight(consdata, v, weights[v]/gcd);
9490 }
9491 (*nchgcoefs) += nvars;
9492
9493 consdata->capacity /= gcd;
9494 (*nchgsides)++;
9495 }
9496 assert(consdata->nvars == nvars);
9497
9498 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal weight
9499 * must not be sorted by their index
9500 */
9501#ifndef NDEBUG
9502 for( v = nvars - 1; v > 0; --v )
9503 assert(weights[v] <= weights[v-1]);
9504#endif
9505
9506 /* 3. start gcd procedure for all variables */
9507 do
9508 {
9509 SCIPdebug( oldnchgcoefs = *nchgcoefs; )
9510 SCIPdebug( oldnchgsides = *nchgsides; )
9511
9512 vars = consdata->vars;
9513 weights = consdata->weights;
9514 nvars = consdata->nvars;
9515
9516 /* stop if we have two coefficients which are one in absolute value */
9517 if( weights[nvars - 1] == 1 && weights[nvars - 2] == 1 )
9518 return SCIP_OKAY;
9519
9520 v = 0;
9521 /* determine coefficients as big as the capacity, these we do not need to take into account when calculating the
9522 * gcd
9523 */
9524 while( weights[v] == consdata->capacity )
9525 {
9526 ++v;
9527 assert(v < nvars);
9528 }
9529
9530 /* all but one variable are as big as the capacity, this is handled elsewhere */
9531 if( v == nvars - 1 )
9532 return SCIP_OKAY;
9533
9534 offsetv = v;
9535
9536 gcd = -1;
9537 candpos = -1;
9538 candpos2 = -1;
9539
9540 /* calculate greatest common divisor over all integer and binary variables and determine the candidate where we might
9541 * change the coefficient
9542 */
9543 for( v = nvars - 1; v >= offsetv; --v )
9544 {
9545 weight = weights[v];
9546 assert(weight >= 1);
9547
9548 oldgcd = gcd;
9549
9550 if( gcd == -1 )
9551 {
9552 gcd = weights[v];
9553 assert(gcd >= 1);
9554 }
9555 else
9556 {
9557 /* calculate greatest common divisor for all variables */
9558 gcd = SCIPcalcGreComDiv(gcd, weight);
9559 }
9560
9561 /* if the greatest commmon divisor has become 1, we might have found the possible coefficient to change or we
9562 * can terminate
9563 */
9564 if( gcd == 1 )
9565 {
9566 /* found candidate */
9567 if( candpos == -1 )
9568 {
9569 gcd = oldgcd;
9570 candpos = v;
9571
9572 /* if both first coefficients have a gcd of 1, both are candidates for the coefficient change */
9573 if( v == nvars - 2 )
9574 candpos2 = v + 1;
9575 }
9576 /* two different variables lead to a gcd of one, so we cannot change a coefficient */
9577 else
9578 {
9579 if( candpos == v + 1 && candpos2 == v + 2 )
9580 {
9581 assert(candpos2 == nvars - 1);
9582
9583 /* take new candidates */
9584 candpos = candpos2;
9585
9586 /* recalculate gcd from scratch */
9587 gcd = weights[v+1];
9588 assert(gcd >= 1);
9589
9590 /* calculate greatest common divisor for variables */
9591 gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9592 if( gcd == 1 )
9593 return SCIP_OKAY;
9594 }
9595 else
9596 /* cannot determine a possible coefficient for reduction */
9597 return SCIP_OKAY;
9598 }
9599 }
9600 }
9601 assert(gcd >= 2);
9602
9603 /* we should have found one coefficient, that led to a gcd of 1, otherwise we could normalize the constraint
9604 * further
9605 */
9606 assert(((candpos >= offsetv) || (candpos == -1 && offsetv > 0)) && candpos < nvars);
9607
9608 /* determine the remainder of the capacity and the gcd */
9609 rest = consdata->capacity % gcd;
9610 assert(rest >= 0);
9611 assert(rest < gcd);
9612
9613 if( candpos == -1 )
9614 {
9615 /* we assume that the constraint was normalized */
9616 assert(rest > 0);
9617
9618 /* replace old with new capacity */
9619 consdata->capacity -= rest;
9620 ++(*nchgsides);
9621
9622 /* replace old big coefficients with new capacity */
9623 for( v = 0; v < offsetv; ++v )
9624 {
9625 consdataChgWeight(consdata, v, consdata->capacity);
9626 }
9627
9628 *nchgcoefs += offsetv;
9629 goto CONTINUE;
9630 }
9631
9632 /* determine the remainder of the coefficient candidate and the gcd */
9633 restweight = weights[candpos] % gcd;
9634 assert(restweight >= 1);
9635 assert(restweight < gcd);
9636
9637 /* calculate new coefficient */
9638 if( restweight > rest )
9639 newweight = weights[candpos] - restweight + gcd;
9640 else
9641 newweight = weights[candpos] - restweight;
9642
9643 assert(newweight == 0 || SCIPcalcGreComDiv(gcd, newweight) == gcd);
9644
9645 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);
9646
9647 /* must not change weights and capacity if one variable would be removed and we have a big coefficient,
9648 * e.g., 11x1 + 6x2 + 6x3 + 5x4 <= 11 => gcd = 6, offsetv = 1 => newweight = 0, but we would lose x1 = 1 => x4 = 0
9649 */
9650 if( newweight == 0 && offsetv > 0 )
9651 return SCIP_OKAY;
9652
9653 if( rest > 0 )
9654 {
9655 /* replace old with new capacity */
9656 consdata->capacity -= rest;
9657 ++(*nchgsides);
9658
9659 /* replace old big coefficients with new capacity */
9660 for( v = 0; v < offsetv; ++v )
9661 {
9662 consdataChgWeight(consdata, v, consdata->capacity);
9663 }
9664
9665 *nchgcoefs += offsetv;
9666 }
9667
9668 if( newweight == 0 )
9669 {
9670 /* delete redundant coefficient */
9671 SCIP_CALL( delCoefPos(scip, cons, candpos) );
9672 assert(consdata->nvars == nvars - 1);
9673 --nvars;
9674 }
9675 else
9676 {
9677 /* replace old with new coefficient */
9678 consdataChgWeight(consdata, candpos, newweight);
9679 }
9680 ++(*nchgcoefs);
9681
9682 assert(consdata->vars == vars);
9683 assert(consdata->nvars == nvars);
9684 assert(consdata->weights == weights);
9685
9686 CONTINUE:
9687 /* now constraint can be normalized, dividing it by the gcd */
9688 for( v = nvars - 1; v >= 0; --v )
9689 {
9690 consdataChgWeight(consdata, v, weights[v]/gcd);
9691 }
9692 (*nchgcoefs) += nvars;
9693
9694 consdata->capacity /= gcd;
9695 ++(*nchgsides);
9696
9698
9699 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));
9700 }
9701 while( nvars >= 2 );
9702
9703 return SCIP_OKAY;
9704}
9705
9706
9707/** inserts an element into the list of binary zero implications */
9708static
9710 SCIP* scip, /**< SCIP data structure */
9711 int** liftcands, /**< array of the lifting candidates */
9712 int* nliftcands, /**< number of lifting candidates */
9713 int** firstidxs, /**< array of first zeroitems indices */
9714 SCIP_Longint** zeroweightsums, /**< array of sums of weights of the implied-to-zero items */
9715 int** zeroitems, /**< pointer to zero items array */
9716 int** nextidxs, /**< pointer to array of next zeroitems indeces */
9717 int* zeroitemssize, /**< pointer to size of zero items array */
9718 int* nzeroitems, /**< pointer to length of zero items array */
9719 int probindex, /**< problem index of variable y in implication y == v -> x == 0 */
9720 SCIP_Bool value, /**< value v of variable y in implication */
9721 int knapsackidx, /**< index of variable x in knapsack */
9722 SCIP_Longint knapsackweight, /**< weight of variable x in knapsack */
9723 SCIP_Bool* memlimitreached /**< pointer to store whether the memory limit was reached */
9724 )
9725{
9726 int nzeros;
9727
9728 assert(liftcands != NULL);
9729 assert(liftcands[value] != NULL);
9730 assert(nliftcands != NULL);
9731 assert(firstidxs != NULL);
9732 assert(firstidxs[value] != NULL);
9733 assert(zeroweightsums != NULL);
9734 assert(zeroweightsums[value] != NULL);
9735 assert(zeroitems != NULL);
9736 assert(nextidxs != NULL);
9737 assert(zeroitemssize != NULL);
9738 assert(nzeroitems != NULL);
9739 assert(*nzeroitems <= *zeroitemssize);
9740 assert(0 <= probindex && probindex < SCIPgetNVars(scip) - SCIPgetNContVars(scip));
9741 assert(memlimitreached != NULL);
9742
9743 nzeros = *nzeroitems;
9744
9745 /* allocate enough memory */
9746 if( nzeros == *zeroitemssize )
9747 {
9748 /* we explicitly construct the complete implication graph where the knapsack variables are involved;
9749 * this can be too huge - abort on memory limit
9750 */
9751 if( *zeroitemssize >= MAX_ZEROITEMS_SIZE )
9752 {
9753 SCIPdebugMsg(scip, "memory limit of %d bytes reached in knapsack preprocessing - abort collecting zero items\n",
9754 *zeroitemssize);
9755 *memlimitreached = TRUE;
9756 return SCIP_OKAY;
9757 }
9758 *zeroitemssize *= 2;
9759 *zeroitemssize = MIN(*zeroitemssize, MAX_ZEROITEMS_SIZE);
9760 SCIP_CALL( SCIPreallocBufferArray(scip, zeroitems, *zeroitemssize) );
9761 SCIP_CALL( SCIPreallocBufferArray(scip, nextidxs, *zeroitemssize) );
9762 }
9763 assert(nzeros < *zeroitemssize);
9764
9765 if( *memlimitreached )
9766 *memlimitreached = FALSE;
9767
9768 /* insert element */
9769 (*zeroitems)[nzeros] = knapsackidx;
9770 (*nextidxs)[nzeros] = firstidxs[value][probindex];
9771 if( firstidxs[value][probindex] == 0 )
9772 {
9773 liftcands[value][nliftcands[value]] = probindex;
9774 ++nliftcands[value];
9775 }
9776 firstidxs[value][probindex] = nzeros;
9777 ++(*nzeroitems);
9778 zeroweightsums[value][probindex] += knapsackweight;
9779
9780 return SCIP_OKAY;
9781}
9782
9783#define MAX_CLIQUELENGTH 50
9784/** applies rule (3) of the weight tightening procedure, which can lift other variables into the knapsack:
9785 * (3) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
9786 * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
9787 * if cliqueweightsum(xi == v) < capacity:
9788 * - fixing variable xi to v would make the knapsack constraint redundant
9789 * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
9790 * redundancy effect:
9791 * wi' := capacity - cliqueweightsum(xi == v)
9792 * this rule can also be applied to binary variables not in the knapsack!
9793 */
9794static
9796 SCIP* scip, /**< SCIP data structure */
9797 SCIP_CONS* cons, /**< knapsack constraint */
9798 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9799 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9800 )
9801{
9802 SCIP_CONSDATA* consdata;
9803 SCIP_VAR** binvars;
9804 int nbinvars;
9805 int* liftcands[2]; /* binary variables that have at least one entry in zeroitems */
9806 int* firstidxs[2]; /* first index in zeroitems for each binary variable/value pair, or zero for empty list */
9807 SCIP_Longint* zeroweightsums[2]; /* sums of weights of the implied-to-zero items */
9808 int* zeroitems; /* item number in knapsack that is implied to zero */
9809 int* nextidxs; /* next index in zeroitems for the same binary variable, or zero for end of list */
9810 int zeroitemssize;
9811 int nzeroitems;
9812 SCIP_Bool* zeroiteminserted[2];
9813 SCIP_Bool memlimitreached;
9814 int nliftcands[2];
9815 SCIP_Bool* cliqueused;
9816 SCIP_Bool* itemremoved;
9817 SCIP_Longint maxcliqueweightsum;
9818 SCIP_VAR** addvars;
9819 SCIP_Longint* addweights;
9820 SCIP_Longint addweightsum;
9821 int nvars;
9822 int cliquenum;
9823 int naddvars;
9824 int val;
9825 int i;
9826
9827 int* tmpindices;
9828 SCIP_Bool* tmpboolindices;
9829 int* tmpindices2;
9830 SCIP_Bool* tmpboolindices2;
9831 int* tmpindices3;
9832 SCIP_Bool* tmpboolindices3;
9833 int tmp;
9834 int tmp2;
9835 int tmp3;
9836 SCIP_CONSHDLR* conshdlr;
9837 SCIP_CONSHDLRDATA* conshdlrdata;
9838
9839 assert(nchgcoefs != NULL);
9840 assert(!SCIPconsIsModifiable(cons));
9841
9842 consdata = SCIPconsGetData(cons);
9843 assert(consdata != NULL);
9844 assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
9845 assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
9846 assert(consdata->nvars > 0);
9847 assert(consdata->merged);
9848
9849 nvars = consdata->nvars;
9850
9851 /* check if the knapsack has too many items/cliques for applying this costly method */
9852 if( (!consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE) || consdata->ncliques > MAX_USECLIQUES_SIZE )
9853 return SCIP_OKAY;
9854
9855 /* sort items, s.t. the heaviest one is in the first position */
9856 sortItems(consdata);
9857
9858 if( !consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE )
9859 return SCIP_OKAY;
9860
9861 /* we have to consider all integral variables since even integer and implicit integer variables can have binary bounds */
9862 nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
9863 assert(nbinvars > 0);
9864 binvars = SCIPgetVars(scip);
9865
9866 /* get conshdlrdata to use cleared memory */
9867 conshdlr = SCIPconsGetHdlr(cons);
9868 assert(conshdlr != NULL);
9869 conshdlrdata = SCIPconshdlrGetData(conshdlr);
9870 assert(conshdlrdata != NULL);
9871
9872 /* allocate temporary memory for the list of implied to zero variables */
9873 zeroitemssize = MIN(nbinvars, MAX_ZEROITEMS_SIZE); /* initial size of zeroitems buffer */
9874 SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[0], nbinvars) );
9875 SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[1], nbinvars) );
9876
9877 assert(conshdlrdata->ints1size > 0);
9878 assert(conshdlrdata->ints2size > 0);
9879 assert(conshdlrdata->longints1size > 0);
9880 assert(conshdlrdata->longints2size > 0);
9881
9882 /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9883 * than binary + integer variables existed at the presolving initialization method, but for example if you would
9884 * transform all integers into their binary representation then it maybe happens
9885 */
9886 if( conshdlrdata->ints1size < nbinvars )
9887 {
9888 int oldsize = conshdlrdata->ints1size;
9889
9890 conshdlrdata->ints1size = nbinvars;
9891 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints1, oldsize, conshdlrdata->ints1size) );
9892 BMSclearMemoryArray(&(conshdlrdata->ints1[oldsize]), conshdlrdata->ints1size - oldsize); /*lint !e866*/
9893 }
9894 if( conshdlrdata->ints2size < nbinvars )
9895 {
9896 int oldsize = conshdlrdata->ints2size;
9897
9898 conshdlrdata->ints2size = nbinvars;
9899 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints2, oldsize, conshdlrdata->ints2size) );
9900 BMSclearMemoryArray(&(conshdlrdata->ints2[oldsize]), conshdlrdata->ints2size - oldsize); /*lint !e866*/
9901 }
9902 if( conshdlrdata->longints1size < nbinvars )
9903 {
9904 int oldsize = conshdlrdata->longints1size;
9905
9906 conshdlrdata->longints1size = nbinvars;
9907 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints1, oldsize, conshdlrdata->longints1size) );
9908 BMSclearMemoryArray(&(conshdlrdata->longints1[oldsize]), conshdlrdata->longints1size - oldsize); /*lint !e866*/
9909 }
9910 if( conshdlrdata->longints2size < nbinvars )
9911 {
9912 int oldsize = conshdlrdata->longints2size;
9913
9914 conshdlrdata->longints2size = nbinvars;
9915 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints2, oldsize, conshdlrdata->longints2size) );
9916 BMSclearMemoryArray(&(conshdlrdata->longints2[oldsize]), conshdlrdata->longints2size - oldsize); /*lint !e866*/
9917 }
9918
9919 firstidxs[0] = conshdlrdata->ints1;
9920 firstidxs[1] = conshdlrdata->ints2;
9921 zeroweightsums[0] = conshdlrdata->longints1;
9922 zeroweightsums[1] = conshdlrdata->longints2;
9923
9924 /* check for cleared arrays, all entries are zero */
9925#ifndef NDEBUG
9926 for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9927 {
9928 assert(firstidxs[0][tmp] == 0);
9929 assert(firstidxs[1][tmp] == 0);
9930 assert(zeroweightsums[0][tmp] == 0);
9931 assert(zeroweightsums[1][tmp] == 0);
9932 }
9933#endif
9934
9935 SCIP_CALL( SCIPallocBufferArray(scip, &zeroitems, zeroitemssize) );
9936 SCIP_CALL( SCIPallocBufferArray(scip, &nextidxs, zeroitemssize) );
9937
9938 zeroitems[0] = -1; /* dummy element */
9939 nextidxs[0] = -1;
9940 nzeroitems = 1;
9941 nliftcands[0] = 0;
9942 nliftcands[1] = 0;
9943
9944 assert(conshdlrdata->bools1size > 0);
9945 assert(conshdlrdata->bools2size > 0);
9946
9947 /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9948 * than binary + integer variables existed at the presolving initialization method, but for example if you would
9949 * transform all integers into their binary representation then it maybe happens
9950 */
9951 if( conshdlrdata->bools1size < nbinvars )
9952 {
9953 int oldsize = conshdlrdata->bools1size;
9954
9955 conshdlrdata->bools1size = nbinvars;
9956 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools1, oldsize, conshdlrdata->bools1size) );
9957 BMSclearMemoryArray(&(conshdlrdata->bools1[oldsize]), conshdlrdata->bools1size - oldsize); /*lint !e866*/
9958 }
9959 if( conshdlrdata->bools2size < nbinvars )
9960 {
9961 int oldsize = conshdlrdata->bools2size;
9962
9963 conshdlrdata->bools2size = nbinvars;
9964 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools2, oldsize, conshdlrdata->bools2size) );
9965 BMSclearMemoryArray(&(conshdlrdata->bools2[oldsize]), conshdlrdata->bools2size - oldsize); /*lint !e866*/
9966 }
9967
9968 zeroiteminserted[0] = conshdlrdata->bools1;
9969 zeroiteminserted[1] = conshdlrdata->bools2;
9970
9971 /* check for cleared arrays, all entries are zero */
9972#ifndef NDEBUG
9973 for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9974 {
9975 assert(zeroiteminserted[0][tmp] == 0);
9976 assert(zeroiteminserted[1][tmp] == 0);
9977 }
9978#endif
9979
9980 SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices3, consdata->nvars) );
9981 SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices2, 2 * nbinvars) );
9982 SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices3, consdata->nvars) );
9983 SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices2, 2 * nbinvars) );
9984 SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, 2 * nbinvars) );
9985 SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices, 2 * nbinvars) );
9986
9987 tmp2 = 0;
9988 tmp3 = 0;
9989
9990 memlimitreached = FALSE;
9991 for( i = 0; i < consdata->nvars && !memlimitreached; ++i )
9992 {
9993 SCIP_CLIQUE** cliques;
9994 SCIP_VAR* var;
9995 SCIP_Longint weight;
9996 SCIP_Bool value;
9997 int varprobindex;
9998 int ncliques;
9999 int j;
10000
10001 tmp = 0;
10002
10003 /* get corresponding active problem variable */
10004 var = consdata->vars[i];
10005 weight = consdata->weights[i];
10006 value = TRUE;
10007 SCIP_CALL( SCIPvarGetProbvarBinary(&var, &value) );
10008 varprobindex = SCIPvarGetProbindex(var);
10009 assert(0 <= varprobindex && varprobindex < nbinvars);
10010
10011 /* update the zeroweightsum */
10012 zeroweightsums[!value][varprobindex] += weight; /*lint !e514*/
10013 tmpboolindices3[tmp3] = !value;
10014 tmpindices3[tmp3] = varprobindex;
10015 ++tmp3;
10016
10017 /* initialize the arrays of inserted zero items */
10018 /* first add the implications (~x == 1 -> x == 0) */
10019 {
10020 SCIP_Bool implvalue;
10021 int probindex;
10022
10023 probindex = SCIPvarGetProbindex(var);
10024 assert(0 <= probindex && probindex < nbinvars);
10025
10026 implvalue = !value;
10027
10028 /* insert the item into the list of the implied variable/value */
10029 assert( !zeroiteminserted[implvalue][probindex] );
10030
10031 if( firstidxs[implvalue][probindex] == 0 )
10032 {
10033 tmpboolindices2[tmp2] = implvalue;
10034 tmpindices2[tmp2] = probindex;
10035 ++tmp2;
10036 }
10037 SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
10038 &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
10039 &memlimitreached) );
10040 zeroiteminserted[implvalue][probindex] = TRUE;
10041 tmpboolindices[tmp] = implvalue;
10042 tmpindices[tmp] = probindex;
10043 ++tmp;
10044 }
10045
10046 /* get the cliques where the knapsack item is member of with value 1 */
10047 ncliques = SCIPvarGetNCliques(var, value);
10048 cliques = SCIPvarGetCliques(var, value);
10049 for( j = 0; j < ncliques && !memlimitreached; ++j )
10050 {
10051 SCIP_VAR** cliquevars;
10052 SCIP_Bool* cliquevalues;
10053 int ncliquevars;
10054 int k;
10055
10056 ncliquevars = SCIPcliqueGetNVars(cliques[j]);
10057
10058 /* discard big cliques */
10059 if( ncliquevars > MAX_CLIQUELENGTH )
10060 continue;
10061
10062 cliquevars = SCIPcliqueGetVars(cliques[j]);
10063 cliquevalues = SCIPcliqueGetValues(cliques[j]);
10064
10065 for( k = ncliquevars - 1; k >= 0; --k )
10066 {
10067 SCIP_Bool implvalue;
10068 int probindex;
10069
10070 if( var == cliquevars[k] )
10071 continue;
10072
10073 probindex = SCIPvarGetProbindex(cliquevars[k]);
10074 if( probindex == -1 )
10075 continue;
10076
10077 assert(0 <= probindex && probindex < nbinvars);
10078 implvalue = cliquevalues[k];
10079
10080 /* insert the item into the list of the clique variable/value */
10081 if( !zeroiteminserted[implvalue][probindex] )
10082 {
10083 if( firstidxs[implvalue][probindex] == 0 )
10084 {
10085 tmpboolindices2[tmp2] = implvalue;
10086 tmpindices2[tmp2] = probindex;
10087 ++tmp2;
10088 }
10089
10090 SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
10091 &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
10092 &memlimitreached) );
10093 zeroiteminserted[implvalue][probindex] = TRUE;
10094 tmpboolindices[tmp] = implvalue;
10095 tmpindices[tmp] = probindex;
10096 ++tmp;
10097
10098 if( memlimitreached )
10099 break;
10100 }
10101 }
10102 }
10103 /* clear zeroiteminserted */
10104 for( --tmp; tmp >= 0; --tmp)
10105 zeroiteminserted[tmpboolindices[tmp]][tmpindices[tmp]] = FALSE;
10106 }
10107 SCIPfreeBufferArray(scip, &tmpboolindices);
10108
10109 /* calculate the clique partition and the maximal sum of weights using the clique information */
10110 assert(consdata->sorted);
10111 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10112
10113 assert(conshdlrdata->bools3size > 0);
10114
10115 /* next if condition should normally not be true, because it means that presolving has created more binary variables
10116 * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10117 * method, but for example if you would transform all integers into their binary representation then it maybe happens
10118 */
10119 if( conshdlrdata->bools3size < consdata->nvars )
10120 {
10121 int oldsize = conshdlrdata->bools3size;
10122
10123 conshdlrdata->bools3size = consdata->nvars;;
10124 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools3, oldsize, conshdlrdata->bools3size) );
10125 BMSclearMemoryArray(&(conshdlrdata->bools3[oldsize]), conshdlrdata->bools3size - oldsize); /*lint !e866*/
10126 }
10127
10128 cliqueused = conshdlrdata->bools3;
10129
10130 /* check for cleared array, all entries are zero */
10131#ifndef NDEBUG
10132 for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10133 assert(cliqueused[tmp] == 0);
10134#endif
10135
10136 maxcliqueweightsum = 0;
10137 tmp = 0;
10138
10139 /* calculates maximal weight of cliques */
10140 for( i = 0; i < consdata->nvars; ++i )
10141 {
10142 cliquenum = consdata->cliquepartition[i];
10143 assert(0 <= cliquenum && cliquenum < consdata->nvars);
10144
10145 if( !cliqueused[cliquenum] )
10146 {
10147 maxcliqueweightsum += consdata->weights[i];
10148 cliqueused[cliquenum] = TRUE;
10149 tmpindices[tmp] = cliquenum;
10150 ++tmp;
10151 }
10152 }
10153 /* clear cliqueused */
10154 for( --tmp; tmp >= 0; --tmp)
10155 cliqueused[tmp] = FALSE;
10156
10157 assert(conshdlrdata->bools4size > 0);
10158
10159 /* next if condition should normally not be true, because it means that presolving has created more binary variables
10160 * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10161 * method, but for example if you would transform all integers into their binary representation then it maybe happens
10162 */
10163 if( conshdlrdata->bools4size < consdata->nvars )
10164 {
10165 int oldsize = conshdlrdata->bools4size;
10166
10167 conshdlrdata->bools4size = consdata->nvars;
10168 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools4, oldsize, conshdlrdata->bools4size) );
10169 BMSclearMemoryArray(&conshdlrdata->bools4[oldsize], conshdlrdata->bools4size - oldsize); /*lint !e866*/
10170 }
10171
10172 itemremoved = conshdlrdata->bools4;
10173
10174 /* check for cleared array, all entries are zero */
10175#ifndef NDEBUG
10176 for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10177 assert(itemremoved[tmp] == 0);
10178#endif
10179
10180 /* for each binary variable xi and each fixing v, calculate the cliqueweightsum and update the weight of the
10181 * variable in the knapsack (this is sequence-dependent because the new or modified weights have to be
10182 * included in subsequent cliqueweightsum calculations)
10183 */
10184 SCIP_CALL( SCIPallocBufferArray(scip, &addvars, 2*nbinvars) );
10185 SCIP_CALL( SCIPallocBufferArray(scip, &addweights, 2*nbinvars) );
10186 naddvars = 0;
10187 addweightsum = 0;
10188 for( val = 0; val < 2 && addweightsum < consdata->capacity; ++val )
10189 {
10190 for( i = 0; i < nliftcands[val] && addweightsum < consdata->capacity; ++i )
10191 {
10192 SCIP_Longint cliqueweightsum;
10193 int probindex;
10194 int idx;
10195 int j;
10196
10197 tmp = 0;
10198
10199 probindex = liftcands[val][i];
10200 assert(0 <= probindex && probindex < nbinvars);
10201
10202 /* ignore empty zero lists and variables that cannot be lifted anyways */
10203 if( firstidxs[val][probindex] == 0
10204 || maxcliqueweightsum - zeroweightsums[val][probindex] + addweightsum >= consdata->capacity )
10205 continue;
10206
10207 /* mark the items that are implied to zero by setting the current variable to the current value */
10208 for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10209 {
10210 assert(0 < idx && idx < nzeroitems);
10211 assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10212 itemremoved[zeroitems[idx]] = TRUE;
10213 }
10214
10215 /* calculate the residual cliqueweight sum */
10216 cliqueweightsum = addweightsum; /* the previously added items are single-element cliques */
10217 for( j = 0; j < consdata->nvars; ++j )
10218 {
10219 cliquenum = consdata->cliquepartition[j];
10220 assert(0 <= cliquenum && cliquenum < consdata->nvars);
10221 if( !itemremoved[j] )
10222 {
10223 if( !cliqueused[cliquenum] )
10224 {
10225 cliqueweightsum += consdata->weights[j];
10226 cliqueused[cliquenum] = TRUE;
10227 tmpindices[tmp] = cliquenum;
10228 ++tmp;
10229 }
10230
10231 if( cliqueweightsum >= consdata->capacity )
10232 break;
10233 }
10234 }
10235
10236 /* check if the weight of the variable/value can be increased */
10237 if( cliqueweightsum < consdata->capacity )
10238 {
10239 SCIP_VAR* var;
10240 SCIP_Longint weight;
10241
10242 /* insert the variable (with value TRUE) in the list of additional items */
10243 assert(naddvars < 2*nbinvars);
10244 var = binvars[probindex];
10245 if( val == FALSE )
10246 {
10247 SCIP_CALL( SCIPgetNegatedVar(scip, var, &var) );
10248 }
10249 weight = consdata->capacity - cliqueweightsum;
10250 addvars[naddvars] = var;
10251 addweights[naddvars] = weight;
10252 addweightsum += weight;
10253 naddvars++;
10254
10255 SCIPdebugMsg(scip, "knapsack constraint <%s>: adding lifted item %" SCIP_LONGINT_FORMAT "<%s>\n",
10256 SCIPconsGetName(cons), weight, SCIPvarGetName(var));
10257 }
10258
10259 /* clear itemremoved */
10260 for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10261 {
10262 assert(0 < idx && idx < nzeroitems);
10263 assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10264 itemremoved[zeroitems[idx]] = FALSE;
10265 }
10266 /* clear cliqueused */
10267 for( --tmp; tmp >= 0; --tmp)
10268 cliqueused[tmpindices[tmp]] = FALSE;
10269 }
10270 }
10271
10272 /* clear part of zeroweightsums */
10273 for( --tmp3; tmp3 >= 0; --tmp3)
10274 zeroweightsums[tmpboolindices3[tmp3]][tmpindices3[tmp3]] = 0;
10275
10276 /* clear rest of zeroweightsums and firstidxs */
10277 for( --tmp2; tmp2 >= 0; --tmp2)
10278 {
10279 zeroweightsums[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10280 firstidxs[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10281 }
10282
10283 /* add all additional item weights */
10284 for( i = 0; i < naddvars; ++i )
10285 {
10286 SCIP_CALL( addCoef(scip, cons, addvars[i], addweights[i]) );
10287 }
10288 *nchgcoefs += naddvars;
10289
10290 if( naddvars > 0 )
10291 {
10292 /* if new items were added, multiple entries of the same variable are possible and we have to clean up the constraint */
10293 SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10294 }
10295
10296 /* free temporary memory */
10297 SCIPfreeBufferArray(scip, &addweights);
10298 SCIPfreeBufferArray(scip, &addvars);
10299 SCIPfreeBufferArray(scip, &tmpindices);
10300 SCIPfreeBufferArray(scip, &tmpindices2);
10301 SCIPfreeBufferArray(scip, &tmpindices3);
10302 SCIPfreeBufferArray(scip, &tmpboolindices2);
10303 SCIPfreeBufferArray(scip, &tmpboolindices3);
10304 SCIPfreeBufferArray(scip, &nextidxs);
10305 SCIPfreeBufferArray(scip, &zeroitems);
10306 SCIPfreeBufferArray(scip, &liftcands[1]);
10307 SCIPfreeBufferArray(scip, &liftcands[0]);
10308
10309 return SCIP_OKAY;
10310}
10311
10312/** tightens item weights and capacity in presolving:
10313 * given a knapsack sum(wi*xi) <= capacity
10314 * (1) let weightsum := sum(wi)
10315 * if weightsum - wi < capacity:
10316 * - not using item i would make the knapsack constraint redundant
10317 * - wi and capacity can be changed to have the same redundancy effect and the same results for
10318 * fixing xi to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10319 * - change coefficients:
10320 * wi' := weightsum - capacity
10321 * capacity' := capacity - (wi - wi')
10322 * (2) increase weights from front to back(sortation is necessary) if there is no space left for another weight
10323 * - determine the four(can be adjusted) minimal weightsums of the knapsack, i.e. in increasing order
10324 * weights[nvars - 1], weights[nvars - 2], MIN(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]),
10325 * MIN(MAX(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]), weights[nvars - 4]), note that there
10326 * can be multiple times the same weight, this can be improved
10327 * - check if summing up a minimal weightsum with a big weight exceeds the capacity, then we can increase the big
10328 * weight, to capacity - lastmininmalweightsum, e.g. :
10329 * 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19
10330 * -> minimal weightsums: 5, 5, 10, 10
10331 * -> 15 + 5 > 19 => increase 15 to 19 - 0 = 19
10332 * -> 10 + 10 > 19 => increase 10 to 19 - 5 = 14, resulting in
10333 * 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10334 * (3) let W(C) be the maximal weight of clique C,
10335 * cliqueweightsum := sum(W(C))
10336 * if cliqueweightsum - W(C) < capacity:
10337 * - not using any item of C would make the knapsack constraint redundant
10338 * - weights wi, i in C, and capacity can be changed to have the same redundancy effect and the same results for
10339 * fixing xi, i in C, to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10340 * - change coefficients:
10341 * delta := capacity - (cliqueweightsum - W(C))
10342 * wi' := max(wi - delta, 0)
10343 * capacity' := capacity - delta
10344 * This rule has to add the used cliques in order to ensure they are enforced - otherwise, the reduction might
10345 * introduce infeasible solutions.
10346 * (4) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
10347 * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
10348 * if cliqueweightsum(xi == v) < capacity:
10349 * - fixing variable xi to v would make the knapsack constraint redundant
10350 * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
10351 * redundancy effect:
10352 * wi' := capacity - cliqueweightsum(xi == v)
10353 * This rule can also be applied to binary variables not in the knapsack!
10354 * (5) if min{w} + wi > capacity:
10355 * - using item i would force to fix other items to zero
10356 * - wi can be increased to the capacity
10357 */
10358static
10360 SCIP* scip, /**< SCIP data structure */
10361 SCIP_CONS* cons, /**< knapsack constraint */
10362 SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
10363 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10364 int* nchgsides, /**< pointer to count number of side changes */
10365 int* naddconss, /**< pointer to count number of added constraints */
10366 int* ndelconss, /**< pointer to count number of deleted constraints */
10367 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
10368 )
10369{
10370 SCIP_CONSHDLRDATA* conshdlrdata;
10371 SCIP_CONSDATA* consdata;
10372 SCIP_Longint* weights;
10373 SCIP_Longint sumcoef;
10374 SCIP_Longint capacity;
10375 SCIP_Longint newweight;
10376 SCIP_Longint maxweight;
10377 SCIP_Longint minweight;
10378 SCIP_Bool sumcoefcase = FALSE;
10379 int startpos;
10380 int backpos;
10381 int nvars;
10382 int pos;
10383 int k;
10384 int i;
10385
10386 assert(nchgcoefs != NULL);
10387 assert(nchgsides != NULL);
10388 assert(!SCIPconsIsModifiable(cons));
10389
10390 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
10391 assert(conshdlrdata != NULL);
10392
10393 consdata = SCIPconsGetData(cons);
10394 assert(consdata != NULL);
10395 assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
10396 assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
10397 assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
10398 assert(consdata->nvars > 0);
10399
10400 SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10401 if( *cutoff )
10402 return SCIP_OKAY;
10403
10404 /* apply rule (1) */
10405 if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10406 {
10407 do
10408 {
10409 assert(consdata->merged);
10410
10411 /* sort items, s.t. the heaviest one is in the first position */
10412 sortItems(consdata);
10413
10414 for( i = 0; i < consdata->nvars; ++i )
10415 {
10416 SCIP_Longint weight;
10417
10418 weight = consdata->weights[i];
10419 if( consdata->weightsum - weight < consdata->capacity )
10420 {
10421 newweight = consdata->weightsum - consdata->capacity;
10422 consdataChgWeight(consdata, i, newweight);
10423 consdata->capacity -= (weight - newweight);
10424 (*nchgcoefs)++;
10425 (*nchgsides)++;
10426 assert(!consdata->sorted);
10427 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",
10428 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, newweight,
10429 consdata->capacity + (weight-newweight), consdata->capacity);
10430 }
10431 else
10432 break;
10433 }
10434 }
10435 while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10436 }
10437
10438 /* check for redundancy */
10439 if( consdata->weightsum <= consdata->capacity )
10440 return SCIP_OKAY;
10441
10442 pos = 0;
10443 while( pos < consdata->nvars && consdata->weights[pos] == consdata->capacity )
10444 ++pos;
10445
10446 sumcoef = 0;
10447 weights = consdata->weights;
10448 nvars = consdata->nvars;
10449 capacity = consdata->capacity;
10450
10451 if( (presoltiming & (SCIP_PRESOLTIMING_FAST | SCIP_PRESOLTIMING_MEDIUM)) != 0 &&
10452 pos < nvars && weights[pos] + weights[pos + 1] > capacity )
10453 {
10454 /* further reductions using the next possible coefficient sum
10455 *
10456 * e.g. 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19 <=> 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10457 */
10458 /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
10459 for( k = 0; k < 4; ++k )
10460 {
10461 newweight = capacity - sumcoef;
10462
10463 /* determine next minimal coefficient sum */
10464 switch( k )
10465 {
10466 case 0:
10467 sumcoef = weights[nvars - 1];
10468 backpos = nvars - 1;
10469 break;
10470 case 1:
10471 sumcoef = weights[nvars - 2];
10472 backpos = nvars - 2;
10473 break;
10474 case 2:
10475 if( weights[nvars - 3] < weights[nvars - 1] + weights[nvars - 2] )
10476 {
10477 sumcoefcase = TRUE;
10478 sumcoef = weights[nvars - 3];
10479 backpos = nvars - 3;
10480 }
10481 else
10482 {
10483 sumcoefcase = FALSE;
10484 sumcoef = weights[nvars - 1] + weights[nvars - 2];
10485 backpos = nvars - 2;
10486 }
10487 break;
10488 default:
10489 assert(k == 3);
10490 if( sumcoefcase )
10491 {
10492 if( weights[nvars - 4] < weights[nvars - 1] + weights[nvars - 2] )
10493 {
10494 sumcoef = weights[nvars - 4];
10495 backpos = nvars - 4;
10496 }
10497 else
10498 {
10499 sumcoef = weights[nvars - 1] + weights[nvars - 2];
10500 backpos = nvars - 2;
10501 }
10502 }
10503 else
10504 {
10505 sumcoef = weights[nvars - 3];
10506 backpos = nvars - 3;
10507 }
10508 break;
10509 }
10510
10511 if( backpos <= pos )
10512 break;
10513
10514 /* tighten next coefficients that, paired with the current small coefficient, exceed the capacity */
10515 maxweight = weights[pos];
10516 startpos = pos;
10517 while( 2 * maxweight > capacity && maxweight + sumcoef > capacity )
10518 {
10519 assert(newweight > weights[pos]);
10520
10521 SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10522 SCIPconsGetName(cons), maxweight, newweight);
10523
10524 consdataChgWeight(consdata, pos, newweight);
10525
10526 ++pos;
10527 assert(pos < nvars);
10528
10529 maxweight = weights[pos];
10530
10531 if( backpos <= pos )
10532 break;
10533 }
10534 (*nchgcoefs) += (pos - startpos);
10535
10536 /* skip unchangable weights */
10537 while( pos < nvars && weights[pos] + sumcoef == capacity )
10538 ++pos;
10539
10540 /* check special case were there is only one weight left to tighten
10541 *
10542 * e.g. 95x1 + 59x2 + 37x3 + 36x4 <= 95 (37 > 36)
10543 *
10544 * => 95x1 + 59x2 + 59x3 + 36x4 <= 95
10545 *
10546 * 197x1 + 120x2 + 77x3 + 10x4 <= 207 (here we cannot tighten the coefficient further)
10547 */
10548 if( pos + 1 == backpos && weights[pos] > sumcoef &&
10549 ((k == 0) || (k == 1 && weights[nvars - 1] + sumcoef + weights[pos] > capacity)) )
10550 {
10551 newweight = capacity - sumcoef;
10552 assert(newweight > weights[pos]);
10553
10554 SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10555 SCIPconsGetName(cons), maxweight, newweight);
10556
10557 consdataChgWeight(consdata, pos, newweight);
10558
10559 break;
10560 }
10561
10562 if( backpos <= pos )
10563 break;
10564 }
10565 }
10566
10567 /* apply rule (2) (don't apply, if the knapsack has too many items for applying this costly method) */
10568 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
10569 {
10570 if( conshdlrdata->disaggregation && consdata->nvars - pos <= MAX_USECLIQUES_SIZE && consdata->nvars >= 2 &&
10571 pos > 0 && (SCIP_Longint)consdata->nvars - pos <= consdata->capacity &&
10572 consdata->weights[pos - 1] == consdata->capacity && (pos == consdata->nvars || consdata->weights[pos] == 1) )
10573 {
10574 SCIP_VAR** clqvars;
10575 SCIP_CONS* cliquecons;
10576 char name[SCIP_MAXSTRLEN];
10577 int* clqpart;
10578 int nclqvars;
10579 int nclq;
10580 int len;
10581 int c;
10582 int w;
10583
10584 assert(!SCIPconsIsDeleted(cons));
10585
10586 if( pos == consdata->nvars )
10587 {
10588 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
10589
10590 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, SCIPconsGetName(cons), pos, consdata->vars,
10594 SCIPconsIsStickingAtNode(cons)) );
10595
10596 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10597 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10598 ++(*naddconss);
10599
10600 /* delete old constraint */
10601 SCIP_CALL( SCIPdelCons(scip, cons) );
10602 ++(*ndelconss);
10603
10604 return SCIP_OKAY;
10605 }
10606
10607 len = consdata->nvars - pos;
10608
10609 /* allocate temporary memory */
10610 SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
10611
10612 /* calculate clique partition */
10613 SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[pos]), len, clqpart, &nclq) );
10614 assert(nclq <= len);
10615
10616#ifndef NDEBUG
10617 /* clique numbers must be at least as high as the index */
10618 for( w = 0; w < nclq; ++w )
10619 assert(clqpart[w] <= w);
10620#endif
10621
10622 SCIPdebugMsg(scip, "Disaggregating knapsack constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
10623
10624 /* allocate temporary memory */
10625 SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, pos + len - nclq + 1) );
10626
10627 /* copy corresponding variables with big coefficients */
10628 for( w = pos - 1; w >= 0; --w )
10629 clqvars[w] = consdata->vars[w];
10630
10631 /* create for each clique a set-packing constraint */
10632 for( c = 0; c < nclq; ++c )
10633 {
10634 nclqvars = pos;
10635
10636 for( w = c; w < len; ++w )
10637 {
10638 if( clqpart[w] == c )
10639 {
10640 assert(nclqvars < pos + len - nclq + 1);
10641 clqvars[nclqvars] = consdata->vars[w + pos];
10642 ++nclqvars;
10643 }
10644 }
10645
10646 assert(nclqvars > 1);
10647
10648 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, c);
10649 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
10653 SCIPconsIsStickingAtNode(cons)) );
10654 SCIPdebugMsg(scip, " -> adding clique constraint: ");
10655 SCIPdebugPrintCons(scip, cliquecons, NULL);
10656 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10657 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10658 ++(*naddconss);
10659 }
10660
10661 /* delete old constraint */
10662 SCIP_CALL( SCIPdelCons(scip, cons) );
10663 ++(*ndelconss);
10664
10665 SCIPfreeBufferArray(scip, &clqvars);
10666 SCIPfreeBufferArray(scip, &clqpart);
10667
10668 return SCIP_OKAY;
10669 }
10670 else if( consdata->nvars <= MAX_USECLIQUES_SIZE || (consdata->cliquepartitioned && consdata->ncliques <= MAX_USECLIQUES_SIZE) )
10671 {
10672 SCIP_Longint* maxcliqueweights;
10673 SCIP_Longint* newweightvals;
10674 int* newweightidxs;
10675 SCIP_Longint cliqueweightsum;
10676
10677 SCIP_CALL( SCIPallocBufferArray(scip, &maxcliqueweights, consdata->nvars) );
10678 SCIP_CALL( SCIPallocBufferArray(scip, &newweightvals, consdata->nvars) );
10679 SCIP_CALL( SCIPallocBufferArray(scip, &newweightidxs, consdata->nvars) );
10680
10681 /* repeat as long as changes have been applied */
10682 do
10683 {
10684 int ncliques;
10685 int cliquenum;
10686 SCIP_Bool zeroweights;
10687
10688 assert(consdata->merged);
10689
10690 /* sort items, s.t. the heaviest one is in the first position */
10691 sortItems(consdata);
10692
10693 /* calculate a clique partition */
10694 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10695
10696 /* if there are only single element cliques, rule (2) is equivalent to rule (1) */
10697 if( consdata->cliquepartition[consdata->nvars - 1] == consdata->nvars - 1 )
10698 break;
10699
10700 /* calculate the maximal weight of the cliques and store the clique type */
10701 cliqueweightsum = 0;
10702 ncliques = 0;
10703
10704 for( i = 0; i < consdata->nvars; ++i )
10705 {
10706 SCIP_Longint weight;
10707
10708 cliquenum = consdata->cliquepartition[i];
10709 assert(0 <= cliquenum && cliquenum <= ncliques);
10710
10711 weight = consdata->weights[i];
10712 assert(weight > 0);
10713
10714 if( cliquenum == ncliques )
10715 {
10716 maxcliqueweights[ncliques] = weight;
10717 cliqueweightsum += weight;
10718 ++ncliques;
10719 }
10720
10721 assert(maxcliqueweights[cliquenum] >= weight);
10722 }
10723
10724 /* apply rule on every clique */
10725 zeroweights = FALSE;
10726 for( i = 0; i < ncliques; ++i )
10727 {
10728 SCIP_Longint delta;
10729
10730 delta = consdata->capacity - (cliqueweightsum - maxcliqueweights[i]);
10731 if( delta > 0 )
10732 {
10733 SCIP_Longint newcapacity;
10734#ifndef NDEBUG
10735 SCIP_Longint newmincliqueweight;
10736#endif
10737 SCIP_Longint newminweightsuminclique;
10738 SCIP_Bool forceclique;
10739 int nnewweights;
10740 int j;
10741
10742 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",
10743 SCIPconsGetName(cons), i, maxcliqueweights[i], cliqueweightsum, consdata->capacity, delta);
10744 newcapacity = consdata->capacity - delta;
10745 forceclique = FALSE;
10746 nnewweights = 0;
10747#ifndef NDEBUG
10748 newmincliqueweight = newcapacity + 1;
10749 for( j = 0; j < i; ++j )
10750 assert(consdata->cliquepartition[j] < i); /* no element j < i can be in clique i */
10751#endif
10752 for( j = i; j < consdata->nvars; ++j )
10753 {
10754 if( consdata->cliquepartition[j] == i )
10755 {
10756 newweight = consdata->weights[j] - delta;
10757 newweight = MAX(newweight, 0);
10758
10759 /* cache the new weight */
10760 assert(nnewweights < consdata->nvars);
10761 newweightvals[nnewweights] = newweight;
10762 newweightidxs[nnewweights] = j;
10763 nnewweights++;
10764
10765#ifndef NDEBUG
10766 assert(newweight <= newmincliqueweight); /* items are sorted by non-increasing weight! */
10767 newmincliqueweight = newweight;
10768#endif
10769 }
10770 }
10771
10772 /* check if our clique information results out of this knapsack constraint and if so check if we would loose the clique information */
10773 if( nnewweights > 1 )
10774 {
10775#ifndef NDEBUG
10776 j = newweightidxs[nnewweights - 2];
10777 assert(0 <= j && j < consdata->nvars);
10778 assert(consdata->cliquepartition[j] == i);
10779 j = newweightidxs[nnewweights - 1];
10780 assert(0 <= j && j < consdata->nvars);
10781 assert(consdata->cliquepartition[j] == i);
10782#endif
10783
10784 newminweightsuminclique = newweightvals[nnewweights - 2];
10785 newminweightsuminclique += newweightvals[nnewweights - 1];
10786
10787 /* check if these new two minimal weights both fit into the knapsack;
10788 * if this is true, we have to add a clique constraint in order to enforce the clique
10789 * (otherwise, the knapsack might have been one of the reasons for the clique, and the weight
10790 * reduction might be infeasible, i.e., allows additional solutions)
10791 */
10792 if( newminweightsuminclique <= newcapacity )
10793 forceclique = TRUE;
10794 }
10795
10796 /* check if we really want to apply the change */
10797 if( conshdlrdata->disaggregation || !forceclique )
10798 {
10799 SCIPdebugMsg(scip, " -> change capacity from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT " (forceclique:%u)\n",
10800 consdata->capacity, newcapacity, forceclique);
10801 consdata->capacity = newcapacity;
10802 (*nchgsides)++;
10803
10804 for( k = 0; k < nnewweights; ++k )
10805 {
10806 j = newweightidxs[k];
10807 assert(0 <= j && j < consdata->nvars);
10808 assert(consdata->cliquepartition[j] == i);
10809
10810 /* apply the weight change */
10811 SCIPdebugMsg(scip, " -> change weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10812 SCIPvarGetName(consdata->vars[j]), consdata->weights[j], newweightvals[k]);
10813 consdataChgWeight(consdata, j, newweightvals[k]);
10814 (*nchgcoefs)++;
10815 assert(!consdata->sorted);
10816 zeroweights = zeroweights || (newweightvals[k] == 0);
10817 }
10818 /* if before the weight update at least one pair of weights did not fit into the knapsack and now fits,
10819 * we have to make sure, the clique is enforced - the clique might have been constructed partially from
10820 * this constraint, and by reducing the weights, this clique information is not contained anymore in the
10821 * knapsack constraint
10822 */
10823 if( forceclique )
10824 {
10825 SCIP_CONS* cliquecons;
10826 char name[SCIP_MAXSTRLEN];
10827 SCIP_VAR** cliquevars;
10828
10829 SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nnewweights) );
10830 for( k = 0; k < nnewweights; ++k )
10831 cliquevars[k] = consdata->vars[newweightidxs[k]];
10832
10833 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, i);
10834 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nnewweights, cliquevars,
10838 SCIPconsIsStickingAtNode(cons)) );
10839 SCIPdebugMsg(scip, " -> adding clique constraint: ");
10840 SCIPdebugPrintCons(scip, cliquecons, NULL);
10841 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10842 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10843 SCIPfreeBufferArray(scip, &cliquevars);
10844 (*naddconss)++;
10845 }
10846 }
10847 }
10848 }
10849 if( zeroweights )
10850 {
10852 }
10853 }
10854 while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10855
10856 /* free temporary memory */
10857 SCIPfreeBufferArray(scip, &newweightidxs);
10858 SCIPfreeBufferArray(scip, &newweightvals);
10859 SCIPfreeBufferArray(scip, &maxcliqueweights);
10860
10861 /* check for redundancy */
10862 if( consdata->weightsum <= consdata->capacity )
10863 return SCIP_OKAY;
10864 }
10865 }
10866
10867 /* apply rule (3) */
10868 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
10869 {
10870 SCIP_CALL( tightenWeightsLift(scip, cons, nchgcoefs, cutoff) );
10871 }
10872
10873 /* check for redundancy */
10874 if( consdata->weightsum <= consdata->capacity )
10875 return SCIP_OKAY;
10876
10877 if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10878 {
10879 /* apply rule (4) (all but smallest weight) */
10880 assert(consdata->merged);
10881 sortItems(consdata);
10882 minweight = consdata->weights[consdata->nvars-1];
10883 for( i = 0; i < consdata->nvars-1; ++i )
10884 {
10885 SCIP_Longint weight;
10886
10887 weight = consdata->weights[i];
10888 assert(weight >= minweight);
10889 if( minweight + weight > consdata->capacity )
10890 {
10891 if( weight < consdata->capacity )
10892 {
10893 SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10894 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, consdata->capacity);
10895 assert(consdata->sorted);
10896 consdataChgWeight(consdata, i, consdata->capacity); /* this does not destroy the weight order! */
10897 assert(i == 0 || consdata->weights[i-1] >= consdata->weights[i]);
10898 consdata->sorted = TRUE;
10899 (*nchgcoefs)++;
10900 }
10901 }
10902 else
10903 break;
10904 }
10905
10906 /* apply rule (5) (smallest weight) */
10907 if( consdata->nvars >= 2 )
10908 {
10909 SCIP_Longint weight;
10910
10911 minweight = consdata->weights[consdata->nvars-2];
10912 weight = consdata->weights[consdata->nvars-1];
10913 assert(minweight >= weight);
10914 if( minweight + weight > consdata->capacity && 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[consdata->nvars-1]), weight, consdata->capacity);
10918 assert(consdata->sorted);
10919 consdataChgWeight(consdata, consdata->nvars-1, consdata->capacity); /* this does not destroy the weight order! */
10920 assert(minweight >= consdata->weights[consdata->nvars-1]);
10921 consdata->sorted = TRUE;
10922 (*nchgcoefs)++;
10923 }
10924 }
10925 }
10926
10927 return SCIP_OKAY;
10928}
10929
10930
10931#ifdef SCIP_DEBUG
10932static
10933void printClique(
10934 SCIP_VAR** cliquevars,
10935 int ncliquevars
10936 )
10937{
10938 int b;
10939 SCIPdebugMessage("adding new Clique: ");
10940 for( b = 0; b < ncliquevars; ++b )
10941 SCIPdebugPrintf("%s ", SCIPvarGetName(cliquevars[b]));
10942 SCIPdebugPrintf("\n");
10943}
10944#endif
10945
10946/** adds negated cliques of the knapsack constraint to the global clique table */
10947static
10949 SCIP*const scip, /**< SCIP data structure */
10950 SCIP_CONS*const cons, /**< knapsack constraint */
10951 SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
10952 int*const nbdchgs /**< pointer to count the number of performed bound changes */
10953 )
10954{
10955 SCIP_CONSDATA* consdata;
10956 SCIP_CONSHDLRDATA* conshdlrdata;
10957 SCIP_VAR** poscliquevars;
10958 SCIP_VAR** cliquevars;
10959 SCIP_Longint* maxweights;
10960 SCIP_Longint* gainweights;
10961 int* gaincliquepartition;
10962 SCIP_Bool* cliqueused;
10963 SCIP_Longint minactduetonegcliques;
10964 SCIP_Longint freecapacity;
10965 SCIP_Longint lastweight;
10966 SCIP_Longint beforelastweight;
10967 int nposcliquevars;
10968 int ncliquevars;
10969 int nvars;
10970 int nnegcliques;
10971 int lastcliqueused;
10972 int thisnbdchgs;
10973 int v;
10974 int w;
10975
10976 assert(scip != NULL);
10977 assert(cons != NULL);
10978 assert(cutoff != NULL);
10979 assert(nbdchgs != NULL);
10980
10981 *cutoff = FALSE;
10982
10983 consdata = SCIPconsGetData(cons);
10984 assert(consdata != NULL);
10985
10986 nvars = consdata->nvars;
10987
10988 /* check whether the cliques have already been added */
10989 if( consdata->cliquesadded || nvars == 0 )
10990 return SCIP_OKAY;
10991
10992 /* make sure, the items are merged */
10993 SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10994 if( *cutoff )
10995 return SCIP_OKAY;
10996
10997 /* make sure, items are sorted by non-increasing weight */
10998 sortItems(consdata);
10999
11000 assert(consdata->merged);
11001
11002 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11003 assert(conshdlrdata != NULL);
11004
11005 /* calculate a clique partition */
11006 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
11007 nnegcliques = consdata->nnegcliques;
11008
11009 /* if we have no negated cliques, stop */
11010 if( nnegcliques == nvars )
11011 return SCIP_OKAY;
11012
11013 /* get temporary memory */
11014 SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
11015 SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
11016 SCIP_CALL( SCIPallocClearBufferArray(scip, &gainweights, nvars) );
11017 SCIP_CALL( SCIPallocBufferArray(scip, &gaincliquepartition, nvars) );
11018 SCIP_CALL( SCIPallocBufferArray(scip, &maxweights, nnegcliques) );
11019 SCIP_CALL( SCIPallocClearBufferArray(scip, &cliqueused, nnegcliques) );
11020
11021 nnegcliques = 0;
11022 minactduetonegcliques = 0;
11023
11024 /* determine maximal weights for all negated cliques and calculate minimal weightsum due to negated cliques */
11025 for( v = 0; v < nvars; ++v )
11026 {
11027 assert(0 <= consdata->negcliquepartition[v] && consdata->negcliquepartition[v] <= nnegcliques);
11028 assert(consdata->weights[v] > 0);
11029
11030 if( consdata->negcliquepartition[v] == nnegcliques )
11031 {
11032 nnegcliques++;
11033 maxweights[consdata->negcliquepartition[v]] = consdata->weights[v];
11034 }
11035 else
11036 minactduetonegcliques += consdata->weights[v];
11037 }
11038
11039 nposcliquevars = 0;
11040
11041 /* add cliques, using negated cliques information */
11042 if( minactduetonegcliques > 0 )
11043 {
11044 /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11045 freecapacity = consdata->capacity - minactduetonegcliques;
11046
11048 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",
11049 SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11050
11051 /* calculate possible gain by switching chosen items in negated cliques */
11052 for( v = 0; v < nvars; ++v )
11053 {
11054 if( !cliqueused[consdata->negcliquepartition[v]] )
11055 {
11056 cliqueused[consdata->negcliquepartition[v]] = TRUE;
11057 for( w = v + 1; w < nvars; ++w )
11058 {
11059 /* if we would take the biggest weight instead of another what would we gain, take weight[v] instead of
11060 * weight[w] (which are both in a negated clique) */
11061 if( consdata->negcliquepartition[v] == consdata->negcliquepartition[w]
11062 && consdata->weights[v] > consdata->weights[w] )
11063 {
11064 poscliquevars[nposcliquevars] = consdata->vars[w];
11065 gainweights[nposcliquevars] = maxweights[consdata->negcliquepartition[v]] - consdata->weights[w];
11066 gaincliquepartition[nposcliquevars] = consdata->negcliquepartition[v];
11067 ++nposcliquevars;
11068 }
11069 }
11070 }
11071 }
11072
11073 /* try to create negated cliques */
11074 if( nposcliquevars > 0 )
11075 {
11076 /* sort possible gain per substitution of the clique members */
11077 SCIPsortDownLongPtrInt(gainweights,(void**) poscliquevars, gaincliquepartition, nposcliquevars);
11078
11079 for( v = 0; v < nposcliquevars; ++v )
11080 {
11081 SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[v], &cliquevars[0]) );
11082 ncliquevars = 1;
11083 lastweight = gainweights[v];
11084 beforelastweight = -1;
11085 lastcliqueused = gaincliquepartition[v];
11086 /* clear cliqueused to get an unused array */
11087 BMSclearMemoryArray(cliqueused, nnegcliques);
11088 cliqueused[gaincliquepartition[v]] = TRUE;
11089
11090 /* taking bigger weights make the knapsack redundant so we will create cliques, only take items which are not
11091 * in the same negated clique and by taking two of them would exceed the free capacity */
11092 for( w = v + 1; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && gainweights[w] + lastweight > freecapacity; ++w )
11093 {
11094 beforelastweight = lastweight;
11095 lastweight = gainweights[w];
11096 lastcliqueused = gaincliquepartition[w];
11097 cliqueused[gaincliquepartition[w]] = TRUE;
11098 SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars]) );
11099 ++ncliquevars;
11100 }
11101
11102 if( ncliquevars > 1 )
11103 {
11104 SCIPdebug( printClique(cliquevars, ncliquevars) );
11105 assert(beforelastweight > 0);
11106 /* add the clique to the clique table */
11107 /* this really happens, e.g., on enigma.mps from the short test set */
11108 SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11109 if( *cutoff )
11110 goto TERMINATE;
11111 *nbdchgs += thisnbdchgs;
11112
11113 /* reset last used clique to get slightly different cliques */
11114 cliqueused[lastcliqueused] = FALSE;
11115
11116 /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11117 for( ++w; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && beforelastweight + gainweights[w] > freecapacity; ++w )
11118 {
11119 SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars - 1]) );
11120 SCIPdebug( printClique(cliquevars, ncliquevars) );
11121 SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11122 if( *cutoff )
11123 goto TERMINATE;
11124 *nbdchgs += thisnbdchgs;
11125 }
11126 }
11127 }
11128 }
11129 }
11130
11131 TERMINATE:
11132 /* free temporary memory */
11133 SCIPfreeBufferArray(scip, &cliqueused);
11134 SCIPfreeBufferArray(scip, &maxweights);
11135 SCIPfreeBufferArray(scip, &gaincliquepartition);
11136 SCIPfreeBufferArray(scip, &gainweights);
11137 SCIPfreeBufferArray(scip, &cliquevars);
11138 SCIPfreeBufferArray(scip, &poscliquevars);
11139
11140 return SCIP_OKAY;
11141}
11142
11143/** greedy clique detection by considering weights and capacity
11144 *
11145 * greedily detects cliques by first sorting the items by decreasing weights (optional) and then collecting greedily
11146 * 1) neighboring items which exceed the capacity together => one clique
11147 * 2) looping through the remaining items and finding the largest set of preceding items to build a clique => possibly many more cliques
11148 */
11149static
11151 SCIP*const scip, /**< SCIP data structure */
11152 SCIP_VAR** items, /**< array of variable items */
11153 SCIP_Longint* weights, /**< weights of the items */
11154 int nitems, /**< the number of items */
11155 SCIP_Longint capacity, /**< maximum free capacity of the knapsack */
11156 SCIP_Bool sorteditems, /**< are the items sorted by their weights nonincreasing? */
11157 SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11158 SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11159 int*const nbdchgs /**< pointer to count the number of performed bound changes */
11160 )
11161{
11162 SCIP_Longint lastweight;
11163 int ncliquevars;
11164 int i;
11165 int thisnbdchgs;
11166
11167 if( nitems <= 1 )
11168 return SCIP_OKAY;
11169
11170 /* sort possible gain per substitution of the clique members */
11171 if( ! sorteditems )
11172 SCIPsortDownLongPtr(weights,(void**) items, nitems);
11173
11174 ncliquevars = 1;
11175 lastweight = weights[0];
11176
11177 /* taking these two weights together violates the knapsack => include into clique */
11178 for( i = 1; i < nitems && weights[i] + lastweight > capacity; ++i )
11179 {
11180 lastweight = weights[i];
11181 ++ncliquevars;
11182 }
11183
11184 if( ncliquevars > 1 )
11185 {
11186 SCIP_Longint compareweight;
11187 SCIP_VAR** cliquevars;
11188 int compareweightidx;
11189 int minclqsize;
11190 int nnzadded;
11191
11192 /* add the clique to the clique table */
11193 SCIPdebug( printClique(items, ncliquevars) );
11194 SCIP_CALL( SCIPaddClique(scip, items, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11195
11196 if( *cutoff )
11197 return SCIP_OKAY;
11198
11199 *nbdchgs += thisnbdchgs;
11200 nnzadded = ncliquevars;
11201
11202 /* 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)*/
11203 if( ncliquevars == nitems )
11204 return SCIP_OKAY;
11205
11206 /* copy items in order into buffer array and deduce more cliques */
11207 SCIP_CALL( SCIPduplicateBufferArray(scip, &cliquevars, items, ncliquevars) );
11208
11209 /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11210 /* loop over remaining, smaller items and compare each item backwards against larger weights, starting with the second smallest weight */
11211 compareweightidx = ncliquevars - 2;
11212 assert(i == nitems || weights[i] + weights[ncliquevars - 1] <= capacity);
11213
11214 /* determine minimum clique size for the following loop */
11215 minclqsize = (int)(cliqueextractfactor * ncliquevars);
11216 minclqsize = MAX(minclqsize, 2);
11217
11218 /* loop over the remaining variables and the larger items of the first clique until we
11219 * find another clique or reach the size limit */
11220 while( compareweightidx >= 0 && i < nitems && ! (*cutoff)
11221 && ncliquevars >= minclqsize /* stop at a given minimum clique size */
11222 && nnzadded <= 2 * nitems /* stop if enough nonzeros were added to the cliquetable */
11223 )
11224 {
11225 compareweight = weights[compareweightidx];
11226 assert(compareweight > 0);
11227
11228 /* include this item together with all items that have a weight at least as large as the compare weight in a clique */
11229 if( compareweight + weights[i] > capacity )
11230 {
11231 assert(compareweightidx == ncliquevars -2);
11232 cliquevars[ncliquevars - 1] = items[i];
11233 SCIPdebug( printClique(cliquevars, ncliquevars) );
11234 SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11235
11236 nnzadded += ncliquevars;
11237
11238 /* stop when there is a cutoff */
11239 if( ! (*cutoff) )
11240 *nbdchgs += thisnbdchgs;
11241
11242 /* go to next smaller item */
11243 ++i;
11244 }
11245 else
11246 {
11247 /* choose a preceding, larger weight to compare small items against. Clique size is reduced by 1 simultaneously */
11248 compareweightidx--;
11249 ncliquevars --;
11250 }
11251 }
11252
11253 SCIPfreeBufferArray(scip, &cliquevars);
11254 }
11255
11256 return SCIP_OKAY;
11257}
11258
11259/** adds cliques of the knapsack constraint to the global clique table */
11260static
11262 SCIP*const scip, /**< SCIP data structure */
11263 SCIP_CONS*const cons, /**< knapsack constraint */
11264 SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11265 SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11266 int*const nbdchgs /**< pointer to count the number of performed bound changes */
11267 )
11268{
11269 SCIP_CONSDATA* consdata;
11270 SCIP_CONSHDLRDATA* conshdlrdata;
11271 int i;
11272 SCIP_Longint minactduetonegcliques;
11273 SCIP_Longint freecapacity;
11274 int nnegcliques;
11275 int cliquenum;
11276 SCIP_VAR** poscliquevars;
11277 SCIP_Longint* gainweights;
11278 int nposcliquevars;
11279 SCIP_Longint* secondmaxweights;
11280 int nvars;
11281
11282 assert(scip != NULL);
11283 assert(cons != NULL);
11284 assert(cutoff != NULL);
11285 assert(nbdchgs != NULL);
11286
11287 *cutoff = FALSE;
11288
11289 consdata = SCIPconsGetData(cons);
11290 assert(consdata != NULL);
11291
11292 nvars = consdata->nvars;
11293
11294 /* check whether the cliques have already been added */
11295 if( consdata->cliquesadded || nvars == 0 )
11296 return SCIP_OKAY;
11297
11298 /* make sure, the items are merged */
11299 SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
11300 if( *cutoff )
11301 return SCIP_OKAY;
11302
11303 /* make sure, the items are sorted by non-increasing weight */
11304 sortItems(consdata);
11305
11306 assert(consdata->merged);
11307
11308 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11309 assert(conshdlrdata != NULL);
11310
11311 /* calculate a clique partition */
11312 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
11313 nnegcliques = consdata->nnegcliques;
11314 assert(nnegcliques <= nvars);
11315
11316 /* get temporary memory */
11317 SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
11318 SCIP_CALL( SCIPallocBufferArray(scip, &gainweights, nvars) );
11319 BMSclearMemoryArray(gainweights, nvars);
11320 SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
11321 BMSclearMemoryArray(secondmaxweights, nnegcliques);
11322
11323 minactduetonegcliques = 0;
11324
11325 /* calculate minimal activity due to negated cliques, and determine second maximal weight in each clique */
11326 if( nnegcliques < nvars )
11327 {
11328 nnegcliques = 0;
11329
11330 for( i = 0; i < nvars; ++i )
11331 {
11332 SCIP_Longint weight;
11333
11334 cliquenum = consdata->negcliquepartition[i];
11335 assert(0 <= cliquenum && cliquenum <= nnegcliques);
11336
11337 weight = consdata->weights[i];
11338 assert(weight > 0);
11339
11340 if( cliquenum == nnegcliques )
11341 nnegcliques++;
11342 else
11343 {
11344 minactduetonegcliques += weight;
11345 if( secondmaxweights[cliquenum] == 0 )
11346 secondmaxweights[cliquenum] = weight;
11347 }
11348 }
11349 }
11350
11351 /* add cliques, using negated cliques information */
11352 if( minactduetonegcliques > 0 )
11353 {
11354 /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11355 freecapacity = consdata->capacity - minactduetonegcliques;
11356
11358 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",
11359 SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11360
11361 /* create negated cliques out of negated cliques, if we do not take the smallest weight of a cliques ... */
11362 SCIP_CALL( addNegatedCliques(scip, cons, cutoff, nbdchgs ) );
11363
11364 if( *cutoff )
11365 goto TERMINATE;
11366
11367 nposcliquevars = 0;
11368
11369 for( i = nvars - 1; i >= 0; --i )
11370 {
11371 /* if we would take the biggest weight instead of the second biggest */
11372 cliquenum = consdata->negcliquepartition[i];
11373 if( consdata->weights[i] > secondmaxweights[cliquenum] )
11374 {
11375 poscliquevars[nposcliquevars] = consdata->vars[i];
11376 gainweights[nposcliquevars] = consdata->weights[i] - secondmaxweights[cliquenum];
11377 ++nposcliquevars;
11378 }
11379 }
11380
11381 /* use the gain weights and free capacity to derive greedily cliques */
11382 if( nposcliquevars > 1 )
11383 {
11384 SCIP_CALL( greedyCliqueAlgorithm(scip, poscliquevars, gainweights, nposcliquevars, freecapacity, FALSE, cliqueextractfactor, cutoff, nbdchgs) );
11385
11386 if( *cutoff )
11387 goto TERMINATE;
11388 }
11389 }
11390
11391 /* build cliques by using the items with the maximal weights */
11392 SCIP_CALL( greedyCliqueAlgorithm(scip, consdata->vars, consdata->weights, nvars, consdata->capacity, TRUE, cliqueextractfactor, cutoff, nbdchgs) );
11393
11394 TERMINATE:
11395 /* free temporary memory and mark the constraint */
11396 SCIPfreeBufferArray(scip, &secondmaxweights);
11397 SCIPfreeBufferArray(scip, &gainweights);
11398 SCIPfreeBufferArray(scip, &poscliquevars);
11399 consdata->cliquesadded = TRUE;
11400
11401 return SCIP_OKAY;
11402}
11403
11404
11405/** gets the key of the given element */
11406static
11407SCIP_DECL_HASHGETKEY(hashGetKeyKnapsackcons)
11408{ /*lint --e{715}*/
11409 /* the key is the element itself */
11410 return elem;
11411}
11412
11413/** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables and the
11414 * same coefficients
11415 */
11416static
11417SCIP_DECL_HASHKEYEQ(hashKeyEqKnapsackcons)
11418{
11419#ifndef NDEBUG
11420 SCIP* scip;
11421#endif
11422 SCIP_CONSDATA* consdata1;
11423 SCIP_CONSDATA* consdata2;
11424 int i;
11425
11426 consdata1 = SCIPconsGetData((SCIP_CONS*)key1);
11427 consdata2 = SCIPconsGetData((SCIP_CONS*)key2);
11428 assert(consdata1->sorted);
11429 assert(consdata2->sorted);
11430#ifndef NDEBUG
11431 scip = (SCIP*)userptr;
11432 assert(scip != NULL);
11433#endif
11434
11435 /* checks trivial case */
11436 if( consdata1->nvars != consdata2->nvars )
11437 return FALSE;
11438
11439 for( i = consdata1->nvars - 1; i >= 0; --i )
11440 {
11441 /* tests if variables are equal */
11442 if( consdata1->vars[i] != consdata2->vars[i] )
11443 {
11444 assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 ||
11445 SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1);
11446 return FALSE;
11447 }
11448 assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 0);
11449
11450 /* tests if weights are equal too */
11451 if( consdata1->weights[i] != consdata2->weights[i] )
11452 return FALSE;
11453 }
11454
11455 return TRUE;
11456}
11457
11458/** returns the hash value of the key */
11459static
11460SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)
11461{
11462#ifndef NDEBUG
11463 SCIP* scip;
11464#endif
11465 SCIP_CONSDATA* consdata;
11466 uint64_t firstweight;
11467 int minidx;
11468 int mididx;
11469 int maxidx;
11470
11471 consdata = SCIPconsGetData((SCIP_CONS*)key);
11472 assert(consdata != NULL);
11473 assert(consdata->nvars > 0);
11474
11475#ifndef NDEBUG
11476 scip = (SCIP*)userptr;
11477 assert(scip != NULL);
11478#endif
11479
11480 /* sorts the constraints */
11481 sortItems(consdata);
11482
11483 minidx = SCIPvarGetIndex(consdata->vars[0]);
11484 mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]);
11485 maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]);
11486 assert(minidx >= 0 && mididx >= 0 && maxidx >= 0);
11487
11488 /* hash value depends on vectors of variable indices */
11489 firstweight = (uint64_t)consdata->weights[0];
11490 return SCIPhashSix(consdata->nvars, minidx, mididx, maxidx, firstweight>>32, firstweight);
11491}
11492
11493/** compares each constraint with all other constraints for possible redundancy and removes or changes constraint
11494 * accordingly; in contrast to preprocessConstraintPairs(), it uses a hash table
11495 */
11496static
11498 SCIP* scip, /**< SCIP data structure */
11499 BMS_BLKMEM* blkmem, /**< block memory */
11500 SCIP_CONS** conss, /**< constraint set */
11501 int nconss, /**< number of constraints in constraint set */
11502 SCIP_Bool* cutoff, /**< pointer to store whether the problem is infeasible */
11503 int* ndelconss /**< pointer to count number of deleted constraints */
11504 )
11505{
11506 SCIP_HASHTABLE* hashtable;
11507 int hashtablesize;
11508 int c;
11509
11510 assert(scip != NULL);
11511 assert(blkmem != NULL);
11512 assert(conss != NULL);
11513 assert(ndelconss != NULL);
11514
11515 /* create a hash table for the constraint set */
11516 hashtablesize = nconss;
11517 hashtablesize = MAX(hashtablesize, HASHSIZE_KNAPSACKCONS);
11518 SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize,
11519 hashGetKeyKnapsackcons, hashKeyEqKnapsackcons, hashKeyValKnapsackcons, (void*) scip) );
11520
11521 /* check all constraints in the given set for redundancy */
11522 for( c = nconss - 1; c >= 0; --c )
11523 {
11524 SCIP_CONS* cons0;
11525 SCIP_CONS* cons1;
11526 SCIP_CONSDATA* consdata0;
11527
11528 cons0 = conss[c];
11529
11530 if( !SCIPconsIsActive(cons0) || SCIPconsIsModifiable(cons0) )
11531 continue;
11532
11533 consdata0 = SCIPconsGetData(cons0);
11534 assert(consdata0 != NULL);
11535 if( consdata0->nvars == 0 )
11536 {
11537 if( consdata0->capacity < 0 )
11538 {
11539 *cutoff = TRUE;
11540 goto TERMINATE;
11541 }
11542 else
11543 {
11544 SCIP_CALL( SCIPdelCons(scip, cons0) );
11545 ++(*ndelconss);
11546 continue;
11547 }
11548 }
11549
11550 /* get constraint from current hash table with same variables and same weights as cons0 */
11551 cons1 = (SCIP_CONS*)(SCIPhashtableRetrieve(hashtable, (void*)cons0));
11552
11553 if( cons1 != NULL )
11554 {
11555 SCIP_CONS* consstay;
11556 SCIP_CONS* consdel;
11557 SCIP_CONSDATA* consdata1;
11558
11559 assert(SCIPconsIsActive(cons1));
11560 assert(!SCIPconsIsModifiable(cons1));
11561
11562 /* constraint found: create a new constraint with same coefficients and best left and right hand side;
11563 * delete old constraints afterwards
11564 */
11565 consdata1 = SCIPconsGetData(cons1);
11566
11567 assert(consdata1 != NULL);
11568 assert(consdata0->nvars > 0 && consdata0->nvars == consdata1->nvars);
11569
11570 assert(consdata0->sorted && consdata1->sorted);
11571 assert(consdata0->vars[0] == consdata1->vars[0]);
11572 assert(consdata0->weights[0] == consdata1->weights[0]);
11573
11574 SCIPdebugMsg(scip, "knapsack constraints <%s> and <%s> with equal coefficients\n",
11575 SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11576
11577 /* check which constraint has to stay; */
11578 if( consdata0->capacity < consdata1->capacity )
11579 {
11580 consstay = cons0;
11581 consdel = cons1;
11582
11583 /* exchange consdel with consstay in hashtable */
11584 SCIP_CALL( SCIPhashtableRemove(hashtable, (void*) consdel) );
11585 SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) consstay) );
11586 }
11587 else
11588 {
11589 consstay = cons1;
11590 consdel = cons0;
11591 }
11592
11593 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11594 SCIP_CALL( SCIPupdateConsFlags(scip, consstay, consdel) );
11595
11596 /* delete consdel */
11597 SCIP_CALL( SCIPdelCons(scip, consdel) );
11598 ++(*ndelconss);
11599
11600 assert(SCIPconsIsActive(consstay));
11601 }
11602 else
11603 {
11604 /* no such constraint in current hash table: insert cons0 into hash table */
11605 SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) cons0) );
11606 }
11607 }
11608
11609 TERMINATE:
11610 /* free hash table */
11611 SCIPhashtableFree(&hashtable);
11612
11613 return SCIP_OKAY;
11614}
11615
11616
11617/** compares constraint with all prior constraints for possible redundancy or aggregation,
11618 * and removes or changes constraint accordingly
11619 */
11620static
11622 SCIP* scip, /**< SCIP data structure */
11623 SCIP_CONS** conss, /**< constraint set */
11624 int firstchange, /**< first constraint that changed since last pair preprocessing round */
11625 int chkind, /**< index of constraint to check against all prior indices upto startind */
11626 int* ndelconss /**< pointer to count number of deleted constraints */
11627 )
11628{
11629 SCIP_CONS* cons0;
11630 SCIP_CONSDATA* consdata0;
11631 int c;
11632
11633 assert(scip != NULL);
11634 assert(conss != NULL);
11635 assert(firstchange <= chkind);
11636 assert(ndelconss != NULL);
11637
11638 /* get the constraint to be checked against all prior constraints */
11639 cons0 = conss[chkind];
11640 assert(cons0 != NULL);
11641 assert(SCIPconsIsActive(cons0));
11642 assert(!SCIPconsIsModifiable(cons0));
11643
11644 consdata0 = SCIPconsGetData(cons0);
11645 assert(consdata0 != NULL);
11646 assert(consdata0->nvars >= 1);
11647 assert(consdata0->merged);
11648
11649 /* sort the constraint */
11650 sortItems(consdata0);
11651
11652 /* see #2970 */
11653 if( consdata0->capacity == 0 )
11654 return SCIP_OKAY;
11655
11656 /* check constraint against all prior constraints */
11657 for( c = (consdata0->presolvedtiming == SCIP_PRESOLTIMING_EXHAUSTIVE ? firstchange : 0); c < chkind; ++c )
11658 {
11659 SCIP_CONS* cons1;
11660 SCIP_CONSDATA* consdata1;
11661 SCIP_Bool iscons0incons1contained;
11662 SCIP_Bool iscons1incons0contained;
11663 SCIP_Real quotient;
11664 int v;
11665 int v0;
11666 int v1;
11667
11668 cons1 = conss[c];
11669 assert(cons1 != NULL);
11670 if( !SCIPconsIsActive(cons1) || SCIPconsIsModifiable(cons1) )
11671 continue;
11672
11673 consdata1 = SCIPconsGetData(cons1);
11674 assert(consdata1 != NULL);
11675
11676 /* if both constraints didn't change since last pair processing, we can ignore the pair */
11677 if( consdata0->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE && consdata1->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE ) /*lint !e574*/
11678 continue;
11679
11680 assert(consdata1->nvars >= 1);
11681 assert(consdata1->merged);
11682
11683 /* sort the constraint */
11684 sortItems(consdata1);
11685
11686 /* see #2970 */
11687 if( consdata1->capacity == 0 )
11688 continue;
11689
11690 quotient = ((SCIP_Real) consdata0->capacity) / ((SCIP_Real) consdata1->capacity);
11691
11692 if( consdata0->nvars > consdata1->nvars )
11693 {
11694 iscons0incons1contained = FALSE;
11695 iscons1incons0contained = TRUE;
11696 v = consdata1->nvars - 1;
11697 }
11698 else if( consdata0->nvars < consdata1->nvars )
11699 {
11700 iscons0incons1contained = TRUE;
11701 iscons1incons0contained = FALSE;
11702 v = consdata0->nvars - 1;
11703 }
11704 else
11705 {
11706 iscons0incons1contained = TRUE;
11707 iscons1incons0contained = TRUE;
11708 v = consdata0->nvars - 1;
11709 }
11710
11711 SCIPdebugMsg(scip, "preprocess knapsack constraint pair <%s> and <%s>\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11712
11713 /* check consdata0 against consdata1:
11714 * 1. if all variables var_i of cons1 are in cons0 and for each of these variables
11715 * (consdata0->weights[i] / quotient) >= consdata1->weights[i] cons1 is redundant
11716 * 2. if all variables var_i of cons0 are in cons1 and for each of these variables
11717 * (consdata0->weights[i] / quotient) <= consdata1->weights[i] cons0 is redundant
11718 */
11719 v0 = consdata0->nvars - 1;
11720 v1 = consdata1->nvars - 1;
11721
11722 while( v >= 0 )
11723 {
11724 assert(iscons0incons1contained || iscons1incons0contained);
11725
11726 /* now there are more variables in cons1 left */
11727 if( v1 > v0 )
11728 {
11729 iscons1incons0contained = FALSE;
11730 if( !iscons0incons1contained )
11731 break;
11732 }
11733 /* now there are more variables in cons0 left */
11734 else if( v1 < v0 )
11735 {
11736 iscons0incons1contained = FALSE;
11737 if( !iscons1incons0contained )
11738 break;
11739 }
11740
11741 assert(v == v0 || v == v1);
11742 assert(v0 >= 0);
11743 assert(v1 >= 0);
11744
11745 /* both variables are the same */
11746 if( consdata0->vars[v0] == consdata1->vars[v1] )
11747 {
11748 /* if cons1 is possible contained in cons0 (consdata0->weights[v0] / quotient) must be greater equals consdata1->weights[v1] */
11749 if( iscons1incons0contained && SCIPisLT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11750 {
11751 iscons1incons0contained = FALSE;
11752 if( !iscons0incons1contained )
11753 break;
11754 }
11755 /* if cons0 is possible contained in cons1 (consdata0->weight[v0] / quotient) must be less equals consdata1->weight[v1] */
11756 else if( iscons0incons1contained && SCIPisGT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11757 {
11758 iscons0incons1contained = FALSE;
11759 if( !iscons1incons0contained )
11760 break;
11761 }
11762 --v0;
11763 --v1;
11764 --v;
11765 }
11766 else
11767 {
11768 /* both constraints have a variables which is not part of the other constraint, so stop */
11769 if( iscons0incons1contained && iscons1incons0contained )
11770 {
11771 iscons0incons1contained = FALSE;
11772 iscons1incons0contained = FALSE;
11773 break;
11774 }
11775 assert(iscons0incons1contained ? (v1 >= v0) : iscons1incons0contained);
11776 assert(iscons1incons0contained ? (v1 <= v0) : iscons0incons1contained);
11777 /* continue to the next variable */
11778 if( iscons0incons1contained )
11779 --v1;
11780 else
11781 --v0;
11782 }
11783 }
11784 /* neither one constraint was contained in another or we checked all variables of one constraint against the
11785 * other
11786 */
11787 assert(!iscons1incons0contained || !iscons0incons1contained || v0 == -1 || v1 == -1);
11788
11789 if( iscons1incons0contained )
11790 {
11791 SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons1));
11792 SCIPdebugPrintCons(scip, cons1, NULL);
11793
11794 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11795 SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
11796
11797 SCIP_CALL( SCIPdelCons(scip, cons1) );
11798 ++(*ndelconss);
11799 }
11800 else if( iscons0incons1contained )
11801 {
11802 SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons0));
11803 SCIPdebugPrintCons(scip, cons0, NULL);
11804
11805 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11806 SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
11807
11808 SCIP_CALL( SCIPdelCons(scip, cons0) );
11809 ++(*ndelconss);
11810 break;
11811 }
11812 }
11813
11814 return SCIP_OKAY;
11815}
11816
11817/** helper function to enforce constraints */
11818static
11820 SCIP* scip, /**< SCIP data structure */
11821 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11822 SCIP_CONS** conss, /**< constraints to process */
11823 int nconss, /**< number of constraints */
11824 int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
11825 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
11826 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
11827 )
11828{
11829 SCIP_CONSHDLRDATA* conshdlrdata;
11830 SCIP_Bool violated;
11831 SCIP_Bool cutoff = FALSE;
11832 int maxncuts;
11833 int ncuts = 0;
11834 int i;
11835
11836 *result = SCIP_FEASIBLE;
11837
11838 SCIPdebugMsg(scip, "knapsack enforcement of %d/%d constraints for %s solution\n", nusefulconss, nconss,
11839 sol == NULL ? "LP" : "relaxation");
11840
11841 /* get maximal number of cuts per round */
11842 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11843 assert(conshdlrdata != NULL);
11844 maxncuts = (SCIPgetDepth(scip) == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
11845
11846 /* search for violated useful knapsack constraints */
11847 for( i = 0; i < nusefulconss && ncuts < maxncuts && ! cutoff; i++ )
11848 {
11849 SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11850 if( violated )
11851 {
11852 /* add knapsack constraint as LP row to the relaxation */
11853 SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11854 ncuts++;
11855 }
11856 }
11857
11858 /* as long as no violations were found, search for violated obsolete knapsack constraints */
11859 for( i = nusefulconss; i < nconss && ncuts == 0 && ! cutoff; i++ )
11860 {
11861 SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11862 if( violated )
11863 {
11864 /* add knapsack constraint as LP row to the relaxation */
11865 SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11866 ncuts++;
11867 }
11868 }
11869
11870 /* adjust the result code */
11871 if ( cutoff )
11872 *result = SCIP_CUTOFF;
11873 else if ( ncuts > 0 )
11874 *result = SCIP_SEPARATED;
11875
11876 return SCIP_OKAY;
11877}
11878
11879/*
11880 * Linear constraint upgrading
11881 */
11882
11883/** creates and captures a knapsack constraint out of a linear inequality */
11884static
11886 SCIP* scip, /**< SCIP data structure */
11887 SCIP_CONS** cons, /**< pointer to hold the created constraint */
11888 const char* name, /**< name of constraint */
11889 int nvars, /**< number of variables in the constraint */
11890 SCIP_VAR** vars, /**< array with variables of constraint entries */
11891 SCIP_Real* vals, /**< array with inequality coefficients */
11892 SCIP_Real lhs, /**< left hand side of inequality */
11893 SCIP_Real rhs, /**< right hand side of inequality */
11894 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11895 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11896 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11897 * Usually set to TRUE. */
11898 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11899 * TRUE for model constraints, FALSE for additional, redundant constraints. */
11900 SCIP_Bool check, /**< should the constraint be checked for feasibility?
11901 * TRUE for model constraints, FALSE for additional, redundant constraints. */
11902 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11903 * Usually set to TRUE. */
11904 SCIP_Bool local, /**< is constraint only valid locally?
11905 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11906 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11907 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11908 * adds coefficients to this constraint. */
11909 SCIP_Bool dynamic, /**< is constraint subject to aging?
11910 * Usually set to FALSE. Set to TRUE for own cuts which
11911 * are separated as constraints. */
11912 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
11913 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11914 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
11915 * if it may be moved to a more global node?
11916 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
11917 )
11918{
11919 SCIP_VAR** transvars;
11920 SCIP_Longint* weights;
11921 SCIP_Longint capacity;
11922 SCIP_Longint weight;
11923 int mult;
11924 int v;
11925
11926 assert(nvars == 0 || vars != NULL);
11927 assert(nvars == 0 || vals != NULL);
11928 assert(SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11929
11930 /* get temporary memory */
11931 SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );
11933
11934 /* if the right hand side is non-infinite, we have to negate all variables with negative coefficient;
11935 * otherwise, we have to negate all variables with positive coefficient and multiply the row with -1
11936 */
11937 if( SCIPisInfinity(scip, rhs) )
11938 {
11939 mult = -1;
11940 capacity = (SCIP_Longint)SCIPfeasFloor(scip, -lhs);
11941 }
11942 else
11943 {
11944 mult = +1;
11945 capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
11946 }
11947
11948 /* negate positive or negative variables */
11949 for( v = 0; v < nvars; ++v )
11950 {
11951 assert(SCIPisFeasIntegral(scip, vals[v]));
11952 weight = mult * (SCIP_Longint)SCIPfeasFloor(scip, vals[v]);
11953 if( weight > 0 )
11954 {
11955 transvars[v] = vars[v];
11956 weights[v] = weight;
11957 }
11958 else
11959 {
11960 SCIP_CALL( SCIPgetNegatedVar(scip, vars[v], &transvars[v]) );
11961 weights[v] = -weight; /*lint !e2704*/
11962 capacity -= weight;
11963 }
11964 assert(transvars[v] != NULL);
11965 }
11966
11967 /* create the constraint */
11968 SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, transvars, weights, capacity,
11969 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
11970
11971 /* free temporary memory */
11972 SCIPfreeBufferArray(scip, &weights);
11973 SCIPfreeBufferArray(scip, &transvars);
11974
11975 return SCIP_OKAY;
11976}
11977
11978/** tries to upgrade a linear constraint into a knapsack constraint */
11979static
11980SCIP_DECL_LINCONSUPGD(linconsUpgdKnapsack)
11981{ /*lint --e{715}*/
11982 SCIP_Bool upgrade;
11983
11984 assert(upgdcons != NULL);
11985
11986 /* check, if linear constraint can be upgraded to a knapsack constraint
11987 * - all variables must be binary
11988 * - all coefficients must be integral
11989 * - exactly one of the sides must be infinite
11990 * note that this includes the case of negative capacity, which has been
11991 * observed to occur, e.g., when upgrading a conflict constraint
11992 */
11993 upgrade = (nposbin + nnegbin + nposimplbin + nnegimplbin == nvars)
11994 && (ncoeffspone + ncoeffsnone + ncoeffspint + ncoeffsnint == nvars)
11995 && (SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11996
11997 if( upgrade )
11998 {
11999 SCIPdebugMsg(scip, "upgrading constraint <%s> to knapsack constraint\n", SCIPconsGetName(cons));
12000
12001 /* create the knapsack constraint (an automatically upgraded constraint is always unmodifiable) */
12002 assert(!SCIPconsIsModifiable(cons));
12003 SCIP_CALL( createNormalizedKnapsack(scip, upgdcons, SCIPconsGetName(cons), nvars, vars, vals, lhs, rhs,
12008 }
12009
12010 return SCIP_OKAY;
12011}
12012
12013/** adds symmetry information of constraint to a symmetry detection graph */
12014static
12016 SCIP* scip, /**< SCIP pointer */
12017 SYM_SYMTYPE symtype, /**< type of symmetries that need to be added */
12018 SCIP_CONS* cons, /**< constraint */
12019 SYM_GRAPH* graph, /**< symmetry detection graph */
12020 SCIP_Bool* success /**< pointer to store whether symmetry information could be added */
12021 )
12022{
12023 SCIP_CONSDATA* consdata;
12024 SCIP_VAR** vars;
12025 SCIP_Real* vals;
12026 SCIP_Real constant = 0.0;
12027 SCIP_Real rhs;
12028 int nlocvars;
12029 int nvars;
12030 int i;
12031
12032 assert(scip != NULL);
12033 assert(cons != NULL);
12034 assert(graph != NULL);
12035 assert(success != NULL);
12036
12037 consdata = SCIPconsGetData(cons);
12038 assert(consdata != NULL);
12039 assert(graph != NULL);
12040
12041 /* get active variables of the constraint */
12043 nlocvars = consdata->nvars;
12044
12047
12048 for( i = 0; i < consdata->nvars; ++i )
12049 {
12050 vars[i] = consdata->vars[i];
12051 vals[i] = (SCIP_Real) consdata->weights[i];
12052 }
12053
12054 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &vars, &vals, &nlocvars, &constant, SCIPisTransformed(scip)) );
12055 rhs = (SCIP_Real) SCIPgetCapacityKnapsack(scip, cons) - constant;
12056
12057 SCIP_CALL( SCIPextendPermsymDetectionGraphLinear(scip, graph, vars, vals, nlocvars,
12058 cons, -SCIPinfinity(scip), rhs, success) );
12059
12060 SCIPfreeBufferArray(scip, &vals);
12061 SCIPfreeBufferArray(scip, &vars);
12062
12063 return SCIP_OKAY;
12064}
12065
12066/*
12067 * Callback methods of constraint handler
12068 */
12069
12070/** copy method for constraint handler plugins (called when SCIP copies plugins) */
12071/**! [SnippetConsCopyKnapsack] */
12072static
12073SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack)
12074{ /*lint --e{715}*/
12075 assert(scip != NULL);
12076 assert(conshdlr != NULL);
12077 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12078
12079 /* call inclusion method of constraint handler */
12081
12082 *valid = TRUE;
12083
12084 return SCIP_OKAY;
12085}
12086/**! [SnippetConsCopyKnapsack] */
12087
12088/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12089/**! [SnippetConsFreeKnapsack] */
12090static
12091SCIP_DECL_CONSFREE(consFreeKnapsack)
12092{ /*lint --e{715}*/
12093 SCIP_CONSHDLRDATA* conshdlrdata;
12094
12095 /* free constraint handler data */
12096 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12097 assert(conshdlrdata != NULL);
12098
12099 SCIPfreeBlockMemory(scip, &conshdlrdata);
12100
12101 SCIPconshdlrSetData(conshdlr, NULL);
12102
12103 return SCIP_OKAY;
12104}
12105/**! [SnippetConsFreeKnapsack] */
12106
12107
12108/** initialization method of constraint handler (called after problem was transformed) */
12109static
12110SCIP_DECL_CONSINIT(consInitKnapsack)
12111{ /*lint --e{715}*/
12112 SCIP_CONSHDLRDATA* conshdlrdata;
12113 int nvars;
12114
12115 assert( scip != NULL );
12116 assert( conshdlr != NULL );
12117
12118 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12119 assert(conshdlrdata != NULL);
12120
12121 /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12123
12124 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->reals1, nvars) );
12125 conshdlrdata->reals1size = nvars;
12126
12127 return SCIP_OKAY;
12128}
12129
12130/** deinitialization method of constraint handler (called before transformed problem is freed) */
12131static
12132SCIP_DECL_CONSEXIT(consExitKnapsack)
12133{ /*lint --e{715}*/
12134 SCIP_CONSHDLRDATA* conshdlrdata;
12135
12136 assert( scip != NULL );
12137 assert( conshdlr != NULL );
12138
12139 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12140 assert(conshdlrdata != NULL);
12141
12142 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->reals1, conshdlrdata->reals1size);
12143 conshdlrdata->reals1size = 0;
12144
12145 return SCIP_OKAY;
12146}
12147
12148
12149/** presolving initialization method of constraint handler (called when presolving is about to begin) */
12150static
12151SCIP_DECL_CONSINITPRE(consInitpreKnapsack)
12152{ /*lint --e{715}*/
12153 SCIP_CONSHDLRDATA* conshdlrdata;
12154 int nvars;
12155
12156 assert(scip != NULL);
12157 assert(conshdlr != NULL);
12158 assert(nconss == 0 || conss != NULL);
12159
12160 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12161 assert(conshdlrdata != NULL);
12162
12163 /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12165
12166 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints1, nvars) );
12167 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints2, nvars) );
12168 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints1, nvars) );
12169 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints2, nvars) );
12170 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools1, nvars) );
12171 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools2, nvars) );
12172 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools3, nvars) );
12173 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools4, nvars) );
12174
12175 conshdlrdata->ints1size = nvars;
12176 conshdlrdata->ints2size = nvars;
12177 conshdlrdata->longints1size = nvars;
12178 conshdlrdata->longints2size = nvars;
12179 conshdlrdata->bools1size = nvars;
12180 conshdlrdata->bools2size = nvars;
12181 conshdlrdata->bools3size = nvars;
12182 conshdlrdata->bools4size = nvars;
12183
12184#ifdef WITH_CARDINALITY_UPGRADE
12185 conshdlrdata->upgradedcard = FALSE;
12186#endif
12187
12188 return SCIP_OKAY;
12189}
12190
12191
12192/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12193static
12194SCIP_DECL_CONSEXITPRE(consExitpreKnapsack)
12195{ /*lint --e{715}*/
12196 SCIP_CONSHDLRDATA* conshdlrdata;
12197 int c;
12198
12199 assert(scip != NULL);
12200 assert(conshdlr != NULL);
12201
12202 for( c = 0; c < nconss; ++c )
12203 {
12204 if( !SCIPconsIsDeleted(conss[c]) )
12205 {
12206 /* since we are not allowed to detect infeasibility in the exitpre stage, we dont give an infeasible pointer */
12207 SCIP_CALL( applyFixings(scip, conss[c], NULL) );
12208 }
12209 }
12210
12211 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12212 assert(conshdlrdata != NULL);
12213
12214 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints1, conshdlrdata->ints1size);
12215 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints2, conshdlrdata->ints2size);
12216 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints1, conshdlrdata->longints1size);
12217 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints2, conshdlrdata->longints2size);
12218 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools1, conshdlrdata->bools1size);
12219 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools2, conshdlrdata->bools2size);
12220 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools3, conshdlrdata->bools3size);
12221 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools4, conshdlrdata->bools4size);
12222
12223 conshdlrdata->ints1size = 0;
12224 conshdlrdata->ints2size = 0;
12225 conshdlrdata->longints1size = 0;
12226 conshdlrdata->longints2size = 0;
12227 conshdlrdata->bools1size = 0;
12228 conshdlrdata->bools2size = 0;
12229 conshdlrdata->bools3size = 0;
12230 conshdlrdata->bools4size = 0;
12231
12232 return SCIP_OKAY;
12233}
12234
12235/** solving process initialization method of constraint handler */
12236static
12237SCIP_DECL_CONSINITSOL(consInitsolKnapsack)
12238{ /*lint --e{715}*/
12239 /* add nlrow representation to NLP, if NLP had been constructed */
12241 {
12242 int c;
12243 for( c = 0; c < nconss; ++c )
12244 {
12245 SCIP_CALL( addNlrow(scip, conss[c]) );
12246 }
12247 }
12248
12249 return SCIP_OKAY;
12250}
12251
12252/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12253static
12254SCIP_DECL_CONSEXITSOL(consExitsolKnapsack)
12255{ /*lint --e{715}*/
12256 SCIP_CONSDATA* consdata;
12257 int c;
12258
12259 assert( scip != NULL );
12260
12261 /* release the rows and nlrows of all constraints */
12262 for( c = 0; c < nconss; ++c )
12263 {
12264 consdata = SCIPconsGetData(conss[c]);
12265 assert(consdata != NULL);
12266
12267 if( consdata->row != NULL )
12268 {
12269 SCIP_CALL( SCIPreleaseRow(scip, &consdata->row) );
12270 }
12271
12272 if( consdata->nlrow != NULL )
12273 {
12274 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
12275 }
12276 }
12277
12278 return SCIP_OKAY;
12279}
12280
12281/** frees specific constraint data */
12282static
12283SCIP_DECL_CONSDELETE(consDeleteKnapsack)
12284{ /*lint --e{715}*/
12285 SCIP_CONSHDLRDATA* conshdlrdata;
12286
12287 assert(conshdlr != NULL);
12288 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12289
12290 /* get event handler */
12291 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12292 assert(conshdlrdata != NULL);
12293 assert(conshdlrdata->eventhdlr != NULL);
12294
12295 /* free knapsack constraint */
12296 SCIP_CALL( consdataFree(scip, consdata, conshdlrdata->eventhdlr) );
12297
12298 return SCIP_OKAY;
12299}
12300
12301/** transforms constraint data into data belonging to the transformed problem */
12302/**! [SnippetConsTransKnapsack]*/
12303static
12304SCIP_DECL_CONSTRANS(consTransKnapsack)
12305{ /*lint --e{715}*/
12306 SCIP_CONSHDLRDATA* conshdlrdata;
12307 SCIP_CONSDATA* sourcedata;
12308 SCIP_CONSDATA* targetdata;
12309
12310 assert(conshdlr != NULL);
12311 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12313 assert(sourcecons != NULL);
12314 assert(targetcons != NULL);
12315
12316 sourcedata = SCIPconsGetData(sourcecons);
12317 assert(sourcedata != NULL);
12318 assert(sourcedata->row == NULL); /* in original problem, there cannot be LP rows */
12319
12320 /* get event handler */
12321 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12322 assert(conshdlrdata != NULL);
12323 assert(conshdlrdata->eventhdlr != NULL);
12324
12325 /* create target constraint data */
12326 SCIP_CALL( consdataCreate(scip, &targetdata,
12327 sourcedata->nvars, sourcedata->vars, sourcedata->weights, sourcedata->capacity) );
12328
12329 /* create target constraint */
12330 SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12331 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12332 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12333 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12334 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12335
12336 /* catch events for variables */
12337 SCIP_CALL( catchEvents(scip, *targetcons, targetdata, conshdlrdata->eventhdlr) );
12338
12339 return SCIP_OKAY;
12340}
12341/**! [SnippetConsTransKnapsack]*/
12342
12343/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
12344static
12345SCIP_DECL_CONSINITLP(consInitlpKnapsack)
12346{ /*lint --e{715}*/
12347 int i;
12348
12349 *infeasible = FALSE;
12350
12351 for( i = 0; i < nconss && !(*infeasible); i++ )
12352 {
12353 assert(SCIPconsIsInitial(conss[i]));
12354 SCIP_CALL( addRelaxation(scip, conss[i], infeasible) );
12355 }
12356
12357 return SCIP_OKAY;
12358}
12359
12360/** separation method of constraint handler for LP solutions */
12361static
12362SCIP_DECL_CONSSEPALP(consSepalpKnapsack)
12363{ /*lint --e{715}*/
12364 SCIP_CONSHDLRDATA* conshdlrdata;
12365 SCIP_Bool sepacardinality;
12366 SCIP_Bool cutoff;
12367
12368 SCIP_Real loclowerbound;
12369 SCIP_Real glblowerbound;
12370 SCIP_Real cutoffbound;
12371 SCIP_Real maxbound;
12372
12373 int depth;
12374 int nrounds;
12375 int sepafreq;
12376 int sepacardfreq;
12377 int ncuts;
12378 int maxsepacuts;
12379 int i;
12380
12381 *result = SCIP_DIDNOTRUN;
12382
12383 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12384 assert(conshdlrdata != NULL);
12385
12386 depth = SCIPgetDepth(scip);
12387 nrounds = SCIPgetNSepaRounds(scip);
12388
12389 SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12390 nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12391
12392 /* only call the separator a given number of times at each node */
12393 if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12394 || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12395 return SCIP_OKAY;
12396
12397 /* check, if we should additionally separate knapsack cuts */
12398 sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12399 sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12400 sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12401 && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12402
12403 /* check dual bound to see if we want to produce knapsack cuts at this node */
12404 loclowerbound = SCIPgetLocalLowerbound(scip);
12405 glblowerbound = SCIPgetLowerbound(scip);
12406 cutoffbound = SCIPgetCutoffbound(scip);
12407 maxbound = glblowerbound + conshdlrdata->maxcardbounddist * (cutoffbound - glblowerbound);
12408 sepacardinality = sepacardinality && SCIPisLE(scip, loclowerbound, maxbound);
12409 sepacardinality = sepacardinality && (SCIPgetNLPBranchCands(scip) > 0);
12410
12411 /* get the maximal number of cuts allowed in a separation round */
12412 maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12413
12414 *result = SCIP_DIDNOTFIND;
12415 ncuts = 0;
12416 cutoff = FALSE;
12417
12418 /* separate useful constraints */
12419 for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12420 {
12421 SCIP_CALL( separateCons(scip, conss[i], NULL, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12422 }
12423
12424 /* adjust return value */
12425 if ( cutoff )
12426 *result = SCIP_CUTOFF;
12427 else if ( ncuts > 0 )
12428 *result = SCIP_SEPARATED;
12429
12430 return SCIP_OKAY;
12431}
12432
12433
12434/** separation method of constraint handler for arbitrary primal solutions */
12435static
12436SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
12437{ /*lint --e{715}*/
12438 SCIP_CONSHDLRDATA* conshdlrdata;
12439 SCIP_Bool sepacardinality;
12440 SCIP_Bool cutoff;
12441
12442 int depth;
12443 int nrounds;
12444 int sepafreq;
12445 int sepacardfreq;
12446 int ncuts;
12447 int maxsepacuts;
12448 int i;
12449
12450 *result = SCIP_DIDNOTRUN;
12451
12452 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12453 assert(conshdlrdata != NULL);
12454
12455 depth = SCIPgetDepth(scip);
12456 nrounds = SCIPgetNSepaRounds(scip);
12457
12458 SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12459 nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12460
12461 /* only call the separator a given number of times at each node */
12462 if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12463 || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12464 return SCIP_OKAY;
12465
12466 /* check, if we should additionally separate knapsack cuts */
12467 sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12468 sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12469 sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12470 && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12471
12472 /* get the maximal number of cuts allowed in a separation round */
12473 maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12474
12475 *result = SCIP_DIDNOTFIND;
12476 ncuts = 0;
12477 cutoff = FALSE;
12478
12479 /* separate useful constraints */
12480 for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12481 {
12482 SCIP_CALL( separateCons(scip, conss[i], sol, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12483 }
12484
12485 /* adjust return value */
12486 if ( cutoff )
12487 *result = SCIP_CUTOFF;
12488 else if( ncuts > 0 )
12489 *result = SCIP_SEPARATED;
12490
12491 return SCIP_OKAY;
12492}
12493
12494/** constraint enforcing method of constraint handler for LP solutions */
12495static
12496SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
12497{ /*lint --e{715}*/
12498 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, result) );
12499
12500 return SCIP_OKAY;
12501}
12502
12503/** constraint enforcing method of constraint handler for relaxation solutions */
12504static
12505SCIP_DECL_CONSENFORELAX(consEnforelaxKnapsack)
12506{ /*lint --e{715}*/
12507 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, result) );
12508
12509 return SCIP_OKAY;
12510}
12511
12512/** constraint enforcing method of constraint handler for pseudo solutions */
12513static
12514SCIP_DECL_CONSENFOPS(consEnfopsKnapsack)
12515{ /*lint --e{715}*/
12516 SCIP_Bool violated;
12517 int i;
12518
12519 for( i = 0; i < nconss; i++ )
12520 {
12521 SCIP_CALL( checkCons(scip, conss[i], NULL, TRUE, FALSE, &violated) );
12522 if( violated )
12523 {
12524 *result = SCIP_INFEASIBLE;
12525 return SCIP_OKAY;
12526 }
12527 }
12528 *result = SCIP_FEASIBLE;
12529
12530 return SCIP_OKAY;
12531}
12532
12533/** feasibility check method of constraint handler for integral solutions */
12534static
12535SCIP_DECL_CONSCHECK(consCheckKnapsack)
12536{ /*lint --e{715}*/
12537 SCIP_Bool violated;
12538 int i;
12539
12540 *result = SCIP_FEASIBLE;
12541
12542 for( i = 0; i < nconss && (*result == SCIP_FEASIBLE || completely); i++ )
12543 {
12544 SCIP_CALL( checkCons(scip, conss[i], sol, checklprows, printreason, &violated) );
12545 if( violated )
12546 *result = SCIP_INFEASIBLE;
12547 }
12548
12549 return SCIP_OKAY;
12550}
12551
12552/** domain propagation method of constraint handler */
12553static
12554SCIP_DECL_CONSPROP(consPropKnapsack)
12555{ /*lint --e{715}*/
12556 SCIP_CONSHDLRDATA* conshdlrdata;
12557 SCIP_Bool cutoff;
12558 SCIP_Bool redundant;
12559 SCIP_Bool inpresolve;
12560 int nfixedvars;
12561 int i;
12562
12563 cutoff = FALSE;
12564 nfixedvars = 0;
12565
12566 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12567 assert(conshdlrdata != NULL);
12568
12569 inpresolve = (SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE);
12570 assert(!inpresolve || SCIPinProbing(scip));
12571
12572 /* process useful constraints */
12573 for( i = 0; i < nmarkedconss && !cutoff; i++ )
12574 {
12575 /* do not propagate constraints with multi-aggregated variables, which should only happen in probing mode,
12576 * otherwise the multi-aggregation should be resolved
12577 */
12578 if( inpresolve && SCIPconsGetData(conss[i])->existmultaggr )
12579 continue;
12580#ifndef NDEBUG
12581 else
12582 assert(!(SCIPconsGetData(conss[i])->existmultaggr));
12583#endif
12584
12585 SCIP_CALL( propagateCons(scip, conss[i], &cutoff, &redundant, &nfixedvars, conshdlrdata->negatedclique) );
12586
12587 /* unmark the constraint to be propagated */
12589 }
12590
12591 /* adjust result code */
12592 if( cutoff )
12593 *result = SCIP_CUTOFF;
12594 else if( nfixedvars > 0 )
12595 *result = SCIP_REDUCEDDOM;
12596 else
12597 *result = SCIP_DIDNOTFIND;
12598
12599 return SCIP_OKAY; /*lint !e438*/
12600}
12601
12602/** presolving method of constraint handler */
12603static
12604SCIP_DECL_CONSPRESOL(consPresolKnapsack)
12605{ /*lint --e{574,715}*/
12606 SCIP_CONSHDLRDATA* conshdlrdata;
12607 SCIP_CONSDATA* consdata;
12608 SCIP_CONS* cons;
12609 SCIP_Bool cutoff;
12610 SCIP_Bool redundant;
12611 SCIP_Bool success;
12612 int oldnfixedvars;
12613 int oldnchgbds;
12614 int oldndelconss;
12615 int oldnaddconss;
12616 int oldnchgcoefs;
12617 int oldnchgsides;
12618 int firstchange;
12619 int c;
12620 SCIP_Bool newchanges;
12621
12622 /* remember old preprocessing counters */
12623 cutoff = FALSE;
12624 oldnfixedvars = *nfixedvars;
12625 oldnchgbds = *nchgbds;
12626 oldndelconss = *ndelconss;
12627 oldnaddconss = *naddconss;
12628 oldnchgcoefs = *nchgcoefs;
12629 oldnchgsides = *nchgsides;
12630 firstchange = INT_MAX;
12631
12632 newchanges = (nrounds == 0 || nnewfixedvars > 0 || nnewaggrvars > 0 || nnewchgbds > 0 || nnewupgdconss > 0);
12633
12634 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12635 assert(conshdlrdata != NULL);
12636
12637 for( c = 0; c < nconss && !SCIPisStopped(scip); c++ )
12638 {
12639 int thisnfixedvars;
12640 int thisnchgbds;
12641
12642 cons = conss[c];
12643 consdata = SCIPconsGetData(cons);
12644 assert(consdata != NULL);
12645
12646 /* update data structures */
12647 /* todo if UBTIGHTENED events were caught, we could move this block after the continue */
12648 if( newchanges || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12649 {
12650 SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12651 if( cutoff )
12652 break;
12653 }
12654
12655 /* force presolving the constraint in the initial round */
12656 if( nrounds == 0 )
12657 consdata->presolvedtiming = 0;
12658 else if( consdata->presolvedtiming >= presoltiming )
12659 continue;
12660
12661 SCIPdebugMsg(scip, "presolving knapsack constraint <%s>\n", SCIPconsGetName(cons));
12663 consdata->presolvedtiming = presoltiming;
12664
12665 thisnfixedvars = *nfixedvars;
12666 thisnchgbds = *nchgbds;
12667
12668 /* merge constraint, so propagation works better */
12669 SCIP_CALL( mergeMultiples(scip, cons, &cutoff) );
12670 if( cutoff )
12671 break;
12672
12673 /* add cliques in the knapsack to the clique table */
12674 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12675 {
12676 SCIP_CALL( addCliques(scip, cons, conshdlrdata->cliqueextractfactor, &cutoff, nchgbds) );
12677 if( cutoff )
12678 break;
12679 }
12680
12681 /* propagate constraint */
12682 if( presoltiming < SCIP_PRESOLTIMING_EXHAUSTIVE )
12683 {
12684 SCIP_CALL( propagateCons(scip, cons, &cutoff, &redundant, nfixedvars, (presoltiming & SCIP_PRESOLTIMING_MEDIUM)) );
12685
12686 if( cutoff )
12687 break;
12688 if( redundant )
12689 {
12690 (*ndelconss)++;
12691 continue;
12692 }
12693 }
12694
12695 /* remove again all fixed variables, if further fixings were found */
12696 if( *nfixedvars > thisnfixedvars || *nchgbds > thisnchgbds )
12697 {
12698 SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12699 if( cutoff )
12700 break;
12701
12702 thisnfixedvars = *nfixedvars;
12703 }
12704
12705 if( !SCIPconsIsModifiable(cons) )
12706 {
12707 /* check again for redundancy (applyFixings() might have decreased weightsum due to fixed-to-zero vars) */
12708 if( consdata->weightsum <= consdata->capacity )
12709 {
12710 SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
12711 SCIPconsGetName(cons), consdata->weightsum, consdata->capacity);
12713 continue;
12714 }
12715
12716 /* divide weights by their greatest common divisor */
12717 normalizeWeights(cons, nchgcoefs, nchgsides);
12718
12719 /* try to simplify inequalities */
12720 if( conshdlrdata->simplifyinequalities && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
12721 {
12722 SCIP_CALL( simplifyInequalities(scip, cons, nfixedvars, ndelconss, nchgcoefs, nchgsides, naddconss, &cutoff) );
12723 if( cutoff )
12724 break;
12725
12726 if( SCIPconsIsDeleted(cons) )
12727 continue;
12728
12729 /* remove again all fixed variables, if further fixings were found */
12730 if( *nfixedvars > thisnfixedvars )
12731 {
12732 SCIP_CALL(applyFixings(scip, cons, &cutoff));
12733 if( cutoff )
12734 break;
12735 }
12736 }
12737
12738 /* tighten capacity and weights */
12739 SCIP_CALL( tightenWeights(scip, cons, presoltiming, nchgcoefs, nchgsides, naddconss, ndelconss, &cutoff) );
12740 if( cutoff )
12741 break;
12742
12743 if( SCIPconsIsActive(cons) )
12744 {
12745 if( conshdlrdata->dualpresolving && SCIPallowStrongDualReds(scip) && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12746 {
12747 /* in case the knapsack constraints is independent of everything else, solve the knapsack and apply the
12748 * dual reduction
12749 */
12750 SCIP_CALL( dualPresolving(scip, cons, nchgbds, ndelconss, &redundant) );
12751 if( redundant )
12752 continue;
12753 }
12754
12755 /* check if knapsack constraint is parallel to objective function */
12756 SCIP_CALL( checkParallelObjective(scip, cons, conshdlrdata) );
12757 }
12758 }
12759 /* remember the first changed constraint to begin the next aggregation round with */
12760 if( firstchange == INT_MAX && consdata->presolvedtiming != SCIP_PRESOLTIMING_EXHAUSTIVE )
12761 firstchange = c;
12762 }
12763
12764 /* preprocess pairs of knapsack constraints */
12765 if( !cutoff && conshdlrdata->presolusehashing && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12766 {
12767 /* detect redundant constraints; fast version with hash table instead of pairwise comparison */
12768 SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &cutoff, ndelconss) );
12769 }
12770
12771 if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) || (*naddconss != oldnaddconss) )
12772 success = TRUE;
12773 else
12774 success = FALSE;
12775
12776 if( !cutoff && firstchange < nconss && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
12777 {
12778 SCIP_Longint npaircomparisons;
12779
12780 npaircomparisons = 0;
12781 oldndelconss = *ndelconss;
12782 oldnchgsides = *nchgsides;
12783 oldnchgcoefs = *nchgcoefs;
12784
12785 for( c = firstchange; c < nconss && !cutoff && !SCIPisStopped(scip); ++c )
12786 {
12787 cons = conss[c];
12788 if( !SCIPconsIsActive(cons) || SCIPconsIsModifiable(cons) )
12789 continue;
12790
12791 npaircomparisons += ((SCIPconsGetData(cons)->presolvedtiming < SCIP_PRESOLTIMING_EXHAUSTIVE) ? (SCIP_Longint) c : ((SCIP_Longint) c - (SCIP_Longint) firstchange));
12792
12793 SCIP_CALL( preprocessConstraintPairs(scip, conss, firstchange, c, ndelconss) );
12794
12795 if( npaircomparisons > NMINCOMPARISONS )
12796 {
12797 if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) )
12798 success = TRUE;
12799 if( ((SCIP_Real) (*ndelconss - oldndelconss) + ((SCIP_Real) (*nchgsides - oldnchgsides))/2.0 +
12800 ((SCIP_Real) (*nchgcoefs - oldnchgcoefs))/10.0) / ((SCIP_Real) npaircomparisons) < MINGAINPERNMINCOMPARISONS )
12801 break;
12802 oldndelconss = *ndelconss;
12803 oldnchgsides = *nchgsides;
12804 oldnchgcoefs = *nchgcoefs;
12805 npaircomparisons = 0;
12806 }
12807 }
12808 }
12809#ifdef WITH_CARDINALITY_UPGRADE
12810 /* @todo upgrade to cardinality constraints: the code below relies on disabling the checking of the knapsack
12811 * constraint in the original problem, because the upgrade ensures that at most the given number of continuous
12812 * variables has a nonzero value, but not that the binary variables corresponding to the continuous variables with
12813 * value zero are set to zero as well. This can cause problems if the user accesses the values of the binary
12814 * variables (as the MIPLIB solution checker does), or the transformed problem is freed and the original problem
12815 * (possibly with some user modifications) is re-optimized. Until there is a way to force the binary variables to 0
12816 * as well, we better keep this code disabled. */
12817 /* upgrade to cardinality constraints - only try to upgrade towards the end of presolving, since the process below is quite expensive */
12818 if ( ! cutoff && conshdlrdata->upgdcardinality && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 && SCIPisPresolveFinished(scip) && ! conshdlrdata->upgradedcard )
12819 {
12820 SCIP_HASHMAP* varhash;
12821 SCIP_VAR** cardvars;
12822 SCIP_Real* cardweights;
12823 int noldupgdconss;
12824 int nscipvars;
12825 int makeupgrade;
12826
12827 noldupgdconss = *nupgdconss;
12828 nscipvars = SCIPgetNVars(scip);
12829 SCIP_CALL( SCIPallocClearBufferArray(scip, &cardvars, nscipvars) );
12830 SCIP_CALL( SCIPallocClearBufferArray(scip, &cardweights, nscipvars) );
12831
12832 /* set up hash map */
12833 SCIP_CALL( SCIPhashmapCreate(&varhash, SCIPblkmem(scip), nscipvars) );
12834
12835 /* We loop through all cardinality constraints twice:
12836 * - First, determine for each binary variable the number of cardinality constraints that can be upgraded to a
12837 * knapsack constraint and contain this variable; this number has to coincide with the number of variable up
12838 * locks; otherwise it would be infeasible to delete the knapsack constraints after the constraint update.
12839 * - Second, upgrade knapsack constraints to cardinality constraints. */
12840 for (makeupgrade = 0; makeupgrade < 2; ++makeupgrade)
12841 {
12842 for (c = nconss-1; c >= 0 && ! SCIPisStopped(scip); --c)
12843 {
12844 SCIP_CONS* cardcons;
12845 SCIP_VAR** vars;
12846 SCIP_Longint* weights;
12847 int nvars;
12848 int v;
12849
12850 cons = conss[c];
12851 assert( cons != NULL );
12852 consdata = SCIPconsGetData(cons);
12853 assert( consdata != NULL );
12854
12855 nvars = consdata->nvars;
12856 vars = consdata->vars;
12857 weights = consdata->weights;
12858
12859 /* Check, whether linear knapsack can be upgraded to a cardinality constraint:
12860 * - all variables must be binary (always true)
12861 * - all coefficients must be 1.0
12862 * - the right hand side must be smaller than nvars
12863 */
12864 if ( consdata->capacity >= nvars )
12865 continue;
12866
12867 /* the weights are sorted: check first and last weight */
12868 assert( consdata->sorted );
12869 if ( weights[0] != 1 || weights[nvars-1] != 1 )
12870 continue;
12871
12872 /* check whether all variables are of the form 0 <= x_v <= u_v y_v for y_v \in \{0,1\} and zero objective */
12873 for (v = 0; v < nvars; ++v)
12874 {
12875 SCIP_BOUNDTYPE* impltypes;
12876 SCIP_Real* implbounds;
12877 SCIP_VAR** implvars;
12878 SCIP_VAR* var;
12879 int nimpls;
12880 int j;
12881
12882 var = consdata->vars[v];
12883 assert( var != NULL );
12884 assert( SCIPvarIsBinary(var) );
12885
12886 /* ignore non-active variables */
12887 if ( ! SCIPvarIsActive(var) )
12888 break;
12889
12890 /* be sure that implication variable has zero objective */
12891 if ( ! SCIPisZero(scip, SCIPvarGetObj(var)) )
12892 break;
12893
12894 nimpls = SCIPvarGetNImpls(var, FALSE);
12895 implvars = SCIPvarGetImplVars(var, FALSE);
12896 implbounds = SCIPvarGetImplBounds(var, FALSE);
12897 impltypes = SCIPvarGetImplTypes(var, FALSE);
12898
12899 for (j = 0; j < nimpls; ++j)
12900 {
12901 /* be sure that continuous variable is fixed to 0 */
12902 if ( impltypes[j] != SCIP_BOUNDTYPE_UPPER )
12903 continue;
12904
12905 /* cannot currently deal with nonzero fixings */
12906 if ( ! SCIPisZero(scip, implbounds[j]) )
12907 continue;
12908
12909 /* number of down locks should be one */
12910 if ( SCIPvarGetNLocksDownType(vars[v], SCIP_LOCKTYPE_MODEL) != 1 )
12911 continue;
12912
12913 cardvars[v] = implvars[j];
12914 cardweights[v] = (SCIP_Real) v;
12915
12916 break;
12917 }
12918
12919 /* found no variable upper bound candidate -> exit */
12920 if ( j >= nimpls )
12921 break;
12922 }
12923
12924 /* did not find fitting variable upper bound for some variable -> exit */
12925 if ( v < nvars )
12926 break;
12927
12928 /* save number of knapsack constraints that can be upgraded to a cardinality constraint,
12929 * in which the binary variable is involved in */
12930 if ( makeupgrade == 0 )
12931 {
12932 for (v = 0; v < nvars; ++v)
12933 {
12934 if ( SCIPhashmapExists(varhash, vars[v]) )
12935 {
12936 int image;
12937
12938 image = SCIPhashmapGetImageInt(varhash, vars[v]);
12939 SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image + 1) );
12940 assert( image + 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12941 }
12942 else
12943 {
12944 SCIP_CALL( SCIPhashmapInsertInt(varhash, vars[v], 1) );
12945 assert( 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12946 assert( SCIPhashmapExists(varhash, vars[v]) );
12947 }
12948 }
12949 }
12950 else
12951 {
12952 SCIP_CONS* origcons;
12953
12954 /* for each variable: check whether the number of cardinality constraints that can be upgraded to a
12955 * knapsack constraint coincides with the number of variable up locks */
12956 for (v = 0; v < nvars; ++v)
12957 {
12958 assert( SCIPhashmapExists(varhash, vars[v]) );
12959 if ( SCIPvarGetNLocksUpType(vars[v], SCIP_LOCKTYPE_MODEL) != SCIPhashmapGetImageInt(varhash, vars[v]) )
12960 break;
12961 }
12962 if ( v < nvars )
12963 break;
12964
12965 /* store that we have upgraded */
12966 conshdlrdata->upgradedcard = TRUE;
12967
12968 /* at this point we found suitable variable upper bounds */
12969 SCIPdebugMessage("Upgrading knapsack constraint <%s> to cardinality constraint ...\n", SCIPconsGetName(cons));
12970
12971 /* create cardinality constraint */
12972 assert( ! SCIPconsIsModifiable(cons) );
12973 SCIP_CALL( SCIPcreateConsCardinality(scip, &cardcons, SCIPconsGetName(cons), nvars, cardvars, (int) consdata->capacity, vars, cardweights,
12977#ifdef SCIP_DEBUG
12978 SCIPprintCons(scip, cons, NULL);
12979 SCIPinfoMessage(scip, NULL, "\n");
12980 SCIPprintCons(scip, cardcons, NULL);
12981 SCIPinfoMessage(scip, NULL, "\n");
12982#endif
12983 SCIP_CALL( SCIPaddCons(scip, cardcons) );
12984 SCIP_CALL( SCIPreleaseCons(scip, &cardcons) );
12985 ++(*nupgdconss);
12986
12987 /* delete oknapsack constraint */
12988 SCIP_CALL( SCIPdelCons(scip, cons) );
12989 ++(*ndelconss);
12990
12991 /* We need to disable the original knapsack constraint, since it might happen that the binary variables
12992 * are 1 although the continuous variables are 0. Thus, the knapsack constraint might be violated,
12993 * although the cardinality constraint is satisfied. */
12994 origcons = SCIPfindOrigCons(scip, SCIPconsGetName(cons));
12995 assert( origcons != NULL );
12996 SCIP_CALL( SCIPsetConsChecked(scip, origcons, FALSE) );
12997
12998 for (v = 0; v < nvars; ++v)
12999 {
13000 int image;
13001
13002 assert ( SCIPhashmapExists(varhash, vars[v]) );
13003 image = SCIPhashmapGetImageInt(varhash, vars[v]);
13004 SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image - 1) );
13005 assert( image - 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
13006 }
13007 }
13008 }
13009 }
13010 SCIPhashmapFree(&varhash);
13011 SCIPfreeBufferArray(scip, &cardweights);
13012 SCIPfreeBufferArray(scip, &cardvars);
13013
13014 if ( *nupgdconss > noldupgdconss )
13015 success = TRUE;
13016 }
13017#endif
13018
13019 if( cutoff )
13020 *result = SCIP_CUTOFF;
13021 else if( success || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
13022 *result = SCIP_SUCCESS;
13023 else
13024 *result = SCIP_DIDNOTFIND;
13025
13026 return SCIP_OKAY;
13027}
13028
13029/** propagation conflict resolving method of constraint handler */
13030static
13031SCIP_DECL_CONSRESPROP(consRespropKnapsack)
13032{ /*lint --e{715}*/
13033 SCIP_CONSDATA* consdata;
13034 SCIP_Longint capsum;
13035 int i;
13036
13037 assert(result != NULL);
13038
13039 consdata = SCIPconsGetData(cons);
13040 assert(consdata != NULL);
13041
13042 /* check if we fixed a binary variable to one (due to negated clique) */
13043 if( inferinfo >= 0 && SCIPvarGetLbLocal(infervar) > 0.5 )
13044 {
13045 for( i = 0; i < consdata->nvars; ++i )
13046 {
13047 if( SCIPvarGetIndex(consdata->vars[i]) == inferinfo )
13048 {
13049 assert( SCIPgetVarUbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) < 0.5 );
13050 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
13051 break;
13052 }
13053 }
13054 assert(i < consdata->nvars);
13055 }
13056 else
13057 {
13058 /* according to negated cliques the minweightsum and all variables which are fixed to one which led to a fixing of
13059 * another negated clique variable to one, the inferinfo was chosen to be the negative of the position in the
13060 * knapsack constraint, see one above call of SCIPinferBinvarCons
13061 */
13062 if( inferinfo < 0 )
13063 capsum = 0;
13064 else
13065 {
13066 /* locate the inference variable and calculate the capacity that has to be used up to conclude infervar == 0;
13067 * inferinfo stores the position of the inference variable (but maybe the variables were resorted)
13068 */
13069 if( inferinfo < consdata->nvars && consdata->vars[inferinfo] == infervar )
13070 capsum = consdata->weights[inferinfo];
13071 else
13072 {
13073 for( i = 0; i < consdata->nvars && consdata->vars[i] != infervar; ++i )
13074 {}
13075 assert(i < consdata->nvars);
13076 capsum = consdata->weights[i];
13077 }
13078 }
13079
13080 /* add fixed-to-one variables up to the point, that their weight plus the weight of the conflict variable exceeds
13081 * the capacity
13082 */
13083 if( capsum <= consdata->capacity )
13084 {
13085 for( i = 0; i < consdata->nvars; i++ )
13086 {
13087 if( SCIPgetVarLbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) > 0.5 )
13088 {
13089 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
13090 capsum += consdata->weights[i];
13091 if( capsum > consdata->capacity )
13092 break;
13093 }
13094 }
13095 }
13096 }
13097
13098 /* NOTE: It might be the case that capsum < consdata->capacity. This is due the fact that the fixing of the variable
13099 * to zero can included negated clique information. A negated clique means, that at most one of the clique
13100 * variables can be zero. These information can be used to compute a minimum activity of the constraint and
13101 * used to fix variables to zero.
13102 *
13103 * Even if capsum < consdata->capacity we still reported a complete reason since the minimum activity is based
13104 * on global variable bounds. It might even be the case that we reported to many variables which are fixed to
13105 * one.
13106 */
13107 *result = SCIP_SUCCESS;
13108
13109 return SCIP_OKAY;
13110}
13111
13112/** variable rounding lock method of constraint handler */
13113/**! [SnippetConsLockKnapsack] */
13114static
13115SCIP_DECL_CONSLOCK(consLockKnapsack)
13116{ /*lint --e{715}*/
13117 SCIP_CONSDATA* consdata;
13118 int i;
13119
13120 consdata = SCIPconsGetData(cons);
13121 assert(consdata != NULL);
13122
13123 for( i = 0; i < consdata->nvars; i++)
13124 {
13125 SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlocksneg, nlockspos) );
13126 }
13127
13128 return SCIP_OKAY;
13129}
13130/**! [SnippetConsLockKnapsack] */
13131
13132/** constraint activation notification method of constraint handler */
13133static
13134SCIP_DECL_CONSACTIVE(consActiveKnapsack)
13135{ /*lint --e{715}*/
13137 {
13138 SCIP_CALL( addNlrow(scip, cons) );
13139 }
13140
13141 return SCIP_OKAY;
13142}
13143
13144/** constraint deactivation notification method of constraint handler */
13145static
13146SCIP_DECL_CONSDEACTIVE(consDeactiveKnapsack)
13147{ /*lint --e{715}*/
13148 SCIP_CONSDATA* consdata;
13149
13150 assert(cons != NULL);
13151
13152 consdata = SCIPconsGetData(cons);
13153 assert(consdata != NULL);
13154
13155 /* remove row from NLP, if still in solving
13156 * if we are in exitsolve, the whole NLP will be freed anyway
13157 */
13158 if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && consdata->nlrow != NULL )
13159 {
13160 SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
13161 }
13162
13163 return SCIP_OKAY;
13164}
13165
13166/** variable deletion method of constraint handler */
13167static
13168SCIP_DECL_CONSDELVARS(consDelvarsKnapsack)
13169{
13170 assert(scip != NULL);
13171 assert(conshdlr != NULL);
13172 assert(conss != NULL || nconss == 0);
13173
13174 if( nconss > 0 )
13175 {
13176 SCIP_CALL( performVarDeletions(scip, conshdlr, conss, nconss) );
13177 }
13178
13179 return SCIP_OKAY;
13180}
13181
13182/** constraint display method of constraint handler */
13183static
13184SCIP_DECL_CONSPRINT(consPrintKnapsack)
13185{ /*lint --e{715}*/
13186 SCIP_CONSDATA* consdata;
13187 int i;
13188
13189 assert( scip != NULL );
13190 assert( conshdlr != NULL );
13191 assert( cons != NULL );
13192
13193 consdata = SCIPconsGetData(cons);
13194 assert(consdata != NULL);
13195
13196 for( i = 0; i < consdata->nvars; ++i )
13197 {
13198 if( i > 0 )
13199 SCIPinfoMessage(scip, file, " ");
13200 SCIPinfoMessage(scip, file, "%+" SCIP_LONGINT_FORMAT, consdata->weights[i]);
13201 SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[i], TRUE) );
13202 }
13203 SCIPinfoMessage(scip, file, " <= %" SCIP_LONGINT_FORMAT "", consdata->capacity);
13204
13205 return SCIP_OKAY;
13206}
13207
13208/** constraint copying method of constraint handler */
13209static
13210SCIP_DECL_CONSCOPY(consCopyKnapsack)
13211{ /*lint --e{715}*/
13212 SCIP_VAR** sourcevars;
13213 SCIP_Longint* weights;
13214 SCIP_Real* coefs;
13215 const char* consname;
13216 int nvars;
13217 int v;
13218
13219 /* get variables and coefficients of the source constraint */
13220 sourcevars = SCIPgetVarsKnapsack(sourcescip, sourcecons);
13221 nvars = SCIPgetNVarsKnapsack(sourcescip, sourcecons);
13222 weights = SCIPgetWeightsKnapsack(sourcescip, sourcecons);
13223
13225 for( v = 0; v < nvars; ++v )
13226 coefs[v] = (SCIP_Real) weights[v];
13227
13228 if( name != NULL )
13229 consname = name;
13230 else
13231 consname = SCIPconsGetName(sourcecons);
13232
13233 /* copy the logic using the linear constraint copy method */
13234 SCIP_CALL( SCIPcopyConsLinear(scip, cons, sourcescip, consname, nvars, sourcevars, coefs,
13235 -SCIPinfinity(scip), (SCIP_Real) SCIPgetCapacityKnapsack(sourcescip, sourcecons), varmap, consmap,
13236 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, global, valid) );
13237 assert(cons != NULL);
13238
13239 SCIPfreeBufferArray(scip, &coefs);
13240
13241 return SCIP_OKAY;
13242}
13243
13244/** constraint parsing method of constraint handler */
13245static
13246SCIP_DECL_CONSPARSE(consParseKnapsack)
13247{ /*lint --e{715}*/
13248 SCIP_VAR* var;
13249 SCIP_Longint weight;
13250 SCIP_VAR** vars;
13251 SCIP_Longint* weights;
13252 SCIP_Longint capacity;
13253 char* endptr;
13254 int nread;
13255 int nvars;
13256 int varssize;
13257
13258 assert(scip != NULL);
13259 assert(success != NULL);
13260 assert(str != NULL);
13261 assert(name != NULL);
13262 assert(cons != NULL);
13263
13264 *success = TRUE;
13265
13266 nvars = 0;
13267 varssize = 5;
13268 SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13269 SCIP_CALL( SCIPallocBufferArray(scip, &weights, varssize) );
13270
13271 while( *str != '\0' )
13272 {
13273 /* try to parse coefficient, and use 1 if not successful */
13274 weight = 1;
13275 nread = 0;
13276 (void) sscanf(str, "%" SCIP_LONGINT_FORMAT "%n", &weight, &nread);
13277 str += nread;
13278
13279 /* parse variable name */
13280 SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13281
13282 if( var == NULL )
13283 {
13284 endptr = strchr(endptr, '<');
13285
13286 if( endptr == NULL )
13287 {
13288 SCIPerrorMessage("no capacity found\n");
13289 *success = FALSE;
13290 }
13291 else
13292 str = endptr;
13293
13294 break;
13295 }
13296
13297 str = endptr;
13298
13299 /* store weight and variable */
13300 if( varssize <= nvars )
13301 {
13302 varssize = SCIPcalcMemGrowSize(scip, varssize+1);
13303 SCIP_CALL( SCIPreallocBufferArray(scip, &vars, varssize) );
13304 SCIP_CALL( SCIPreallocBufferArray(scip, &weights, varssize) );
13305 }
13306
13307 vars[nvars] = var;
13308 weights[nvars] = weight;
13309 ++nvars;
13310
13311 /* skip whitespace */
13312 SCIP_CALL( SCIPskipSpace((char**)&str) );
13313 }
13314
13315 if( *success )
13316 {
13317 if( strncmp(str, "<=", 2) != 0 )
13318 {
13319 SCIPerrorMessage("expected '<=' at begin of '%s'\n", str);
13320 *success = FALSE;
13321 }
13322 else
13323 {
13324 str += 2;
13325 }
13326 }
13327
13328 if( *success )
13329 {
13330 /* skip whitespace */
13331 SCIP_CALL( SCIPskipSpace((char**)&str) );
13332
13333 /* coverity[secure_coding] */
13334 if( sscanf(str, "%" SCIP_LONGINT_FORMAT, &capacity) != 1 )
13335 {
13336 SCIPerrorMessage("error parsing capacity from '%s'\n", str);
13337 *success = FALSE;
13338 }
13339 else
13340 {
13341 SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13342 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13343 }
13344 }
13345
13346 SCIPfreeBufferArray(scip, &vars);
13347 SCIPfreeBufferArray(scip, &weights);
13348
13349 return SCIP_OKAY;
13350}
13351
13352/** constraint method of constraint handler which returns the variables (if possible) */
13353static
13354SCIP_DECL_CONSGETVARS(consGetVarsKnapsack)
13355{ /*lint --e{715}*/
13356 SCIP_CONSDATA* consdata;
13357
13358 consdata = SCIPconsGetData(cons);
13359 assert(consdata != NULL);
13360
13361 if( varssize < consdata->nvars )
13362 (*success) = FALSE;
13363 else
13364 {
13365 assert(vars != NULL);
13366
13367 BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13368 (*success) = TRUE;
13369 }
13370
13371 return SCIP_OKAY;
13372}
13373
13374/** constraint method of constraint handler which returns the number of variables (if possible) */
13375static
13376SCIP_DECL_CONSGETNVARS(consGetNVarsKnapsack)
13377{ /*lint --e{715}*/
13378 SCIP_CONSDATA* consdata;
13379
13380 consdata = SCIPconsGetData(cons);
13381 assert(consdata != NULL);
13382
13383 (*nvars) = consdata->nvars;
13384 (*success) = TRUE;
13385
13386 return SCIP_OKAY;
13387}
13388
13389/** constraint handler method which returns the permutation symmetry detection graph of a constraint */
13390static
13391SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphKnapsack)
13392{ /*lint --e{715}*/
13393 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) );
13394
13395 return SCIP_OKAY;
13396}
13397
13398/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint */
13399static
13400SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphKnapsack)
13401{ /*lint --e{715}*/
13402 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) );
13403
13404 return SCIP_OKAY;
13405}
13406
13407/*
13408 * Event handler
13409 */
13410
13411/** execution method of bound change event handler */
13412static
13413SCIP_DECL_EVENTEXEC(eventExecKnapsack)
13414{ /*lint --e{715}*/
13415 SCIP_CONSDATA* consdata;
13416
13417 assert(eventdata != NULL);
13418 assert(eventdata->cons != NULL);
13419
13420 consdata = SCIPconsGetData(eventdata->cons);
13421 assert(consdata != NULL);
13422
13423 switch( SCIPeventGetType(event) )
13424 {
13426 consdata->onesweightsum += eventdata->weight;
13427 consdata->presolvedtiming = 0;
13428 SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13429 break;
13431 consdata->onesweightsum -= eventdata->weight;
13432 break;
13434 consdata->presolvedtiming = 0;
13435 SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13436 break;
13437 case SCIP_EVENTTYPE_VARFIXED: /* the variable should be removed from the constraint in presolving */
13438 if( !consdata->existmultaggr )
13439 {
13440 SCIP_VAR* var;
13441 var = SCIPeventGetVar(event);
13442 assert(var != NULL);
13443
13444 /* if the variable was aggregated or multiaggregated, we must signal to propagation that we are no longer merged */
13446 {
13447 consdata->existmultaggr = TRUE;
13448 consdata->merged = FALSE;
13449 }
13452 consdata->merged = FALSE;
13453 }
13454 /*lint -fallthrough*/
13455 case SCIP_EVENTTYPE_IMPLADDED: /* further preprocessing might be possible due to additional implications */
13456 consdata->presolvedtiming = 0;
13457 break;
13459 consdata->varsdeleted = TRUE;
13460 break;
13461 default:
13462 SCIPerrorMessage("invalid event type %" SCIP_EVENTTYPE_FORMAT "\n", SCIPeventGetType(event));
13463 return SCIP_INVALIDDATA;
13464 }
13465
13466 return SCIP_OKAY;
13467}
13468
13469
13470/*
13471 * constraint specific interface methods
13472 */
13473
13474/** creates the handler for knapsack constraints and includes it in SCIP */
13476 SCIP* scip /**< SCIP data structure */
13477 )
13478{
13479 SCIP_EVENTHDLRDATA* eventhdlrdata;
13480 SCIP_CONSHDLRDATA* conshdlrdata;
13481 SCIP_CONSHDLR* conshdlr;
13482
13483 /* create knapsack constraint handler data */
13484 SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
13485
13486 /* include event handler for bound change events */
13487 eventhdlrdata = NULL;
13488 conshdlrdata->eventhdlr = NULL;
13490 eventExecKnapsack, eventhdlrdata) );
13491
13492 /* get event handler for bound change events */
13493 if( conshdlrdata->eventhdlr == NULL )
13494 {
13495 SCIPerrorMessage("event handler for knapsack constraints not found\n");
13496 return SCIP_PLUGINNOTFOUND;
13497 }
13498
13499 /* include constraint handler */
13502 consEnfolpKnapsack, consEnfopsKnapsack, consCheckKnapsack, consLockKnapsack,
13503 conshdlrdata) );
13504
13505 assert(conshdlr != NULL);
13506
13507 /* set non-fundamental callbacks via specific setter functions */
13508 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyKnapsack, consCopyKnapsack) );
13509 SCIP_CALL( SCIPsetConshdlrActive(scip, conshdlr, consActiveKnapsack) );
13510 SCIP_CALL( SCIPsetConshdlrDeactive(scip, conshdlr, consDeactiveKnapsack) );
13511 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteKnapsack) );
13512 SCIP_CALL( SCIPsetConshdlrDelvars(scip, conshdlr, consDelvarsKnapsack) );
13513 SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitKnapsack) );
13514 SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreKnapsack) );
13515 SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolKnapsack) );
13516 SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolKnapsack) );
13517 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeKnapsack) );
13518 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsKnapsack) );
13519 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsKnapsack) );
13520 SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitKnapsack) );
13521 SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreKnapsack) );
13522 SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpKnapsack) );
13523 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseKnapsack) );
13525 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintKnapsack) );
13528 SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropKnapsack) );
13529 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpKnapsack, consSepasolKnapsack, CONSHDLR_SEPAFREQ,
13531 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransKnapsack) );
13532 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxKnapsack) );
13533 SCIP_CALL( SCIPsetConshdlrGetPermsymGraph(scip, conshdlr, consGetPermsymGraphKnapsack) );
13534 SCIP_CALL( SCIPsetConshdlrGetSignedPermsymGraph(scip, conshdlr, consGetSignedPermsymGraphKnapsack) );
13535
13536 if( SCIPfindConshdlr(scip,"linear") != NULL )
13537 {
13538 /* include the linear constraint to knapsack constraint upgrade in the linear constraint handler */
13540 }
13541
13542 /* add knapsack constraint handler parameters */
13544 "constraints/" CONSHDLR_NAME "/sepacardfreq",
13545 "multiplier on separation frequency, how often knapsack cuts are separated (-1: never, 0: only at root)",
13546 &conshdlrdata->sepacardfreq, TRUE, DEFAULT_SEPACARDFREQ, -1, SCIP_MAXTREEDEPTH, NULL, NULL) );
13548 "constraints/" CONSHDLR_NAME "/maxcardbounddist",
13549 "maximal relative distance from current node's dual bound to primal bound compared to best node's dual bound for separating knapsack cuts",
13550 &conshdlrdata->maxcardbounddist, TRUE, DEFAULT_MAXCARDBOUNDDIST, 0.0, 1.0, NULL, NULL) );
13552 "constraints/" CONSHDLR_NAME "/cliqueextractfactor",
13553 "lower clique size limit for greedy clique extraction algorithm (relative to largest clique)",
13554 &conshdlrdata->cliqueextractfactor, TRUE, DEFAULT_CLIQUEEXTRACTFACTOR, 0.0, 1.0, NULL, NULL) );
13556 "constraints/" CONSHDLR_NAME "/maxrounds",
13557 "maximal number of separation rounds per node (-1: unlimited)",
13558 &conshdlrdata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
13560 "constraints/" CONSHDLR_NAME "/maxroundsroot",
13561 "maximal number of separation rounds per node in the root node (-1: unlimited)",
13562 &conshdlrdata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
13564 "constraints/" CONSHDLR_NAME "/maxsepacuts",
13565 "maximal number of cuts separated per separation round",
13566 &conshdlrdata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
13568 "constraints/" CONSHDLR_NAME "/maxsepacutsroot",
13569 "maximal number of cuts separated per separation round in the root node",
13570 &conshdlrdata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
13572 "constraints/" CONSHDLR_NAME "/disaggregation",
13573 "should disaggregation of knapsack constraints be allowed in preprocessing?",
13574 &conshdlrdata->disaggregation, TRUE, DEFAULT_DISAGGREGATION, NULL, NULL) );
13576 "constraints/" CONSHDLR_NAME "/simplifyinequalities",
13577 "should presolving try to simplify knapsacks",
13578 &conshdlrdata->simplifyinequalities, TRUE, DEFAULT_SIMPLIFYINEQUALITIES, NULL, NULL) );
13580 "constraints/" CONSHDLR_NAME "/negatedclique",
13581 "should negated clique information be used in solving process",
13582 &conshdlrdata->negatedclique, TRUE, DEFAULT_NEGATEDCLIQUE, NULL, NULL) );
13584 "constraints/" CONSHDLR_NAME "/presolpairwise",
13585 "should pairwise constraint comparison be performed in presolving?",
13586 &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13588 "constraints/" CONSHDLR_NAME "/presolusehashing",
13589 "should hash table be used for detecting redundant constraints in advance",
13590 &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) );
13592 "constraints/" CONSHDLR_NAME "/dualpresolving",
13593 "should dual presolving steps be performed?",
13594 &conshdlrdata->dualpresolving, TRUE, DEFAULT_DUALPRESOLVING, NULL, NULL) );
13596 "constraints/" CONSHDLR_NAME "/usegubs",
13597 "should GUB information be used for separation?",
13598 &conshdlrdata->usegubs, TRUE, DEFAULT_USEGUBS, NULL, NULL) );
13600 "constraints/" CONSHDLR_NAME "/detectcutoffbound",
13601 "should presolving try to detect constraints parallel to the objective function defining an upper bound and prevent these constraints from entering the LP?",
13602 &conshdlrdata->detectcutoffbound, TRUE, DEFAULT_DETECTCUTOFFBOUND, NULL, NULL) );
13604 "constraints/" CONSHDLR_NAME "/detectlowerbound",
13605 "should presolving try to detect constraints parallel to the objective function defining a lower bound and prevent these constraints from entering the LP?",
13606 &conshdlrdata->detectlowerbound, TRUE, DEFAULT_DETECTLOWERBOUND, NULL, NULL) );
13608 "constraints/" CONSHDLR_NAME "/updatecliquepartitions",
13609 "should clique partition information be updated when old partition seems outdated?",
13610 &conshdlrdata->updatecliquepartitions, TRUE, DEFAULT_UPDATECLIQUEPARTITIONS, NULL, NULL) );
13612 "constraints/" CONSHDLR_NAME "/clqpartupdatefac",
13613 "factor on the growth of global cliques to decide when to update a previous "
13614 "(negated) clique partition (used only if updatecliquepartitions is set to TRUE)",
13615 &conshdlrdata->clqpartupdatefac, TRUE, DEFAULT_CLQPARTUPDATEFAC, 1.0, 10.0, NULL, NULL) );
13616#ifdef WITH_CARDINALITY_UPGRADE
13618 "constraints/" CONSHDLR_NAME "/upgdcardinality",
13619 "if TRUE then try to update knapsack constraints to cardinality constraints",
13620 &conshdlrdata->upgdcardinality, TRUE, DEFAULT_UPGDCARDINALITY, NULL, NULL) );
13621#endif
13622 return SCIP_OKAY;
13623}
13624
13625/** creates and captures a knapsack constraint
13626 *
13627 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13628 */
13629/**! [SnippetConsCreationKnapsack] */
13631 SCIP* scip, /**< SCIP data structure */
13632 SCIP_CONS** cons, /**< pointer to hold the created constraint */
13633 const char* name, /**< name of constraint */
13634 int nvars, /**< number of items in the knapsack */
13635 SCIP_VAR** vars, /**< array with item variables */
13636 SCIP_Longint* weights, /**< array with item weights */
13637 SCIP_Longint capacity, /**< capacity of knapsack (right hand side of inequality) */
13638 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13639 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13640 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13641 * Usually set to TRUE. */
13642 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13643 * TRUE for model constraints, FALSE for additional, redundant constraints. */
13644 SCIP_Bool check, /**< should the constraint be checked for feasibility?
13645 * TRUE for model constraints, FALSE for additional, redundant constraints. */
13646 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13647 * Usually set to TRUE. */
13648 SCIP_Bool local, /**< is constraint only valid locally?
13649 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13650 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13651 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13652 * adds coefficients to this constraint. */
13653 SCIP_Bool dynamic, /**< is constraint subject to aging?
13654 * Usually set to FALSE. Set to TRUE for own cuts which
13655 * are separated as constraints. */
13656 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13657 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13658 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13659 * if it may be moved to a more global node?
13660 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13661 )
13662{
13663 SCIP_CONSHDLRDATA* conshdlrdata;
13664 SCIP_CONSHDLR* conshdlr;
13665 SCIP_CONSDATA* consdata;
13666
13667 /* find the knapsack constraint handler */
13668 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13669 if( conshdlr == NULL )
13670 {
13671 SCIPerrorMessage("knapsack constraint handler not found\n");
13672 return SCIP_PLUGINNOTFOUND;
13673 }
13674
13675 /* get event handler */
13676 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13677 assert(conshdlrdata != NULL);
13678 assert(conshdlrdata->eventhdlr != NULL);
13679
13680 /* create constraint data */
13681 SCIP_CALL( consdataCreate(scip, &consdata, nvars, vars, weights, capacity) );
13682
13683 /* create constraint */
13684 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
13685 local, modifiable, dynamic, removable, stickingatnode) );
13686
13687 /* catch events for variables */
13688 if( SCIPisTransformed(scip) )
13689 {
13690 SCIP_CALL( catchEvents(scip, *cons, consdata, conshdlrdata->eventhdlr) );
13691 }
13692
13693 return SCIP_OKAY;
13694}
13695/**! [SnippetConsCreationKnapsack] */
13696
13697/** creates and captures a knapsack constraint
13698 * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13699 * method SCIPcreateConsKnapsack(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13700 *
13701 * @see SCIPcreateConsKnapsack() for information about the basic constraint flag configuration
13702 *
13703 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13704 */
13706 SCIP* scip, /**< SCIP data structure */
13707 SCIP_CONS** cons, /**< pointer to hold the created constraint */
13708 const char* name, /**< name of constraint */
13709 int nvars, /**< number of items in the knapsack */
13710 SCIP_VAR** vars, /**< array with item variables */
13711 SCIP_Longint* weights, /**< array with item weights */
13712 SCIP_Longint capacity /**< capacity of knapsack */
13713 )
13714{
13715 assert(scip != NULL);
13716
13717 SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13719
13720 return SCIP_OKAY;
13721}
13722
13723/** adds new item to knapsack constraint */
13725 SCIP* scip, /**< SCIP data structure */
13726 SCIP_CONS* cons, /**< constraint data */
13727 SCIP_VAR* var, /**< item variable */
13728 SCIP_Longint weight /**< item weight */
13729 )
13730{
13731 assert(var != NULL);
13732 assert(scip != NULL);
13733
13734 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13735 {
13736 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13737 return SCIP_INVALIDDATA;
13738 }
13739
13740 SCIP_CALL( addCoef(scip, cons, var, weight) );
13741
13742 return SCIP_OKAY;
13743}
13744
13745/** gets the capacity of the knapsack constraint */
13747 SCIP* scip, /**< SCIP data structure */
13748 SCIP_CONS* cons /**< constraint data */
13749 )
13750{
13751 SCIP_CONSDATA* consdata;
13752
13753 assert(scip != NULL);
13754
13755 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13756 {
13757 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13758 SCIPABORT();
13759 return 0; /*lint !e527*/
13760 }
13761
13762 consdata = SCIPconsGetData(cons);
13763 assert(consdata != NULL);
13764
13765 return consdata->capacity;
13766}
13767
13768/** changes capacity of the knapsack constraint
13769 *
13770 * @note This method can only be called during problem creation stage (SCIP_STAGE_PROBLEM)
13771 */
13773 SCIP* scip, /**< SCIP data structure */
13774 SCIP_CONS* cons, /**< constraint data */
13775 SCIP_Longint capacity /**< new capacity of knapsack */
13776 )
13777{
13778 SCIP_CONSDATA* consdata;
13779
13780 assert(scip != NULL);
13781
13782 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13783 {
13784 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13785 return SCIP_INVALIDDATA;
13786 }
13787
13789 {
13790 SCIPerrorMessage("method can only be called during problem creation stage\n");
13791 return SCIP_INVALIDDATA;
13792 }
13793
13794 consdata = SCIPconsGetData(cons);
13795 assert(consdata != NULL);
13796
13797 consdata->capacity = capacity;
13798
13799 return SCIP_OKAY;
13800}
13801
13802/** gets the number of items in the knapsack constraint */
13804 SCIP* scip, /**< SCIP data structure */
13805 SCIP_CONS* cons /**< constraint data */
13806 )
13807{
13808 SCIP_CONSDATA* consdata;
13809
13810 assert(scip != NULL);
13811
13812 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13813 {
13814 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13815 SCIPABORT();
13816 return -1; /*lint !e527*/
13817 }
13818
13819 consdata = SCIPconsGetData(cons);
13820 assert(consdata != NULL);
13821
13822 return consdata->nvars;
13823}
13824
13825/** gets the array of variables in the knapsack constraint; the user must not modify this array! */
13827 SCIP* scip, /**< SCIP data structure */
13828 SCIP_CONS* cons /**< constraint data */
13829 )
13830{
13831 SCIP_CONSDATA* consdata;
13832
13833 assert(scip != NULL);
13834
13835 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13836 {
13837 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13838 SCIPABORT();
13839 return NULL; /*lint !e527*/
13840 }
13841
13842 consdata = SCIPconsGetData(cons);
13843 assert(consdata != NULL);
13844
13845 return consdata->vars;
13846}
13847
13848/** gets the array of weights in the knapsack constraint; the user must not modify this array! */
13850 SCIP* scip, /**< SCIP data structure */
13851 SCIP_CONS* cons /**< constraint data */
13852 )
13853{
13854 SCIP_CONSDATA* consdata;
13855
13856 assert(scip != NULL);
13857
13858 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13859 {
13860 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13861 SCIPABORT();
13862 return NULL; /*lint !e527*/
13863 }
13864
13865 consdata = SCIPconsGetData(cons);
13866 assert(consdata != NULL);
13867
13868 return consdata->weights;
13869}
13870
13871/** gets the dual solution of the knapsack constraint in the current LP */
13873 SCIP* scip, /**< SCIP data structure */
13874 SCIP_CONS* cons /**< constraint data */
13875 )
13876{
13877 SCIP_CONSDATA* consdata;
13878
13879 assert(scip != NULL);
13880
13881 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13882 {
13883 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13884 SCIPABORT();
13885 return SCIP_INVALID; /*lint !e527*/
13886 }
13887
13888 consdata = SCIPconsGetData(cons);
13889 assert(consdata != NULL);
13890
13891 if( consdata->row != NULL )
13892 return SCIProwGetDualsol(consdata->row);
13893 else
13894 return 0.0;
13895}
13896
13897/** gets the dual Farkas value of the knapsack constraint in the current infeasible LP */
13899 SCIP* scip, /**< SCIP data structure */
13900 SCIP_CONS* cons /**< constraint data */
13901 )
13902{
13903 SCIP_CONSDATA* consdata;
13904
13905 assert(scip != NULL);
13906
13907 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13908 {
13909 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13910 SCIPABORT();
13911 return SCIP_INVALID; /*lint !e527*/
13912 }
13913
13914 consdata = SCIPconsGetData(cons);
13915 assert(consdata != NULL);
13916
13917 if( consdata->row != NULL )
13918 return SCIProwGetDualfarkas(consdata->row);
13919 else
13920 return 0.0;
13921}
13922
13923/** returns the linear relaxation of the given knapsack constraint; may return NULL if no LP row was yet created;
13924 * the user must not modify the row!
13925 */
13927 SCIP* scip, /**< SCIP data structure */
13928 SCIP_CONS* cons /**< constraint data */
13929 )
13930{
13931 SCIP_CONSDATA* consdata;
13932
13933 assert(scip != NULL);
13934
13935 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13936 {
13937 SCIPerrorMessage("constraint is not a knapsack\n");
13938 SCIPABORT();
13939 return NULL; /*lint !e527*/
13940 }
13941
13942 consdata = SCIPconsGetData(cons);
13943 assert(consdata != NULL);
13944
13945 return consdata->row;
13946}
13947
13948/** cleans up (multi-)aggregations and fixings from knapsack constraints */
13950 SCIP* scip, /**< SCIP data structure */
13951 SCIP_Bool onlychecked, /**< should only checked constraints be cleaned up? */
13952 SCIP_Bool* infeasible /**< pointer to return whether the problem was detected to be infeasible */
13953 )
13954{
13955 SCIP_CONSHDLR* conshdlr;
13956 SCIP_CONS** conss;
13957 int nconss;
13958 int i;
13959
13960 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13961 if( conshdlr == NULL )
13962 return SCIP_OKAY;
13963
13964 assert(infeasible != NULL);
13965 *infeasible = FALSE;
13966
13967 nconss = onlychecked ? SCIPconshdlrGetNCheckConss(conshdlr) : SCIPconshdlrGetNActiveConss(conshdlr);
13968 conss = onlychecked ? SCIPconshdlrGetCheckConss(conshdlr) : SCIPconshdlrGetConss(conshdlr);
13969
13970 for( i = 0; i < nconss; ++i )
13971 {
13972 SCIP_CALL( applyFixings(scip, conss[i], infeasible) );
13973
13974 if( *infeasible )
13975 break;
13976 }
13977
13978 return SCIP_OKAY;
13979}
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:267
#define SCIP_MAXSTRLEN
Definition: def.h:288
#define SCIP_Longint
Definition: def.h:158
#define SCIP_MAXTREEDEPTH
Definition: def.h:316
#define SCIP_INVALID
Definition: def.h:193
#define SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:243
#define SCIP_Real
Definition: def.h:173
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:239
#define SCIP_LONGINT_FORMAT
Definition: def.h:165
#define SCIPABORT()
Definition: def.h:346
#define REALABS(x)
Definition: def.h:197
#define SCIP_LONGINT_MAX
Definition: def.h:159
#define SCIP_CALL(x)
Definition: def.h:374
SCIP_RETCODE SCIPincludeLinconsUpgrade(SCIP *scip, SCIP_DECL_LINCONSUPGD((*linconsupgd)), int priority, const char *conshdlrname)
int SCIPgetNVarsKnapsack(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)
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:9409
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:660
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip_general.c:596
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
Definition: scip_general.c:633
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:724
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:380
int SCIPgetNObjVars(SCIP *scip)
Definition: scip_prob.c:2220
int SCIPgetNContVars(SCIP *scip)
Definition: scip_prob.c:2172
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:1992
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2770
SCIP_CONS * SCIPfindOrigCons(SCIP *scip, const char *name)
Definition: scip_prob.c:2898
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2843
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:1947
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:3108
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3281
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3074
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3423
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3192
SCIP_RETCODE SCIPhashmapSetImageInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3357
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2346
#define SCIPhashSix(a, b, c, d, e, f)
Definition: pub_misc.h:563
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:2296
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition: misc.c:2608
SCIP_RETCODE SCIPhashtableRemove(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2677
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2547
SCIP_RETCODE SCIPupdateLocalLowerbound(SCIP *scip, SCIP_Real newbound)
Definition: scip_prob.c:3696
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3474
SCIP_Real SCIPgetLocalLowerbound(SCIP *scip)
Definition: scip_prob.c:3585
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:9121
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:9557
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:11184
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:428
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:4656
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:4227
SCIP_CONS ** SCIPconshdlrGetCheckConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4613
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:4900
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:4197
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:941
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:4217
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:4670
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:5130
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4593
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:8244
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8473
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8234
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8383
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip_cons.c:2537
SCIP_RETCODE SCIPsetConsSeparated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool separate)
Definition: scip_cons.c:1297
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8413
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:8343
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8523
SCIP_RETCODE SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial)
Definition: scip_cons.c:1272
SCIP_RETCODE SCIPsetConsEnforced(SCIP *scip, SCIP_CONS *cons, SCIP_Bool enforce)
Definition: scip_cons.c:1322
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8403
SCIP_RETCODE SCIPunmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:2043
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8275
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:998
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8433
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8453
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8214
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1813
SCIP_RETCODE SCIPmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:2015
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8463
SCIP_RETCODE SCIPupdateConsFlags(SCIP *scip, SCIP_CONS *cons0, SCIP_CONS *cons1)
Definition: scip_cons.c:1525
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8493
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1174
SCIP_RETCODE SCIPsetConsPropagated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool propagate)
Definition: scip_cons.c:1372
SCIP_RETCODE SCIPsetConsChecked(SCIP *scip, SCIP_CONS *cons, SCIP_Bool check)
Definition: scip_cons.c:1347
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8393
SCIP_RETCODE SCIPincConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1785
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8483
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:250
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:104
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:1030
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:354
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:400
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:1053
#define SCIPfreeBuffer(scip, ptr)
Definition: scip_mem.h:134
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:110
#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:1956
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:97
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1635
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:1422
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1658
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:1391
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1701
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2212
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1562
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:1453
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:1482
SCIP_Real SCIProwGetDualfarkas(SCIP_ROW *row)
Definition: lp.c:17325
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:17523
SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
Definition: lp.c:17312
const char * SCIPsepaGetName(SCIP_SEPA *sepa)
Definition: sepa.c:743
SCIP_Longint SCIPsepaGetNCutsFound(SCIP_SEPA *sepa)
Definition: sepa.c:900
SCIP_RETCODE SCIPgetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip_sol.c:1254
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1217
void SCIPupdateSolLPConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition: scip_sol.c:141
SCIP_RETCODE SCIPupdateCutoffbound(SCIP *scip, SCIP_Real cutoffbound)
int SCIPgetNSepaRounds(SCIP *scip)
SCIP_Real SCIPgetLowerbound(SCIP *scip)
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
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_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:670
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5203
int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition: var.c:18270
SCIP_Bool SCIPvarIsDeleted(SCIP_VAR *var)
Definition: var.c:17640
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4351
SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
Definition: var.c:17882
SCIP_VAR * SCIPvarGetNegatedVar(SCIP_VAR *var)
Definition: var.c:17894
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition: var.c:18292
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:17748
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:17599
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:6921
SCIP_RETCODE SCIPcalcCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques)
Definition: scip_var.c:7256
SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
Definition: scip_var.c:1480
int SCIPvarGetNImpls(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18356
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:17538
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3353
SCIP_RETCODE SCIPcalcNegatedCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques)
Definition: scip_var.c:7475
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:18144
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:17561
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17926
SCIP_VAR * SCIPvarGetProbvar(SCIP_VAR *var)
Definition: var.c:12218
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5320
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition: scip_var.c:533
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:18088
SCIP_VAR ** SCIPvarGetImplVars(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18373
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:17758
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition: scip_var.c:4259
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4437
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:2128
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:17768
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17419
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1248
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition: var.c:18302
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:18312
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:17610
SCIP_Real * SCIPvarGetImplBounds(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18402
SCIP_RETCODE SCIPflattenVarAggregationGraph(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1693
SCIP_RETCODE SCIPgetNegatedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **negvar)
Definition: scip_var.c:1527
SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
Definition: var.c:17858
int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition: var.c:17846
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18430
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:18134
SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
Definition: var.c:17574
int SCIPgetNCliques(SCIP *scip)
Definition: scip_var.c:7575
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:18282
SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18441
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:18078
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip_var.c:8276
SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:1992
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11942
SCIP_RETCODE SCIPvarGetProbvarBinary(SCIP_VAR **var, SCIP_Bool *negated)
Definition: var.c:12310
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:5723
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition: var.c:18344
SCIP_RETCODE SCIPwriteVarName(SCIP *scip, FILE *file, SCIP_VAR *var, SCIP_Bool type)
Definition: scip_var.c:230
SCIP_RETCODE SCIPgetBinvarRepresentative(SCIP *scip, SCIP_VAR *var, SCIP_VAR **repvar, SCIP_Bool *negated)
Definition: scip_var.c:1597
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:18324
SCIP_Bool SCIPvarsHaveCommonClique(SCIP_VAR *var1, SCIP_Bool value1, SCIP_VAR *var2, SCIP_Bool value2, SCIP_Bool regardimplics)
Definition: var.c:11475
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:18334
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3295
SCIP_RETCODE SCIPgetNegatedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **negvars)
Definition: scip_var.c:1560
SCIP_BOUNDTYPE * SCIPvarGetImplTypes(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18388
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1214
SCIP_Bool SCIPallowStrongDualReds(SCIP *scip)
Definition: scip_var.c:8629
SCIP_RETCODE SCIPvarsGetProbvarBinary(SCIP_VAR ***vars, SCIP_Bool **negatedarr, int nvars)
Definition: var.c:12278
SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition: var.c:17870
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:10877
SCIP_RETCODE SCIPskipSpace(char **s)
Definition: misc.c:10866
SCIP_VAR ** SCIPcliqueGetVars(SCIP_CLIQUE *clique)
Definition: implics.c:3380
int SCIPcliqueGetNVars(SCIP_CLIQUE *clique)
Definition: implics.c:3370
SCIP_Bool * SCIPcliqueGetValues(SCIP_CLIQUE *clique)
Definition: implics.c:3392
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
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:57
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
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:60
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:173
#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:155
#define SCIP_EVENTTYPE_LBRELAXED
Definition: type_event.h:78
#define SCIP_EVENTTYPE_FORMAT
Definition: type_event.h:152
#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:57
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:59
@ 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:52
@ SCIP_VARSTATUS_MULTAGGR
Definition: type_var.h:54
@ SCIP_VARSTATUS_NEGATED
Definition: type_var.h:55
@ SCIP_VARSTATUS_AGGREGATED
Definition: type_var.h:53
@ SCIP_LOCKTYPE_MODEL
Definition: type_var.h:97