SCIP Doxygen Documentation
 
Loading...
Searching...
No Matches
cons_knapsack.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-2023 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file cons_knapsack.c
26 * @ingroup DEFPLUGINS_CONS
27 * @brief Constraint handler for knapsack constraints of the form \f$a^T x \le b\f$, x binary and \f$a \ge 0\f$.
28 * @author Tobias Achterberg
29 * @author Xin Liu
30 * @author Kati Wolter
31 * @author Michael Winkler
32 * @author Tobias Fischer
33 */
34
35/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
36
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#ifdef WITH_CARDINALITY_UPGRADE
73#endif
74
75/* constraint handler properties */
76#define CONSHDLR_NAME "knapsack"
77#define CONSHDLR_DESC "knapsack constraint of the form a^T x <= b, x binary and a >= 0"
78#define CONSHDLR_SEPAPRIORITY +600000 /**< priority of the constraint handler for separation */
79#define CONSHDLR_ENFOPRIORITY -600000 /**< priority of the constraint handler for constraint enforcing */
80#define CONSHDLR_CHECKPRIORITY -600000 /**< priority of the constraint handler for checking feasibility */
81#define CONSHDLR_SEPAFREQ 0 /**< frequency for separating cuts; zero means to separate only in the root node */
82#define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
83#define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
84 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
85#define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
86#define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
87#define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
88#define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
89
90#define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
91#define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
92
93#define EVENTHDLR_NAME "knapsack"
94#define EVENTHDLR_DESC "bound change event handler for knapsack constraints"
95#define EVENTTYPE_KNAPSACK SCIP_EVENTTYPE_LBCHANGED \
96 | SCIP_EVENTTYPE_UBTIGHTENED \
97 | SCIP_EVENTTYPE_VARFIXED \
98 | SCIP_EVENTTYPE_VARDELETED \
99 | SCIP_EVENTTYPE_IMPLADDED /**< variable events that should be caught by the event handler */
100
101#define LINCONSUPGD_PRIORITY +100000 /**< priority of the constraint handler for upgrading of linear constraints */
102
103#define MAX_USECLIQUES_SIZE 1000 /**< maximal number of items in knapsack where clique information is used */
104#define MAX_ZEROITEMS_SIZE 10000 /**< maximal number of items to store in the zero list in preprocessing */
105
106#define KNAPSACKRELAX_MAXDELTA 0.1 /**< maximal allowed rounding distance for scaling in knapsack relaxation */
107#define KNAPSACKRELAX_MAXDNOM 1000LL /**< maximal allowed denominator in knapsack rational relaxation */
108#define KNAPSACKRELAX_MAXSCALE 1000.0 /**< maximal allowed scaling factor in knapsack rational relaxation */
109
110#define DEFAULT_SEPACARDFREQ 1 /**< multiplier on separation frequency, how often knapsack cuts are separated */
111#define DEFAULT_MAXROUNDS 5 /**< maximal number of separation rounds per node (-1: unlimited) */
112#define DEFAULT_MAXROUNDSROOT -1 /**< maximal number of separation rounds in the root node (-1: unlimited) */
113#define DEFAULT_MAXSEPACUTS 50 /**< maximal number of cuts separated per separation round */
114#define DEFAULT_MAXSEPACUTSROOT 200 /**< maximal number of cuts separated per separation round in the root node */
115#define DEFAULT_MAXCARDBOUNDDIST 0.0 /**< maximal relative distance from current node's dual bound to primal bound compared
116 * to best node's dual bound for separating knapsack cuts */
117#define DEFAULT_DISAGGREGATION TRUE /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
118#define DEFAULT_SIMPLIFYINEQUALITIES TRUE/**< should presolving try to simplify knapsacks */
119#define DEFAULT_NEGATEDCLIQUE TRUE /**< should negated clique information be used in solving process */
120
121#define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds used for knapsack relaxation */
122#define USESUPADDLIFT FALSE /**< should lifted minimal cover inequalities using superadditive up-lifting be separated in addition */
123
124#define DEFAULT_PRESOLUSEHASHING TRUE /**< should hash table be used for detecting redundant constraints in advance */
125#define HASHSIZE_KNAPSACKCONS 500 /**< minimal size of hash table in linear constraint tables */
126
127#define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
128#define NMINCOMPARISONS 200000 /**< number for minimal pairwise presolving comparisons */
129#define MINGAINPERNMINCOMPARISONS 1e-06 /**< minimal gain per minimal pairwise presolving comparisons to repeat pairwise
130 * comparison round */
131#define DEFAULT_DUALPRESOLVING TRUE /**< should dual presolving steps be performed? */
132#define DEFAULT_DETECTCUTOFFBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
133 * function defining an upper bound and prevent these constraints from
134 * entering the LP */
135#define DEFAULT_DETECTLOWERBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
136 * function defining a lower bound and prevent these constraints from
137 * entering the LP */
138#define DEFAULT_CLIQUEEXTRACTFACTOR 0.5 /**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
139#define MAXCOVERSIZEITERLEWI 1000 /**< maximal size for which LEWI are iteratively separated by reducing the feasible set */
140
141#define DEFAULT_USEGUBS FALSE /**< should GUB information be used for separation? */
142#define GUBCONSGROWVALUE 6 /**< memory growing value for GUB constraint array */
143#define GUBSPLITGNC1GUBS FALSE /**< should GNC1 GUB conss without F vars be split into GOC1 and GR GUB conss? */
144#define DEFAULT_CLQPARTUPDATEFAC 1.5 /**< factor on the growth of global cliques to decide when to update a previous
145 * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
146#define DEFAULT_UPDATECLIQUEPARTITIONS FALSE /**< should clique partition information be updated when old partition seems outdated? */
147#define MAXNCLIQUEVARSCOMP 1000000 /**< limit on number of pairwise comparisons in clique partitioning algorithm */
148#ifdef WITH_CARDINALITY_UPGRADE
149#define DEFAULT_UPGDCARDINALITY FALSE /**< if TRUE then try to update knapsack constraints to cardinality constraints */
150#endif
151
152/* @todo maybe use event SCIP_EVENTTYPE_VARUNLOCKED to decide for another dual-presolving run on a constraint */
153
154/*
155 * Data structures
156 */
157
158/** constraint handler data */
159struct SCIP_ConshdlrData
160{
161 int* ints1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
162 * you have to clear it at the end, exists only in presolving stage */
163 int* ints2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
164 * you have to clear it at the end, exists only in presolving stage */
165 SCIP_Longint* longints1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
166 * you have to clear it at the end, exists only in presolving stage */
167 SCIP_Longint* longints2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
168 * you have to clear it at the end, exists only in presolving stage */
169 SCIP_Bool* bools1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
170 * you have to clear it at the end, exists only in presolving stage */
171 SCIP_Bool* bools2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
172 * you have to clear it at the end, exists only in presolving stage */
173 SCIP_Bool* bools3; /**< cleared memory array, all entries are set to zero in initpre, if you use this
174 * you have to clear it at the end, exists only in presolving stage */
175 SCIP_Bool* bools4; /**< cleared memory array, all entries are set to zero in initpre, if you use this
176 * you have to clear it at the end, exists only in presolving stage */
177 SCIP_Real* reals1; /**< cleared memory array, all entries are set to zero in consinit, if you use this
178 * you have to clear it at the end */
179 int ints1size; /**< size of ints1 array */
180 int ints2size; /**< size of ints2 array */
181 int longints1size; /**< size of longints1 array */
182 int longints2size; /**< size of longints2 array */
183 int bools1size; /**< size of bools1 array */
184 int bools2size; /**< size of bools2 array */
185 int bools3size; /**< size of bools3 array */
186 int bools4size; /**< size of bools4 array */
187 int reals1size; /**< size of reals1 array */
188 SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
189 SCIP_Real maxcardbounddist; /**< maximal relative distance from current node's dual bound to primal bound compared
190 * to best node's dual bound for separating knapsack cuts */
191 int sepacardfreq; /**< multiplier on separation frequency, how often knapsack cuts are separated */
192 int maxrounds; /**< maximal number of separation rounds per node (-1: unlimited) */
193 int maxroundsroot; /**< maximal number of separation rounds in the root node (-1: unlimited) */
194 int maxsepacuts; /**< maximal number of cuts separated per separation round */
195 int maxsepacutsroot; /**< maximal number of cuts separated per separation round in the root node */
196 SCIP_Bool disaggregation; /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
197 SCIP_Bool simplifyinequalities;/**< should presolving try to cancel down or delete coefficients in inequalities */
198 SCIP_Bool negatedclique; /**< should negated clique information be used in solving process */
199 SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
200 SCIP_Bool presolusehashing; /**< should hash table be used for detecting redundant constraints in advance */
201 SCIP_Bool dualpresolving; /**< should dual presolving steps be performed? */
202 SCIP_Bool usegubs; /**< should GUB information be used for separation? */
203 SCIP_Bool detectcutoffbound; /**< should presolving try to detect constraints parallel to the objective
204 * function defining an upper bound and prevent these constraints from
205 * entering the LP */
206 SCIP_Bool detectlowerbound; /**< should presolving try to detect constraints parallel to the objective
207 * function defining a lower bound and prevent these constraints from
208 * entering the LP */
209 SCIP_Bool updatecliquepartitions; /**< should clique partition information be updated when old partition seems outdated? */
210 SCIP_Real cliqueextractfactor;/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
211 SCIP_Real clqpartupdatefac; /**< factor on the growth of global cliques to decide when to update a previous
212 * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
213#ifdef WITH_CARDINALITY_UPGRADE
214 SCIP_Bool upgdcardinality; /**< if TRUE then try to update knapsack constraints to cardinality constraints */
215 SCIP_Bool upgradedcard; /**< whether we have already upgraded knapsack constraints to cardinality constraints */
216#endif
217};
218
219
220/** constraint data for knapsack constraints */
221struct SCIP_ConsData
222{
223 SCIP_VAR** vars; /**< variables in knapsack constraint */
224 SCIP_Longint* weights; /**< weights of variables in knapsack constraint */
225 SCIP_EVENTDATA** eventdata; /**< event data for bound change events of the variables */
226 int* cliquepartition; /**< clique indices of the clique partition */
227 int* negcliquepartition; /**< clique indices of the negated clique partition */
228 SCIP_ROW* row; /**< corresponding LP row */
229 SCIP_NLROW* nlrow; /**< corresponding NLP row */
230 int nvars; /**< number of variables in knapsack constraint */
231 int varssize; /**< size of vars, weights, and eventdata arrays */
232 int ncliques; /**< number of cliques in the clique partition */
233 int nnegcliques; /**< number of cliques in the negated clique partition */
234 int ncliqueslastnegpart;/**< number of global cliques the last time a negated clique partition was computed */
235 int ncliqueslastpart; /**< number of global cliques the last time a clique partition was computed */
236 SCIP_Longint capacity; /**< capacity of knapsack */
237 SCIP_Longint weightsum; /**< sum of all weights */
238 SCIP_Longint onesweightsum; /**< sum of weights of variables fixed to one */
239 unsigned int presolvedtiming:5; /**< max level in which the knapsack constraint is already presolved */
240 unsigned int sorted:1; /**< are the knapsack items sorted by weight? */
241 unsigned int cliquepartitioned:1;/**< is the clique partition valid? */
242 unsigned int negcliquepartitioned:1;/**< is the negated clique partition valid? */
243 unsigned int merged:1; /**< are the constraint's equal variables already merged? */
244 unsigned int cliquesadded:1; /**< were the cliques of the knapsack already added to clique table? */
245 unsigned int varsdeleted:1; /**< were variables deleted after last cleanup? */
246 unsigned int existmultaggr:1; /**< does this constraint contain multi-aggregations */
247};
248
249/** event data for bound changes events */
250struct SCIP_EventData
251{
252 SCIP_CONS* cons; /**< knapsack constraint to process the bound change for */
253 SCIP_Longint weight; /**< weight of variable */
254 int filterpos; /**< position of event in variable's event filter */
255};
256
257
258/** data structure to combine two sorting key values */
259struct sortkeypair
260{
261 SCIP_Real key1; /**< first sort key value */
262 SCIP_Real key2; /**< second sort key value */
263};
264typedef struct sortkeypair SORTKEYPAIR;
265
266/** status of GUB constraint */
268{
269 GUBVARSTATUS_UNINITIAL = -1, /** unintitialized variable status */
270 GUBVARSTATUS_CAPACITYEXCEEDED = 0, /** variable with weight exceeding the knapsack capacity */
271 GUBVARSTATUS_BELONGSTOSET_R = 1, /** variable in noncovervars R */
272 GUBVARSTATUS_BELONGSTOSET_F = 2, /** variable in noncovervars F */
273 GUBVARSTATUS_BELONGSTOSET_C2 = 3, /** variable in covervars C2 */
274 GUBVARSTATUS_BELONGSTOSET_C1 = 4 /** variable in covervars C1 */
277
278/** status of variable in GUB constraint */
280{
281 GUBCONSSTATUS_UNINITIAL = -1, /** unintitialized GUB constraint status */
282 GUBCONSSTATUS_BELONGSTOSET_GR = 0, /** all GUB variables are in noncovervars R */
283 GUBCONSSTATUS_BELONGSTOSET_GF = 1, /** all GUB variables are in noncovervars F (and noncovervars R) */
284 GUBCONSSTATUS_BELONGSTOSET_GC2 = 2, /** all GUB variables are in covervars C2 */
285 GUBCONSSTATUS_BELONGSTOSET_GNC1 = 3, /** some GUB variables are in covervars C1, others in noncovervars R or F */
286 GUBCONSSTATUS_BELONGSTOSET_GOC1 = 4 /** all GUB variables are in covervars C1 */
289
290/** data structure of GUB constraints */
292{
293 int* gubvars; /**< indices of GUB variables in knapsack constraint */
294 GUBVARSTATUS* gubvarsstatus; /**< status of GUB variables */
295 int ngubvars; /**< number of GUB variables */
296 int gubvarssize; /**< size of gubvars array */
297};
299
300/** data structure of a set of GUB constraints */
302{
303 SCIP_GUBCONS** gubconss; /**< GUB constraints in GUB set */
304 GUBCONSSTATUS* gubconsstatus; /**< status of GUB constraints */
305 int ngubconss; /**< number of GUB constraints */
306 int nvars; /**< number of variables in knapsack constraint */
307 int* gubconssidx; /**< index of GUB constraint (in gubconss array) of each knapsack variable */
308 int* gubvarsidx; /**< index in GUB constraint (in gubvars array) of each knapsack variable */
309};
311
312/*
313 * Local methods
314 */
315
316/** comparison method for two sorting key pairs */
317static
319{
322
323 if( sortkeypair1->key1 < sortkeypair2->key1 )
324 return -1;
325 else if( sortkeypair1->key1 > sortkeypair2->key1 )
326 return +1;
327 else if( sortkeypair1->key2 < sortkeypair2->key2 )
328 return -1;
329 else if( sortkeypair1->key2 > sortkeypair2->key2 )
330 return +1;
331 else
332 return 0;
333}
334
335/** creates event data */
336static
338 SCIP* scip, /**< SCIP data structure */
339 SCIP_EVENTDATA** eventdata, /**< pointer to store event data */
340 SCIP_CONS* cons, /**< constraint */
341 SCIP_Longint weight /**< weight of variable */
342 )
343{
344 assert(eventdata != NULL);
345
346 SCIP_CALL( SCIPallocBlockMemory(scip, eventdata) );
347 (*eventdata)->cons = cons;
348 (*eventdata)->weight = weight;
349
350 return SCIP_OKAY;
351}
352
353/** frees event data */
354static
356 SCIP* scip, /**< SCIP data structure */
357 SCIP_EVENTDATA** eventdata /**< pointer to event data */
358 )
359{
360 assert(eventdata != NULL);
361
362 SCIPfreeBlockMemory(scip, eventdata);
363
364 return SCIP_OKAY;
365}
366
367/** sorts items in knapsack with nonincreasing weights */
368static
370 SCIP_CONSDATA* consdata /**< constraint data */
371 )
372{
373 assert(consdata != NULL);
374 assert(consdata->nvars == 0 || consdata->vars != NULL);
375 assert(consdata->nvars == 0 || consdata->weights != NULL);
376 assert(consdata->nvars == 0 || consdata->eventdata != NULL);
377 assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
378
379 if( !consdata->sorted )
380 {
381 int pos;
382 int lastcliquenum;
383 int v;
384
385 /* sort of five joint arrays of Long/pointer/pointer/ints/ints,
386 * sorted by first array in non-increasing order via sort template */
388 consdata->weights,
389 (void**)consdata->vars,
390 (void**)consdata->eventdata,
391 consdata->cliquepartition,
392 consdata->negcliquepartition,
393 consdata->nvars);
394
395 v = consdata->nvars - 1;
396 /* sort all items with same weight according to their variable index, used for hash value for fast pairwise comparison of all constraints */
397 while( v >= 0 )
398 {
399 int w = v - 1;
400
401 while( w >= 0 && consdata->weights[v] == consdata->weights[w] )
402 --w;
403
404 if( v - w > 1 )
405 {
406 /* sort all corresponding parts of arrays for which the weights are equal by using the variable index */
408 (void**)(&(consdata->vars[w+1])),
409 (void**)(&(consdata->eventdata[w+1])),
410 &(consdata->cliquepartition[w+1]),
411 &(consdata->negcliquepartition[w+1]),
413 v - w);
414 }
415 v = w;
416 }
417
418 /* we need to make sure that our clique numbers of our normal clique will be in increasing order without gaps */
419 if( consdata->cliquepartitioned )
420 {
421 lastcliquenum = 0;
422
423 for( pos = 0; pos < consdata->nvars; ++pos )
424 {
425 /* if the clique number in the normal clique at position pos is greater than the last found clique number the
426 * partition is invalid */
427 if( consdata->cliquepartition[pos] > lastcliquenum )
428 {
429 consdata->cliquepartitioned = FALSE;
430 break;
431 }
432 else if( consdata->cliquepartition[pos] == lastcliquenum )
434 }
435 }
436 /* we need to make sure that our clique numbers of our negated clique will be in increasing order without gaps */
437 if( consdata->negcliquepartitioned )
438 {
439 lastcliquenum = 0;
440
441 for( pos = 0; pos < consdata->nvars; ++pos )
442 {
443 /* if the clique number in the negated clique at position pos is greater than the last found clique number the
444 * partition is invalid */
445 if( consdata->negcliquepartition[pos] > lastcliquenum )
446 {
447 consdata->negcliquepartitioned = FALSE;
448 break;
449 }
450 else if( consdata->negcliquepartition[pos] == lastcliquenum )
452 }
453 }
454
455 consdata->sorted = TRUE;
456 }
457#ifndef NDEBUG
458 {
459 /* check if the weight array is sorted in a non-increasing way */
460 int i;
461 for( i = 0; i < consdata->nvars-1; ++i )
462 assert(consdata->weights[i] >= consdata->weights[i+1]);
463 }
464#endif
465}
466
467/** calculates a partition of the variables into cliques */
468static
470 SCIP* scip, /**< SCIP data structure */
471 SCIP_CONSHDLRDATA* conshdlrdata, /**< knapsack constraint handler data */
472 SCIP_CONSDATA* consdata, /**< constraint data */
473 SCIP_Bool normalclique, /**< Should normal cliquepartition be created? */
474 SCIP_Bool negatedclique /**< Should negated cliquepartition be created? */
475 )
476{
477 SCIP_Bool ispartitionoutdated;
478 SCIP_Bool isnegpartitionoutdated;
479 assert(consdata != NULL);
480 assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
481
482 /* rerun eventually if number of global cliques increased considerably since last partition */
483 ispartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->ncliques > 1
484 && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastpart));
485
486 if( normalclique && ( !consdata->cliquepartitioned || ispartitionoutdated ) )
487 {
488 SCIP_CALL( SCIPcalcCliquePartition(scip, consdata->vars, consdata->nvars, consdata->cliquepartition, &consdata->ncliques) );
489 consdata->cliquepartitioned = TRUE;
490 consdata->ncliqueslastpart = SCIPgetNCliques(scip);
491 }
492
493 /* rerun eventually if number of global cliques increased considerably since last negated partition */
494 isnegpartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->nnegcliques > 1
495 && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastnegpart));
496
497 if( negatedclique && (!consdata->negcliquepartitioned || isnegpartitionoutdated) )
498 {
499 SCIP_CALL( SCIPcalcNegatedCliquePartition(scip, consdata->vars, consdata->nvars, consdata->negcliquepartition, &consdata->nnegcliques) );
500 consdata->negcliquepartitioned = TRUE;
501 consdata->ncliqueslastnegpart = SCIPgetNCliques(scip);
502 }
503 assert(!consdata->cliquepartitioned || consdata->ncliques <= consdata->nvars);
504 assert(!consdata->negcliquepartitioned || consdata->nnegcliques <= consdata->nvars);
505
506 return SCIP_OKAY;
507}
508
509/** installs rounding locks for the given variable in the given knapsack constraint */
510static
512 SCIP* scip, /**< SCIP data structure */
513 SCIP_CONS* cons, /**< knapsack constraint */
514 SCIP_VAR* var /**< variable of constraint entry */
515 )
516{
518
519 return SCIP_OKAY;
520}
521
522/** removes rounding locks for the given variable in the given knapsack constraint */
523static
525 SCIP* scip, /**< SCIP data structure */
526 SCIP_CONS* cons, /**< knapsack constraint */
527 SCIP_VAR* var /**< variable of constraint entry */
528 )
529{
531
532 return SCIP_OKAY;
533}
534
535/** catches bound change events for variables in knapsack */
536static
538 SCIP* scip, /**< SCIP data structure */
539 SCIP_CONS* cons, /**< constraint */
540 SCIP_CONSDATA* consdata, /**< constraint data */
541 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
542 )
543{
544 int i;
545
546 assert(cons != NULL);
547 assert(consdata != NULL);
548 assert(consdata->nvars == 0 || consdata->vars != NULL);
549 assert(consdata->nvars == 0 || consdata->weights != NULL);
550 assert(consdata->nvars == 0 || consdata->eventdata != NULL);
551
552 for( i = 0; i < consdata->nvars; i++)
553 {
554 SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[i], cons, consdata->weights[i]) );
556 eventhdlr, consdata->eventdata[i], &consdata->eventdata[i]->filterpos) );
557 }
558
559 return SCIP_OKAY;
560}
561
562/** drops bound change events for variables in knapsack */
563static
565 SCIP* scip, /**< SCIP data structure */
566 SCIP_CONSDATA* consdata, /**< constraint data */
567 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
568 )
569{
570 int i;
571
572 assert(consdata != NULL);
573 assert(consdata->nvars == 0 || consdata->vars != NULL);
574 assert(consdata->nvars == 0 || consdata->weights != NULL);
575 assert(consdata->nvars == 0 || consdata->eventdata != NULL);
576
577 for( i = 0; i < consdata->nvars; i++)
578 {
580 eventhdlr, consdata->eventdata[i], consdata->eventdata[i]->filterpos) );
581 SCIP_CALL( eventdataFree(scip, &consdata->eventdata[i]) );
582 }
583
584 return SCIP_OKAY;
585}
586
587/** ensures, that vars and vals arrays can store at least num entries */
588static
590 SCIP* scip, /**< SCIP data structure */
591 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
592 int num, /**< minimum number of entries to store */
593 SCIP_Bool transformed /**< is constraint from transformed problem? */
594 )
595{
596 assert(consdata != NULL);
597 assert(consdata->nvars <= consdata->varssize);
598
599 if( num > consdata->varssize )
600 {
601 int newsize;
602
604 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) );
605 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->weights, consdata->varssize, newsize) );
606 if( transformed )
607 {
608 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->eventdata, consdata->varssize, newsize) );
609 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->cliquepartition, consdata->varssize, newsize) );
610 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->negcliquepartition, consdata->varssize, newsize) );
611 }
612 else
613 {
614 assert(consdata->eventdata == NULL);
615 assert(consdata->cliquepartition == NULL);
616 assert(consdata->negcliquepartition == NULL);
617 }
618 consdata->varssize = newsize;
619 }
620 assert(num <= consdata->varssize);
621
622 return SCIP_OKAY;
623}
624
625/** updates all weight sums for fixed and unfixed variables */
626static
628 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
629 SCIP_VAR* var, /**< variable for this weight */
630 SCIP_Longint weightdelta /**< difference between the old and the new weight of the variable */
631 )
632{
633 assert(consdata != NULL);
634 assert(var != NULL);
635
636 consdata->weightsum += weightdelta;
637
638 if( SCIPvarGetLbLocal(var) > 0.5 )
639 consdata->onesweightsum += weightdelta;
640
641 assert(consdata->weightsum >= 0);
642 assert(consdata->onesweightsum >= 0);
643}
644
645/** creates knapsack constraint data */
646static
648 SCIP* scip, /**< SCIP data structure */
649 SCIP_CONSDATA** consdata, /**< pointer to store constraint data */
650 int nvars, /**< number of variables in knapsack */
651 SCIP_VAR** vars, /**< variables of knapsack */
652 SCIP_Longint* weights, /**< weights of knapsack items */
653 SCIP_Longint capacity /**< capacity of knapsack */
654 )
655{
656 int v;
657 SCIP_Longint constant;
658
659 assert(consdata != NULL);
660
661 SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
662
663 constant = 0L;
664 (*consdata)->vars = NULL;
665 (*consdata)->weights = NULL;
666 (*consdata)->nvars = 0;
667 if( nvars > 0 )
668 {
670 SCIP_Longint* weightsbuffer;
671 int k;
672
675
676 k = 0;
677 for( v = 0; v < nvars; ++v )
678 {
679 assert(vars[v] != NULL);
681
682 /* all weight have to be non negative */
683 assert( weights[v] >= 0 );
684
685 if( weights[v] > 0 )
686 {
687 /* treat fixed variables as constants if problem compression is enabled */
689 {
690 /* only if the variable is fixed to 1, we add its weight to the constant */
691 if( SCIPvarGetUbGlobal(vars[v]) > 0.5 )
692 constant += weights[v];
693 }
694 else
695 {
696 varsbuffer[k] = vars[v];
697 weightsbuffer[k] = weights[v];
698 ++k;
699 }
700 }
701 }
702 assert(k >= 0);
703 assert(constant >= 0);
704
705 (*consdata)->nvars = k;
706
707 /* copy the active variables and weights into the constraint data structure */
708 if( k > 0 )
709 {
710 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, varsbuffer, k) );
711 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->weights, weightsbuffer, k) );
712 }
713
714 /* free buffer storage */
717 }
718
719 (*consdata)->varssize = (*consdata)->nvars;
720 (*consdata)->capacity = capacity - constant;
721 (*consdata)->eventdata = NULL;
722 (*consdata)->cliquepartition = NULL;
723 (*consdata)->negcliquepartition = NULL;
724 (*consdata)->row = NULL;
725 (*consdata)->nlrow = NULL;
726 (*consdata)->weightsum = 0;
727 (*consdata)->onesweightsum = 0;
728 (*consdata)->ncliques = 0;
729 (*consdata)->nnegcliques = 0;
730 (*consdata)->presolvedtiming = 0;
731 (*consdata)->sorted = FALSE;
732 (*consdata)->cliquepartitioned = FALSE;
733 (*consdata)->negcliquepartitioned = FALSE;
734 (*consdata)->ncliqueslastpart = -1;
735 (*consdata)->ncliqueslastnegpart = -1;
736 (*consdata)->merged = FALSE;
737 (*consdata)->cliquesadded = FALSE;
738 (*consdata)->varsdeleted = FALSE;
739 (*consdata)->existmultaggr = FALSE;
740
741 /* get transformed variables, if we are in the transformed problem */
743 {
744 SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
745
746 for( v = 0; v < (*consdata)->nvars; v++ )
747 {
748 SCIP_VAR* var = SCIPvarGetProbvar((*consdata)->vars[v]);
749 assert(var != NULL);
750 (*consdata)->existmultaggr = (*consdata)->existmultaggr || (SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
751 }
752
753 /* allocate memory for additional data structures */
754 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->nvars) );
755 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->nvars) );
756 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->nvars) );
757 }
758
759 /* calculate sum of weights and capture variables */
760 for( v = 0; v < (*consdata)->nvars; ++v )
761 {
762 /* calculate sum of weights */
763 updateWeightSums(*consdata, (*consdata)->vars[v], (*consdata)->weights[v]);
764
765 /* capture variables */
766 SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) );
767 }
768 return SCIP_OKAY;
769}
770
771/** frees knapsack constraint data */
772static
774 SCIP* scip, /**< SCIP data structure */
775 SCIP_CONSDATA** consdata, /**< pointer to the constraint data */
776 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
777 )
778{
779 assert(consdata != NULL);
780 assert(*consdata != NULL);
781
782 if( (*consdata)->row != NULL )
783 {
784 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->row) );
785 }
786 if( (*consdata)->nlrow != NULL )
787 {
788 SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
789 }
790 if( (*consdata)->eventdata != NULL )
791 {
792 SCIP_CALL( dropEvents(scip, *consdata, eventhdlr) );
793 SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->varssize);
794 }
795 if( (*consdata)->negcliquepartition != NULL )
796 {
797 SCIPfreeBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->varssize);
798 }
799 if( (*consdata)->cliquepartition != NULL )
800 {
801 SCIPfreeBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->varssize);
802 }
803 if( (*consdata)->vars != NULL )
804 {
805 int v;
806
807 /* release variables */
808 for( v = 0; v < (*consdata)->nvars; v++ )
809 {
810 assert((*consdata)->vars[v] != NULL);
811 SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->vars[v])) );
812 }
813
814 assert( (*consdata)->weights != NULL );
815 assert( (*consdata)->varssize > 0 );
816 SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->varssize);
817 SCIPfreeBlockMemoryArray(scip, &(*consdata)->weights, (*consdata)->varssize);
818 }
819
820 SCIPfreeBlockMemory(scip, consdata);
821
822 return SCIP_OKAY;
823}
824
825/** changes a single weight in knapsack constraint data */
826static
828 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
829 int item, /**< item number */
830 SCIP_Longint newweight /**< new weight of item */
831 )
832{
833 SCIP_Longint oldweight;
834 SCIP_Longint weightdiff;
835
836 assert(consdata != NULL);
838
839 oldweight = consdata->weights[item];
841 consdata->weights[item] = newweight;
842
843 /* update weight sums for all and fixed variables */
844 updateWeightSums(consdata, consdata->vars[item], weightdiff);
845
846 if( consdata->eventdata != NULL )
847 {
848 assert(consdata->eventdata[item] != NULL);
849 assert(consdata->eventdata[item]->weight == oldweight);
850 consdata->eventdata[item]->weight = newweight;
851 }
852
853 consdata->presolvedtiming = 0;
854 consdata->sorted = FALSE;
855
856 /* recalculate cliques extraction after a weight was increased */
857 if( oldweight < newweight )
858 {
859 consdata->cliquesadded = FALSE;
860 }
861}
862
863/** creates LP row corresponding to knapsack constraint */
864static
866 SCIP* scip, /**< SCIP data structure */
867 SCIP_CONS* cons /**< knapsack constraint */
868 )
869{
870 SCIP_CONSDATA* consdata;
871 int i;
872
873 consdata = SCIPconsGetData(cons);
874 assert(consdata != NULL);
875 assert(consdata->row == NULL);
876
877 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, cons, SCIPconsGetName(cons),
878 -SCIPinfinity(scip), (SCIP_Real)consdata->capacity,
880
881 SCIP_CALL( SCIPcacheRowExtensions(scip, consdata->row) );
882 for( i = 0; i < consdata->nvars; ++i )
883 {
884 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, consdata->vars[i], (SCIP_Real)consdata->weights[i]) );
885 }
886 SCIP_CALL( SCIPflushRowExtensions(scip, consdata->row) );
887
888 return SCIP_OKAY;
889}
890
891/** adds linear relaxation of knapsack constraint to the LP */
892static
894 SCIP* scip, /**< SCIP data structure */
895 SCIP_CONS* cons, /**< knapsack constraint */
896 SCIP_Bool* cutoff /**< whether a cutoff has been detected */
897 )
898{
899 SCIP_CONSDATA* consdata;
900
901 assert( cutoff != NULL );
902 *cutoff = FALSE;
903
904 consdata = SCIPconsGetData(cons);
905 assert(consdata != NULL);
906
907 if( consdata->row == NULL )
908 {
910 }
911 assert(consdata->row != NULL);
912
913 /* insert LP row as cut */
914 if( !SCIProwIsInLP(consdata->row) )
915 {
916 SCIPdebugMsg(scip, "adding relaxation of knapsack constraint <%s> (capacity %" SCIP_LONGINT_FORMAT "): ",
917 SCIPconsGetName(cons), consdata->capacity);
918 SCIPdebug( SCIP_CALL(SCIPprintRow(scip, consdata->row, NULL)) );
919 SCIP_CALL( SCIPaddRow(scip, consdata->row, FALSE, cutoff) );
920 }
921
922 return SCIP_OKAY;
923}
924
925/** adds knapsack constraint as row to the NLP, if not added yet */
926static
928 SCIP* scip, /**< SCIP data structure */
929 SCIP_CONS* cons /**< knapsack constraint */
930 )
931{
932 SCIP_CONSDATA* consdata;
933
935
936 /* skip deactivated, redundant, or local linear constraints (the NLP does not allow for local rows at the moment) */
937 if( !SCIPconsIsActive(cons) || !SCIPconsIsChecked(cons) || SCIPconsIsLocal(cons) )
938 return SCIP_OKAY;
939
940 consdata = SCIPconsGetData(cons);
941 assert(consdata != NULL);
942
943 if( consdata->nlrow == NULL )
944 {
945 SCIP_Real* coefs;
946 int i;
947
948 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, consdata->nvars) );
949 for( i = 0; i < consdata->nvars; ++i )
950 coefs[i] = (SCIP_Real)consdata->weights[i]; /*lint !e613*/
951
952 SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
953 consdata->nvars, consdata->vars, coefs, NULL,
954 -SCIPinfinity(scip), (SCIP_Real)consdata->capacity, SCIP_EXPRCURV_LINEAR) );
955
956 assert(consdata->nlrow != NULL);
957
958 SCIPfreeBufferArray(scip, &coefs);
959 }
960
961 if( !SCIPnlrowIsInNLP(consdata->nlrow) )
962 {
963 SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
964 }
965
966 return SCIP_OKAY;
967}
968
969/** checks knapsack constraint for feasibility of given solution: returns TRUE iff constraint is feasible */
970static
972 SCIP* scip, /**< SCIP data structure */
973 SCIP_CONS* cons, /**< constraint to check */
974 SCIP_SOL* sol, /**< solution to check, NULL for current solution */
975 SCIP_Bool checklprows, /**< Do constraints represented by rows in the current LP have to be checked? */
976 SCIP_Bool printreason, /**< Should the reason for the violation be printed? */
977 SCIP_Bool* violated /**< pointer to store whether the constraint is violated */
978 )
979{
980 SCIP_CONSDATA* consdata;
981
982 assert(violated != NULL);
983
984 consdata = SCIPconsGetData(cons);
985 assert(consdata != NULL);
986
987 SCIPdebugMsg(scip, "checking knapsack constraint <%s> for feasibility of solution %p (lprows=%u)\n",
988 SCIPconsGetName(cons), (void*)sol, checklprows);
989
990 *violated = FALSE;
991
992 if( checklprows || consdata->row == NULL || !SCIProwIsInLP(consdata->row) )
993 {
994 SCIP_Real sum;
995 SCIP_Longint integralsum;
996 SCIP_Bool ishuge;
997 SCIP_Real absviol;
998 SCIP_Real relviol;
999 int v;
1000
1001 /* increase age of constraint; age is reset to zero, if a violation was found only in case we are in
1002 * enforcement
1003 */
1004 if( sol == NULL )
1005 {
1006 SCIP_CALL( SCIPincConsAge(scip, cons) );
1007 }
1008
1009 sum = 0.0;
1010 integralsum = 0;
1011 /* we perform a more exact comparison if the capacity does not exceed the huge value */
1012 if( SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
1013 {
1014 ishuge = TRUE;
1015
1016 /* sum over all weight times the corresponding solution value */
1017 for( v = consdata->nvars - 1; v >= 0; --v )
1018 {
1019 assert(SCIPvarIsBinary(consdata->vars[v]));
1020 sum += consdata->weights[v] * SCIPgetSolVal(scip, sol, consdata->vars[v]);
1021 }
1022 }
1023 else
1024 {
1025 ishuge = FALSE;
1026
1027 /* sum over all weight for which the variable has a solution value of 1 in feastol */
1028 for( v = consdata->nvars - 1; v >= 0; --v )
1029 {
1030 assert(SCIPvarIsBinary(consdata->vars[v]));
1031
1032 if( SCIPgetSolVal(scip, sol, consdata->vars[v]) > 0.5 )
1033 integralsum += consdata->weights[v];
1034 }
1035 }
1036
1037 /* calculate constraint violation and update it in solution */
1039 absviol -= consdata->capacity;
1040 relviol = SCIPrelDiff(absviol + consdata->capacity, (SCIP_Real)consdata->capacity);
1041 if( sol != NULL )
1043
1045 {
1046 *violated = TRUE;
1047
1048 /* only reset constraint age if we are in enforcement */
1049 if( sol == NULL )
1050 {
1052 }
1053
1054 if( printreason )
1055 {
1056 SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
1057
1058 SCIPinfoMessage(scip, NULL, ";\n");
1059 SCIPinfoMessage(scip, NULL, "violation: the capacity is violated by %.15g\n", absviol);
1060 }
1061 }
1062 }
1063
1064 return SCIP_OKAY;
1065}
1066
1067/* IDX computes the integer index for the optimal solution array */
1068#define IDX(j,d) ((j)*(intcap)+(d))
1069
1070/** solves knapsack problem in maximization form exactly using dynamic programming;
1071 * if needed, one can provide arrays to store all selected items and all not selected items
1072 *
1073 * @note in case you provide the solitems or nonsolitems array you also have to provide the counter part, as well
1074 *
1075 * @note the algorithm will first compute a greedy solution and terminate
1076 * if the greedy solution is proven to be optimal.
1077 * The dynamic programming algorithm runs with a time and space complexity
1078 * of O(nitems * capacity).
1079 *
1080 * @todo If only the objective is relevant, it is easy to change the code to use only one slice with O(capacity) space.
1081 * There are recursive methods (see the book by Kellerer et al.) that require O(capacity) space, but it remains
1082 * to be checked whether they are faster and whether they can reconstruct the solution.
1083 * Dembo and Hammer (see Kellerer et al. Section 5.1.3, page 126) found a method that relies on a fast probing method.
1084 * This fixes additional elements to 0 or 1 similar to a reduced cost fixing.
1085 * This could be implemented, however, it would be technically a bit cumbersome,
1086 * since one needs the greedy solution and the LP-value for this.
1087 * This is currently only available after the redundant items have already been sorted out.
1088 */
1090 SCIP* scip, /**< SCIP data structure */
1091 int nitems, /**< number of available items */
1092 SCIP_Longint* weights, /**< item weights */
1093 SCIP_Real* profits, /**< item profits */
1094 SCIP_Longint capacity, /**< capacity of knapsack */
1095 int* items, /**< item numbers */
1096 int* solitems, /**< array to store items in solution, or NULL */
1097 int* nonsolitems, /**< array to store items not in solution, or NULL */
1098 int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1099 int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1100 SCIP_Real* solval, /**< pointer to store optimal solution value, or NULL */
1101 SCIP_Bool* success /**< pointer to store if an error occured during solving
1102 * (normally a memory problem) */
1103 )
1104{
1105 SCIP_RETCODE retcode;
1106 SCIP_Real* tempsort;
1107 SCIP_Real* optvalues;
1108 int intcap;
1109 int d;
1110 int j;
1111 int greedymedianpos;
1112 SCIP_Longint weightsum;
1113 int* myitems;
1114 SCIP_Longint* myweights;
1115 SCIP_Real* realweights;
1116 int* allcurrminweight;
1117 SCIP_Real* myprofits;
1118 int nmyitems;
1119 SCIP_Longint gcd;
1120 SCIP_Longint minweight;
1121 SCIP_Longint maxweight;
1122 int currminweight;
1123 SCIP_Longint greedysolweight;
1124 SCIP_Real greedysolvalue;
1125 SCIP_Real greedyupperbound;
1126 SCIP_Bool eqweights;
1127 SCIP_Bool intprofits;
1128
1129 assert(weights != NULL);
1130 assert(profits != NULL);
1131 assert(capacity >= 0);
1132 assert(items != NULL);
1133 assert(nitems >= 0);
1134 assert(success != NULL);
1135
1136 *success = TRUE;
1137
1138#ifndef NDEBUG
1139 for( j = nitems - 1; j >= 0; --j )
1140 assert(weights[j] >= 0);
1141#endif
1142
1143 SCIPdebugMsg(scip, "Solving knapsack exactly.\n");
1144
1145 /* initializing solution value */
1146 if( solval != NULL )
1147 *solval = 0.0;
1148
1149 /* init solution information */
1150 if( solitems != NULL )
1151 {
1152 assert(items != NULL);
1153 assert(nsolitems != NULL);
1156
1157 *nnonsolitems = 0;
1158 *nsolitems = 0;
1159 }
1160
1161 /* allocate temporary memory */
1165 nmyitems = 0;
1166 weightsum = 0;
1167 minweight = SCIP_LONGINT_MAX;
1168 maxweight = 0;
1169
1170 /* remove unnecessary items */
1171 for( j = 0; j < nitems; ++j )
1172 {
1173 assert(0 <= weights[j] && weights[j] < SCIP_LONGINT_MAX);
1174
1175 /* item does not fit */
1176 if( weights[j] > capacity )
1177 {
1178 if( solitems != NULL )
1179 nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
1180 }
1181 /* item is not profitable */
1182 else if( profits[j] <= 0.0 )
1183 {
1184 if( solitems != NULL )
1185 nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
1186 }
1187 /* item always fits */
1188 else if( weights[j] == 0 )
1189 {
1190 if( solitems != NULL )
1191 solitems[(*nsolitems)++] = items[j]; /*lint !e413*/
1192
1193 if( solval != NULL )
1194 *solval += profits[j];
1195 }
1196 /* all important items */
1197 else
1198 {
1199 myweights[nmyitems] = weights[j];
1201 myitems[nmyitems] = items[j];
1202
1203 /* remember smallest item */
1204 if( myweights[nmyitems] < minweight )
1205 minweight = myweights[nmyitems];
1206
1207 /* remember bigest item */
1208 if( myweights[nmyitems] > maxweight )
1209 maxweight = myweights[nmyitems];
1210
1211 weightsum += myweights[nmyitems];
1212 ++nmyitems;
1213 }
1214 }
1215
1216 intprofits = TRUE;
1217 /* check if all profits are integer to strengthen the upper bound on the greedy solution */
1218 for( j = 0; j < nmyitems && intprofits; ++j )
1220
1221 /* if no item is left then goto end */
1222 if( nmyitems == 0 )
1223 {
1224 SCIPdebugMsg(scip, "After preprocessing no items are left.\n");
1225
1226 goto TERMINATE;
1227 }
1228
1229 /* if all items fit, we also do not need to do the expensive stuff later on */
1230 if( weightsum > 0 && weightsum <= capacity )
1231 {
1232 SCIPdebugMsg(scip, "After preprocessing all items fit into knapsack.\n");
1233
1234 for( j = nmyitems - 1; j >= 0; --j )
1235 {
1236 if( solitems != NULL )
1237 solitems[(*nsolitems)++] = myitems[j]; /*lint !e413*/
1238
1239 if( solval != NULL )
1240 *solval += myprofits[j];
1241 }
1242
1243 goto TERMINATE;
1244 }
1245
1246 assert(0 < minweight && minweight <= capacity );
1247 assert(0 < maxweight && maxweight <= capacity);
1248
1249 /* make weights relatively prime */
1250 eqweights = TRUE;
1251 if( maxweight > 1 )
1252 {
1253 /* determine greatest common divisor */
1254 gcd = myweights[nmyitems - 1];
1255 for( j = nmyitems - 2; j >= 0 && gcd >= 2; --j )
1257
1258 SCIPdebugMsg(scip, "Gcd is %" SCIP_LONGINT_FORMAT ".\n", gcd);
1259
1260 /* divide by greatest common divisor */
1261 if( gcd > 1 )
1262 {
1263 for( j = nmyitems - 1; j >= 0; --j )
1264 {
1265 myweights[j] /= gcd;
1266 eqweights = eqweights && (myweights[j] == 1);
1267 }
1268 capacity /= gcd;
1269 minweight /= gcd;
1270 }
1271 else
1272 eqweights = FALSE;
1273 }
1274 assert(minweight <= capacity);
1275
1276 /* if only one item fits, then take the best */
1277 if( minweight > capacity / 2 )
1278 {
1279 int p;
1280
1281 SCIPdebugMsg(scip, "Only one item fits into knapsack, so take the best.\n");
1282
1283 p = nmyitems - 1;
1284
1285 /* find best item */
1286 for( j = nmyitems - 2; j >= 0; --j )
1287 {
1288 if( myprofits[j] > myprofits[p] )
1289 p = j;
1290 }
1291
1292 /* update solution information */
1293 if( solitems != NULL )
1294 {
1296
1297 solitems[(*nsolitems)++] = myitems[p];
1298 for( j = nmyitems - 1; j >= 0; --j )
1299 {
1300 if( j != p )
1301 nonsolitems[(*nnonsolitems)++] = myitems[j];
1302 }
1303 }
1304 /* update solution value */
1305 if( solval != NULL )
1306 *solval += myprofits[p];
1307
1308 goto TERMINATE;
1309 }
1310
1311 /* if all items have the same weight, then take the best */
1312 if( eqweights )
1313 {
1314 SCIP_Real addval = 0.0;
1315
1316 SCIPdebugMsg(scip, "All weights are equal, so take the best.\n");
1317
1319
1320 /* update solution information */
1321 if( solitems != NULL || solval != NULL )
1322 {
1323 SCIP_Longint i;
1324
1325 /* if all items would fit we had handled this case before */
1326 assert((SCIP_Longint) nmyitems > capacity);
1328
1329 /* take the first best items into the solution */
1330 for( i = capacity - 1; i >= 0; --i )
1331 {
1332 if( solitems != NULL )
1333 solitems[(*nsolitems)++] = myitems[i];
1334 addval += myprofits[i];
1335 }
1336
1337 if( solitems != NULL )
1338 {
1339 /* the rest are not in the solution */
1340 for( i = nmyitems - 1; i >= capacity; --i )
1342 }
1343 }
1344 /* update solution value */
1345 if( solval != NULL )
1346 {
1347 assert(addval > 0.0);
1348 *solval += addval;
1349 }
1350
1351 goto TERMINATE;
1352 }
1353
1354 SCIPdebugMsg(scip, "Determine greedy solution.\n");
1355
1356 /* sort myitems (plus corresponding arrays myweights and myprofits) such that
1357 * p_1/w_1 >= p_2/w_2 >= ... >= p_n/w_n, this is only used for the greedy solution
1358 */
1361
1362 for( j = 0; j < nmyitems; ++j )
1363 {
1366 }
1367
1369 (SCIP_Real)capacity, nmyitems, &greedymedianpos);
1370
1373
1374 /* initialize values for greedy solution information */
1375 greedysolweight = 0;
1376 greedysolvalue = 0.0;
1377
1378 /* determine greedy solution */
1379 for( j = 0; j < greedymedianpos; ++j )
1380 {
1381 assert(myweights[j] <= capacity);
1382
1383 /* update greedy solution weight and value */
1386 }
1387
1388 assert(0 < greedysolweight && greedysolweight <= capacity);
1389 assert(greedysolvalue > 0.0);
1390
1391 /* If the greedy solution is optimal by comparing to the LP solution, we take this solution. This happens if:
1392 * - the greedy solution reaches the capacity, because then the LP solution is integral;
1393 * - the greedy solution has an objective that is at least the LP value rounded down in case that all profits are integer, too. */
1395 if( intprofits )
1398 {
1399 SCIPdebugMsg(scip, "Greedy solution is optimal.\n");
1400
1401 /* update solution information */
1402 if( solitems != NULL )
1403 {
1404 int l;
1405
1407
1408 /* collect items */
1409 for( l = 0; l < j; ++l )
1410 solitems[(*nsolitems)++] = myitems[l];
1411 for ( ; l < nmyitems; ++l )
1413 }
1414 /* update solution value */
1415 if( solval != NULL )
1416 {
1417 assert(greedysolvalue > 0.0);
1418 *solval += greedysolvalue;
1419 }
1420
1421 goto TERMINATE;
1422 }
1423
1424 /* in the following table we do not need the first minweight columns */
1425 capacity -= (minweight - 1);
1426
1427 /* we can only handle integers */
1428 if( capacity >= INT_MAX )
1429 {
1430 SCIPdebugMsg(scip, "Capacity is to big, so we cannot handle it here.\n");
1431
1432 *success = FALSE;
1433 goto TERMINATE;
1434 }
1435 assert(capacity < INT_MAX);
1436
1437 intcap = (int)capacity;
1438 assert(intcap >= 0);
1439 assert(nmyitems > 0);
1440 assert(sizeof(size_t) >= sizeof(int)); /*lint !e506*/ /* no following conversion should be messed up */
1441
1442 /* this condition checks whether we will try to allocate a correct number of bytes and do not have an overflow, while
1443 * computing the size for the allocation
1444 */
1445 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*/
1446 {
1447 SCIPdebugMsg(scip, "Too much memory (%lu) would be consumed.\n", (unsigned long) (((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues))); /*lint !e571*/
1448
1449 *success = FALSE;
1450 goto TERMINATE;
1451 }
1452
1453 /* allocate temporary memory and check for memory exceedance */
1455 if( retcode == SCIP_NOMEMORY )
1456 {
1457 SCIPdebugMsg(scip, "Did not get enough memory.\n");
1458
1459 *success = FALSE;
1460 goto TERMINATE;
1461 }
1462 else
1463 {
1464 SCIP_CALL( retcode );
1465 }
1466
1467 SCIPdebugMsg(scip, "Start real exact algorithm.\n");
1468
1469 /* we memorize at each step the current minimal weight to later on know which value in our optvalues matrix is valid;
1470 * each value entries of the j-th row of optvalues is valid if the index is >= allcurrminweight[j], otherwise it is
1471 * invalid; a second possibility would be to clear the whole optvalues, which should be more expensive than storing
1472 * 'nmyitem' values
1473 */
1475 assert(myweights[0] - minweight < INT_MAX);
1476 currminweight = (int) (myweights[0] - minweight);
1478
1479 /* fills first row of dynamic programming table with optimal values */
1480 for( d = currminweight; d < intcap; ++d )
1481 optvalues[d] = myprofits[0];
1482
1483 /* fills dynamic programming table with optimal values */
1484 for( j = 1; j < nmyitems; ++j )
1485 {
1486 int intweight;
1487
1488 /* compute important part of weight, which will be represented in the table */
1489 intweight = (int)(myweights[j] - minweight);
1490 assert(0 <= intweight && intweight < intcap);
1491
1492 /* copy all nonzeros from row above */
1493 for( d = currminweight; d < intweight && d < intcap; ++d )
1494 optvalues[IDX(j,d)] = optvalues[IDX(j-1,d)];
1495
1496 /* update corresponding row */
1497 for( d = intweight; d < intcap; ++d )
1498 {
1499 /* if index d < current minweight then optvalues[IDX(j-1,d)] is not initialized, i.e. should be 0 */
1500 if( d < currminweight )
1501 optvalues[IDX(j,d)] = myprofits[j];
1502 else
1503 {
1504 SCIP_Real sumprofit;
1505
1506 if( d - myweights[j] < currminweight )
1508 else
1509 sumprofit = optvalues[IDX(j-1,(int)(d-myweights[j]))] + myprofits[j];
1510
1512 }
1513 }
1514
1515 /* update currminweight */
1516 if( intweight < currminweight )
1518
1520 }
1521
1522 /* update optimal solution by following the table */
1523 if( solitems != NULL )
1524 {
1526 d = intcap - 1;
1527
1528 SCIPdebugMsg(scip, "Fill the solution vector after solving exactly.\n");
1529
1530 /* insert all items in (non-) solution vector */
1531 for( j = nmyitems - 1; j > 0; --j )
1532 {
1533 /* if the following condition holds this means all remaining items does not fit anymore */
1534 if( d < allcurrminweight[j] )
1535 {
1536 /* we cannot have exceeded our capacity */
1537 assert((SCIP_Longint) d >= -minweight);
1538 break;
1539 }
1540
1541 /* collect solution items; the first condition means that no further item can fit anymore, but this does */
1542 if( d < allcurrminweight[j-1] || optvalues[IDX(j,d)] > optvalues[IDX(j-1,d)] )
1543 {
1544 solitems[(*nsolitems)++] = myitems[j];
1545
1546 /* check that we do not have an underflow */
1547 assert(myweights[j] <= (INT_MAX + (SCIP_Longint) d));
1548 d = (int)(d - myweights[j]);
1549 }
1550 /* collect non-solution items */
1551 else
1552 nonsolitems[(*nnonsolitems)++] = myitems[j];
1553 }
1554
1555 /* insert remaining items */
1556 if( d >= allcurrminweight[j] )
1557 {
1558 assert(j == 0);
1559 solitems[(*nsolitems)++] = myitems[j];
1560 }
1561 else
1562 {
1563 assert(j >= 0);
1565
1566 for( ; j >= 0; --j )
1568 }
1569
1570 assert(*nsolitems + *nnonsolitems == nitems);
1571 }
1572
1573 /* update solution value */
1574 if( solval != NULL )
1575 *solval += optvalues[IDX(nmyitems-1,intcap-1)];
1577
1578 /* free all temporary memory */
1580
1581 TERMINATE:
1585
1586 return SCIP_OKAY;
1587}
1588
1589/** solves knapsack problem in maximization form approximately by solving the LP-relaxation of the problem using Dantzig's
1590 * method and rounding down the solution; if needed, one can provide arrays to store all selected items and all not
1591 * selected items
1592 */
1594 SCIP* scip, /**< SCIP data structure */
1595 int nitems, /**< number of available items */
1596 SCIP_Longint* weights, /**< item weights */
1597 SCIP_Real* profits, /**< item profits */
1598 SCIP_Longint capacity, /**< capacity of knapsack */
1599 int* items, /**< item numbers */
1600 int* solitems, /**< array to store items in solution, or NULL */
1601 int* nonsolitems, /**< array to store items not in solution, or NULL */
1602 int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1603 int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1604 SCIP_Real* solval /**< pointer to store optimal solution value, or NULL */
1605 )
1606{
1607 SCIP_Real* tempsort;
1608 SCIP_Longint solitemsweight;
1609 SCIP_Real* realweights;
1610 int j;
1611 int criticalindex;
1612
1613 assert(weights != NULL);
1614 assert(profits != NULL);
1615 assert(capacity >= 0);
1616 assert(items != NULL);
1617 assert(nitems >= 0);
1618
1619 if( solitems != NULL )
1620 {
1621 *nsolitems = 0;
1622 *nnonsolitems = 0;
1623 }
1624 if( solval != NULL )
1625 *solval = 0.0;
1626
1627 /* initialize data for median search */
1630 for( j = nitems - 1; j >= 0; --j )
1631 {
1632 tempsort[j] = profits[j]/((SCIP_Real) weights[j]);
1633 realweights[j] = (SCIP_Real)weights[j];
1634 }
1635
1636 /* partially sort indices such that all elements that are larger than the break item appear first */
1637 SCIPselectWeightedDownRealLongRealInt(tempsort, weights, profits, items, realweights, (SCIP_Real)capacity, nitems, &criticalindex);
1638
1639 /* selects items as long as they fit into the knapsack */
1640 solitemsweight = 0;
1641 for( j = 0; j < nitems && solitemsweight + weights[j] <= capacity; ++j )
1642 {
1643 if( solitems != NULL )
1644 solitems[(*nsolitems)++] = items[j];
1645
1646 if( solval != NULL )
1647 (*solval) += profits[j];
1648 solitemsweight += weights[j];
1649 }
1650 if ( solitems != NULL )
1651 {
1652 for( ; j < nitems; j++ )
1654 }
1655
1658
1659 return SCIP_OKAY;
1660}
1661
1662#ifdef SCIP_DEBUG
1663/** prints all nontrivial GUB constraints and their LP solution values */
1664static
1665void GUBsetPrint(
1666 SCIP* scip, /**< SCIP data structure */
1667 SCIP_GUBSET* gubset, /**< GUB set data structure */
1668 SCIP_VAR** vars, /**< variables in knapsack constraint */
1669 SCIP_Real* solvals /**< solution values of variables in knapsack constraint; or NULL */
1670 )
1671{
1673 int c;
1674
1676
1677 SCIPdebugMsg(scip, " Nontrivial GUBs of current GUB set:\n");
1678
1679 /* print out all nontrivial GUB constraints, i.e., with more than one variable */
1680 for( c = 0; c < gubset->ngubconss; c++ )
1681 {
1682 SCIP_Real gubsolval;
1683
1684 assert(gubset->gubconss[c]->ngubvars >= 0);
1685
1686 /* nontrivial GUB */
1687 if( gubset->gubconss[c]->ngubvars > 1 )
1688 {
1689 int v;
1690
1691 gubsolval = 0.0;
1692 SCIPdebugMsg(scip, " GUB<%d>:\n", c);
1693
1694 /* print GUB var */
1695 for( v = 0; v < gubset->gubconss[c]->ngubvars; v++ )
1696 {
1697 int currentvar;
1698
1699 currentvar = gubset->gubconss[c]->gubvars[v];
1700 if( solvals != NULL )
1701 {
1702 gubsolval += solvals[currentvar];
1703 SCIPdebugMsg(scip, " +<%s>(%4.2f)\n", SCIPvarGetName(vars[currentvar]), solvals[currentvar]);
1704 }
1705 else
1706 {
1708 }
1709 }
1710
1711 /* check whether LP solution satisfies the GUB constraint */
1712 if( solvals != NULL )
1713 {
1714 SCIPdebugMsg(scip, " =%4.2f <= 1 %s\n", gubsolval,
1715 SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1716 }
1717 else
1718 {
1719 SCIPdebugMsg(scip, " <= 1 %s\n", SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1720 }
1722 }
1723 }
1724
1725 SCIPdebugMsg(scip, " --> %d/%d nontrivial GUBs\n", nnontrivialgubconss, gubset->ngubconss);
1726}
1727#endif
1728
1729/** creates an empty GUB constraint */
1730static
1732 SCIP* scip, /**< SCIP data structure */
1733 SCIP_GUBCONS** gubcons /**< pointer to store GUB constraint data */
1734 )
1735{
1736 assert(scip != NULL);
1737 assert(gubcons != NULL);
1738
1739 /* allocate memory for GUB constraint data structures */
1741 (*gubcons)->gubvarssize = GUBCONSGROWVALUE;
1742 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvars, (*gubcons)->gubvarssize) );
1743 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvarsstatus, (*gubcons)->gubvarssize) );
1744
1745 (*gubcons)->ngubvars = 0;
1746
1747 return SCIP_OKAY;
1748}
1749
1750/** frees GUB constraint */
1751static
1753 SCIP* scip, /**< SCIP data structure */
1754 SCIP_GUBCONS** gubcons /**< pointer to GUB constraint data structure */
1755 )
1756{
1757 assert(scip != NULL);
1758 assert(gubcons != NULL);
1759 assert((*gubcons)->gubvars != NULL);
1760 assert((*gubcons)->gubvarsstatus != NULL);
1761
1762 /* free allocated memory */
1763 SCIPfreeBufferArray(scip, &(*gubcons)->gubvarsstatus);
1764 SCIPfreeBufferArray(scip, &(*gubcons)->gubvars);
1766}
1767
1768/** adds variable to given GUB constraint */
1769static
1771 SCIP* scip, /**< SCIP data structure */
1772 SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1773 int var /**< index of given variable in knapsack constraint */
1774 )
1775{
1776 assert(scip != NULL);
1777 assert(gubcons != NULL);
1778 assert(gubcons->ngubvars >= 0 && gubcons->ngubvars < gubcons->gubvarssize);
1779 assert(gubcons->gubvars != NULL);
1780 assert(gubcons->gubvarsstatus != NULL);
1781 assert(var >= 0);
1782
1783 /* add variable to GUB constraint */
1784 gubcons->gubvars[gubcons->ngubvars] = var;
1785 gubcons->gubvarsstatus[gubcons->ngubvars] = GUBVARSTATUS_UNINITIAL;
1786 gubcons->ngubvars++;
1787
1788 /* increase space allocated to GUB constraint if the number of variables reaches the size */
1789 if( gubcons->ngubvars == gubcons->gubvarssize )
1790 {
1791 int newlen;
1792
1793 newlen = gubcons->gubvarssize + GUBCONSGROWVALUE;
1795 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1796
1797 gubcons->gubvarssize = newlen;
1798 }
1799
1800 return SCIP_OKAY;
1801}
1802
1803/** deletes variable from its current GUB constraint */
1804static
1806 SCIP* scip, /**< SCIP data structure */
1807 SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1808 int var, /**< index of given variable in knapsack constraint */
1809 int gubvarsidx /**< index of the variable in its current GUB constraint */
1810 )
1811{
1812 assert(scip != NULL);
1813 assert(gubcons != NULL);
1814 assert(var >= 0);
1815 assert(gubvarsidx >= 0 && gubvarsidx < gubcons->ngubvars);
1816 assert(gubcons->ngubvars >= gubvarsidx+1);
1817 assert(gubcons->gubvars[gubvarsidx] == var);
1818
1819 /* delete variable from GUB by swapping it replacing in by the last variable in the GUB constraint */
1820 gubcons->gubvars[gubvarsidx] = gubcons->gubvars[gubcons->ngubvars-1];
1821 gubcons->gubvarsstatus[gubvarsidx] = gubcons->gubvarsstatus[gubcons->ngubvars-1];
1822 gubcons->ngubvars--;
1823
1824 /* decrease space allocated for the GUB constraint, if the last GUBCONSGROWVALUE+1 array entries are now empty */
1825 if( gubcons->ngubvars < gubcons->gubvarssize - GUBCONSGROWVALUE && gubcons->ngubvars > 0 )
1826 {
1827 int newlen;
1828
1829 newlen = gubcons->gubvarssize - GUBCONSGROWVALUE;
1830
1832 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1833
1834 gubcons->gubvarssize = newlen;
1835 }
1836
1837 return SCIP_OKAY;
1838}
1839
1840/** moves variable from current GUB constraint to a different existing (nonempty) GUB constraint */
1841static
1843 SCIP* scip, /**< SCIP data structure */
1844 SCIP_GUBSET* gubset, /**< GUB set data structure */
1845 SCIP_VAR** vars, /**< variables in knapsack constraint */
1846 int var, /**< index of given variable in knapsack constraint */
1847 int oldgubcons, /**< index of old GUB constraint of given variable */
1848 int newgubcons /**< index of new GUB constraint of given variable */
1849 )
1850{
1851 int oldgubvaridx;
1852 int replacevar;
1853 int j;
1854
1855 assert(scip != NULL);
1856 assert(gubset != NULL);
1857 assert(var >= 0);
1861 assert(gubset->gubconssidx[var] == oldgubcons);
1862 assert(gubset->gubconss[oldgubcons]->ngubvars > 0);
1863 assert(gubset->gubconss[newgubcons]->ngubvars >= 0);
1864
1865 SCIPdebugMsg(scip, " moving variable<%s> from GUB<%d> to GUB<%d>\n", SCIPvarGetName(vars[var]), oldgubcons, newgubcons);
1866
1867 oldgubvaridx = gubset->gubvarsidx[var];
1868
1869 /* delete variable from old GUB constraint by replacing it by the last variable of the GUB constraint */
1871
1872 /* in GUB set, update stored index of variable in old GUB constraint for the variable used for replacement;
1873 * replacement variable is given by old position of the deleted variable
1874 */
1875 replacevar = gubset->gubconss[oldgubcons]->gubvars[oldgubvaridx];
1876 assert(gubset->gubvarsidx[replacevar] == gubset->gubconss[oldgubcons]->ngubvars);
1877 gubset->gubvarsidx[replacevar] = oldgubvaridx;
1878
1879 /* add variable to the end of new GUB constraint */
1881 assert(gubset->gubconss[newgubcons]->gubvars[gubset->gubconss[newgubcons]->ngubvars-1] == var);
1882
1883 /* in GUB set, update stored index of GUB of moved variable and stored index of variable in this GUB constraint */
1884 gubset->gubconssidx[var] = newgubcons;
1885 gubset->gubvarsidx[var] = gubset->gubconss[newgubcons]->ngubvars-1;
1886
1887 /* delete old GUB constraint if it became empty */
1888 if( gubset->gubconss[oldgubcons]->ngubvars == 0 )
1889 {
1890 SCIPdebugMsg(scip, "deleting empty GUB cons<%d> from current GUB set\n", oldgubcons);
1891#ifdef SCIP_DEBUG
1893#endif
1894
1895 /* free old GUB constraint */
1896 GUBconsFree(scip, &gubset->gubconss[oldgubcons]);
1897
1898 /* if empty GUB was not the last one in GUB set data structure, replace it by last GUB constraint */
1899 if( oldgubcons != gubset->ngubconss-1 )
1900 {
1901 gubset->gubconss[oldgubcons] = gubset->gubconss[gubset->ngubconss-1];
1902 gubset->gubconsstatus[oldgubcons] = gubset->gubconsstatus[gubset->ngubconss-1];
1903
1904 /* in GUB set, update stored index of GUB constraint for all variable of the GUB constraint used for replacement;
1905 * replacement GUB is given by old position of the deleted GUB
1906 */
1907 for( j = 0; j < gubset->gubconss[oldgubcons]->ngubvars; j++ )
1908 {
1909 assert(gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] == gubset->ngubconss-1);
1910 gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] = oldgubcons;
1911 }
1912 }
1913
1914 /* update number of GUB constraints */
1915 gubset->ngubconss--;
1916
1917 /* variable should be at given new position, unless new GUB constraint replaced empty old GUB constraint
1918 * (because it was at the end of the GUB constraint array)
1919 */
1920 assert(gubset->gubconssidx[var] == newgubcons
1921 || (newgubcons == gubset->ngubconss && gubset->gubconssidx[var] == oldgubcons));
1922 }
1923#ifndef NDEBUG
1924 else
1925 assert(gubset->gubconssidx[var] == newgubcons);
1926#endif
1927
1928 return SCIP_OKAY;
1929}
1930
1931/** swaps two variables in the same GUB constraint */
1932static
1934 SCIP* scip, /**< SCIP data structure */
1935 SCIP_GUBSET* gubset, /**< GUB set data structure */
1936 int var1, /**< first variable to be swapped */
1937 int var2 /**< second variable to be swapped */
1938 )
1939{
1940 int gubcons;
1941 int var1idx;
1943 int var2idx;
1945
1946 assert(scip != NULL);
1947 assert(gubset != NULL);
1948
1949 gubcons = gubset->gubconssidx[var1];
1950 assert(gubcons == gubset->gubconssidx[var2]);
1951
1952 /* nothing to be done if both variables are the same */
1953 if( var1 == var2 )
1954 return;
1955
1956 /* swap index and status of variables in GUB constraint */
1957 var1idx = gubset->gubvarsidx[var1];
1958 var1status = gubset->gubconss[gubcons]->gubvarsstatus[var1idx];
1959 var2idx = gubset->gubvarsidx[var2];
1960 var2status = gubset->gubconss[gubcons]->gubvarsstatus[var2idx];
1961
1962 gubset->gubvarsidx[var1] = var2idx;
1963 gubset->gubconss[gubcons]->gubvars[var1idx] = var2;
1964 gubset->gubconss[gubcons]->gubvarsstatus[var1idx] = var2status;
1965
1966 gubset->gubvarsidx[var2] = var1idx;
1967 gubset->gubconss[gubcons]->gubvars[var2idx] = var1;
1968 gubset->gubconss[gubcons]->gubvarsstatus[var2idx] = var1status;
1969}
1970
1971/** initializes partition of knapsack variables into nonoverlapping trivial GUB constraints (GUB with one variable) */
1972static
1974 SCIP* scip, /**< SCIP data structure */
1975 SCIP_GUBSET** gubset, /**< pointer to store GUB set data structure */
1976 int nvars, /**< number of variables in the knapsack constraint */
1977 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
1978 SCIP_Longint capacity /**< capacity of knapsack */
1979 )
1980{
1981 int i;
1982
1983 assert(scip != NULL);
1984 assert(gubset != NULL);
1985 assert(nvars > 0);
1986 assert(weights != NULL);
1987 assert(capacity >= 0);
1988
1989 /* allocate memory for GUB set data structures */
1991 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconss, nvars) );
1992 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconsstatus, nvars) );
1993 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconssidx, nvars) );
1994 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubvarsidx, nvars) );
1995 (*gubset)->ngubconss = nvars;
1996 (*gubset)->nvars = nvars;
1997
1998 /* initialize the set of GUB constraints */
1999 for( i = 0; i < nvars; i++ )
2000 {
2001 /* assign each variable to a new (trivial) GUB constraint */
2002 SCIP_CALL( GUBconsCreate(scip, &(*gubset)->gubconss[i]) );
2003 SCIP_CALL( GUBconsAddVar(scip, (*gubset)->gubconss[i], i) );
2004
2005 /* set status of GUB constraint to initial */
2006 (*gubset)->gubconsstatus[i] = GUBCONSSTATUS_UNINITIAL;
2007
2008 (*gubset)->gubconssidx[i] = i;
2009 (*gubset)->gubvarsidx[i] = 0;
2010 assert((*gubset)->gubconss[i]->ngubvars == 1);
2011
2012 /* already updated status of variable in GUB constraint if it exceeds the capacity of the knapsack */
2013 if( weights[i] > capacity )
2014 (*gubset)->gubconss[(*gubset)->gubconssidx[i]]->gubvarsstatus[(*gubset)->gubvarsidx[i]] = GUBVARSTATUS_CAPACITYEXCEEDED;
2015 }
2016
2017 return SCIP_OKAY;
2018}
2019
2020/** frees GUB set data structure */
2021static
2023 SCIP* scip, /**< SCIP data structure */
2024 SCIP_GUBSET** gubset /**< pointer to GUB set data structure */
2025 )
2026{
2027 int i;
2028
2029 assert(scip != NULL);
2030 assert(gubset != NULL);
2031 assert((*gubset)->gubconss != NULL);
2032 assert((*gubset)->gubconsstatus != NULL);
2033 assert((*gubset)->gubconssidx != NULL);
2034 assert((*gubset)->gubvarsidx != NULL);
2035
2036 /* free all GUB constraints */
2037 for( i = (*gubset)->ngubconss-1; i >= 0; --i )
2038 {
2039 assert((*gubset)->gubconss[i] != NULL);
2040 GUBconsFree(scip, &(*gubset)->gubconss[i]);
2041 }
2042
2043 /* free allocated memory */
2044 SCIPfreeBufferArray( scip, &(*gubset)->gubvarsidx );
2045 SCIPfreeBufferArray( scip, &(*gubset)->gubconssidx );
2046 SCIPfreeBufferArray( scip, &(*gubset)->gubconsstatus );
2047 SCIPfreeBufferArray( scip, &(*gubset)->gubconss );
2049}
2050
2051#ifndef NDEBUG
2052/** checks whether GUB set data structure is consistent */
2053static
2055 SCIP* scip, /**< SCIP data structure */
2056 SCIP_GUBSET* gubset, /**< GUB set data structure */
2057 SCIP_VAR** vars /**< variables in the knapsack constraint */
2058 )
2059{
2060 int i;
2061 int gubconsidx;
2062 int gubvaridx;
2063 SCIP_VAR* var1;
2064 SCIP_VAR* var2;
2065 SCIP_Bool var1negated;
2066 SCIP_Bool var2negated;
2067
2068 assert(scip != NULL);
2069 assert(gubset != NULL);
2070
2071 SCIPdebugMsg(scip, " GUB set consistency check:\n");
2072
2073 /* checks for all knapsack vars consistency of stored index of associated gubcons and corresponding index in gubvars */
2074 for( i = 0; i < gubset->nvars; i++ )
2075 {
2076 gubconsidx = gubset->gubconssidx[i];
2077 gubvaridx = gubset->gubvarsidx[i];
2078
2079 if( gubset->gubconss[gubconsidx]->gubvars[gubvaridx] != i )
2080 {
2081 SCIPdebugMsg(scip, " var<%d> should be in GUB<%d> at position<%d>, but stored is var<%d> instead\n", i,
2082 gubconsidx, gubvaridx, gubset->gubconss[gubconsidx]->gubvars[gubvaridx] );
2083 }
2084 assert(gubset->gubconss[gubconsidx]->gubvars[gubvaridx] == i);
2085 }
2086
2087 /* checks for each GUB whether all pairs of its variables have a common clique */
2088 for( i = 0; i < gubset->ngubconss; i++ )
2089 {
2090 int j;
2091
2092 for( j = 0; j < gubset->gubconss[i]->ngubvars; j++ )
2093 {
2094 int k;
2095
2096 /* get corresponding active problem variable */
2097 var1 = vars[gubset->gubconss[i]->gubvars[j]];
2100
2101 for( k = j+1; k < gubset->gubconss[i]->ngubvars; k++ )
2102 {
2103 /* get corresponding active problem variable */
2104 var2 = vars[gubset->gubconss[i]->gubvars[k]];
2107
2109 {
2110 SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2111 SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[j]]), k,
2112 SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[k]]));
2113 SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2116 }
2117
2118 /* @todo: in case we used also negated cliques for the GUB partition, this assert has to be changed */
2120 }
2121 }
2122 }
2123 SCIPdebugMsg(scip, " --> successful\n");
2124
2125 return SCIP_OKAY;
2126}
2127#endif
2128
2129/** calculates a partition of the given set of binary variables into cliques;
2130 * afterwards the output array contains one value for each variable, such that two variables got the same value iff they
2131 * were assigned to the same clique;
2132 * the first variable is always assigned to clique 0, and a variable can only be assigned to clique i if at least one of
2133 * the preceding variables was assigned to clique i-1;
2134 * note: in contrast to SCIPcalcCliquePartition(), variables with LP value 1 are put into trivial cliques (with one
2135 * variable) and for the remaining variables, a partition with a small number of cliques is constructed
2136 */
2137
2138static
2140 SCIP*const scip, /**< SCIP data structure */
2141 SCIP_VAR**const vars, /**< binary variables in the clique from which at most one can be set to 1 */
2142 int const nvars, /**< number of variables in the clique */
2143 int*const cliquepartition, /**< array of length nvars to store the clique partition */
2144 int*const ncliques, /**< pointer to store number of cliques actually contained in the partition */
2145 SCIP_Real* solvals /**< solution values of all given binary variables */
2146 )
2147{
2148 SCIP_VAR** tmpvars;
2150 SCIP_Bool* cliquevalues;
2151 SCIP_Bool* tmpvalues;
2152 int* varseq;
2153 int* sortkeys;
2154 int ncliquevars;
2156 int nignorevars;
2157 int nvarsused;
2158 int i;
2159
2160 assert(scip != NULL);
2161 assert(nvars == 0 || vars != NULL);
2162 assert(nvars == 0 || cliquepartition != NULL);
2163 assert(ncliques != NULL);
2164
2165 if( nvars == 0 )
2166 {
2167 *ncliques = 0;
2168 return SCIP_OKAY;
2169 }
2170
2171 /* allocate temporary memory for storing the variables of the current clique */
2178
2179 /* initialize the cliquepartition array with -1 */
2180 /* initialize the tmpvalues array */
2181 for( i = nvars - 1; i >= 0; --i )
2182 {
2183 tmpvalues[i] = TRUE;
2184 cliquepartition[i] = -1;
2185 }
2186
2187 /* get corresponding active problem variables */
2189
2190 /* ignore variables with LP value 1 (will be assigned to trivial GUBs at the end) and sort remaining variables
2191 * by nondecreasing number of cliques the variables are in
2192 */
2193 nignorevars = 0;
2194 nvarsused = 0;
2195 for( i = 0; i < nvars; i++ )
2196 {
2197 if( SCIPisFeasEQ(scip, solvals[i], 1.0) )
2198 {
2199 /* variables with LP value 1 are put to the end of varseq array and will not be sorted */
2201 nignorevars++;
2202 }
2203 else
2204 {
2205 /* remaining variables are put to the front of varseq array and will be sorted by their number of cliques */
2206 varseq[nvarsused] = i;
2208 nvarsused++;
2209 }
2210 }
2212
2213 /* sort variables with LP value less than 1 by nondecreasing order of the number of cliques they are in */
2215
2217
2218 /* calculate the clique partition */
2219 *ncliques = 0;
2220 for( i = 0; i < nvars; ++i )
2221 {
2222 if( cliquepartition[varseq[i]] == -1 )
2223 {
2224 int j;
2225
2226 /* variable starts a new clique */
2227 cliquepartition[varseq[i]] = *ncliques;
2228 cliquevars[0] = tmpvars[varseq[i]];
2230 ncliquevars = 1;
2231
2232 /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique and
2233 * if the variable has LP value 1 we do not want it to be in nontrivial cliques
2234 */
2235 if( SCIPvarIsActive(tmpvars[varseq[i]]) && i < nvarsused )
2236 {
2237 /* greedily fill up the clique */
2238 for( j = i + 1; j < nvarsused; ++j )
2239 {
2240 /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique */
2241 if( cliquepartition[varseq[j]] == -1 && SCIPvarIsActive(tmpvars[varseq[j]]) )
2242 {
2243 int k;
2244
2245 /* check if every variable in the actual clique is in clique with the new variable */
2246 for( k = ncliquevars - 1; k >= 0; --k )
2247 {
2249 cliquevalues[k], TRUE) )
2250 break;
2251 }
2252
2253 if( k == -1 )
2254 {
2255 /* put the variable into the same clique */
2256 cliquepartition[varseq[j]] = cliquepartition[varseq[i]];
2257 cliquevars[ncliquevars] = tmpvars[varseq[j]];
2259 ++ncliquevars;
2260 }
2261 }
2262 }
2263 }
2264
2265 /* this clique is finished */
2266 ++(*ncliques);
2267 }
2268 assert(cliquepartition[varseq[i]] >= 0 && cliquepartition[varseq[i]] < i + 1);
2269
2270 /* break if we reached the maximal number of comparisons */
2271 if( i * nvars > maxncliquevarscomp )
2272 break;
2273 }
2274 /* if we had too many variables fill up the cliquepartition and put each variable in a separate clique */
2275 for( ; i < nvars; ++i )
2276 {
2277 if( cliquepartition[varseq[i]] == -1 )
2278 {
2279 cliquepartition[varseq[i]] = *ncliques;
2280 ++(*ncliques);
2281 }
2282 }
2283
2284 /* free temporary memory */
2287 SCIPfreeBufferArray(scip, &tmpvars);
2291
2292 return SCIP_OKAY;
2293}
2294
2295/** constructs sophisticated partition of knapsack variables into non-overlapping GUBs; current partition uses trivial GUBs */
2296static
2298 SCIP* scip, /**< SCIP data structure */
2299 SCIP_GUBSET* gubset, /**< GUB set data structure */
2300 SCIP_VAR** vars, /**< variables in the knapsack constraint */
2301 SCIP_Real* solvals /**< solution values of all knapsack variables */
2302 )
2303{
2304 int* cliquepartition;
2305 int* gubfirstvar;
2306 int ncliques;
2308 int newgubconsidx;
2309 int cliqueidx;
2310 int nvars;
2311 int i;
2312
2313 assert(scip != NULL);
2314 assert(gubset != NULL);
2315 assert(vars != NULL);
2316
2317 nvars = gubset->nvars;
2318 assert(nvars >= 0);
2319
2320 /* allocate temporary memory for clique partition */
2321 SCIP_CALL( SCIPallocBufferArray(scip, &cliquepartition, nvars) );
2322
2323 /* compute sophisticated clique partition */
2324 SCIP_CALL( GUBsetCalcCliquePartition(scip, vars, nvars, cliquepartition, &ncliques, solvals) );
2325
2326 /* allocate temporary memory for GUB set data structure */
2328
2329 /* translate GUB partition into GUB set data structure */
2330 for( i = 0; i < ncliques; i++ )
2331 {
2332 /* initialize first variable for every GUB */
2333 gubfirstvar[i] = -1;
2334 }
2335 /* move every knapsack variable into GUB defined by clique partition */
2336 for( i = 0; i < nvars; i++ )
2337 {
2338 assert(cliquepartition[i] >= 0);
2339
2340 cliqueidx = cliquepartition[i];
2341 currentgubconsidx = gubset->gubconssidx[i];
2342 assert(gubset->gubconss[currentgubconsidx]->ngubvars == 1 );
2343
2344 /* variable is first element in GUB constraint defined by clique partition */
2345 if( gubfirstvar[cliqueidx] == -1 )
2346 {
2347 /* corresponding GUB constraint in GUB set data structure was already constructed (as initial trivial GUB);
2348 * note: no assert for gubconssidx, because it can changed due to deleting empty GUBs in GUBsetMoveVar()
2349 */
2350 assert(gubset->gubvarsidx[i] == 0);
2351 assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2352
2353 /* remember the first variable found for the current GUB */
2355 }
2356 /* variable is additional element of GUB constraint defined by clique partition */
2357 else
2358 {
2360
2361 /* move variable to GUB constraint defined by clique partition; index of this GUB constraint is given by the
2362 * first variable of this GUB constraint
2363 */
2364 newgubconsidx = gubset->gubconssidx[gubfirstvar[cliqueidx]];
2365 assert(newgubconsidx != currentgubconsidx); /* because initially every variable is in a different GUB */
2367
2368 assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2369 }
2370 }
2371
2372#ifdef SCIP_DEBUG
2373 /* prints GUB set data structure */
2374 GUBsetPrint(scip, gubset, vars, solvals);
2375#endif
2376
2377#ifndef NDEBUG
2378 /* checks consistency of GUB set data structure */
2380#endif
2381
2382 /* free temporary memory */
2384 SCIPfreeBufferArray(scip, &cliquepartition);
2385
2386 return SCIP_OKAY;
2387}
2388
2389/** 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$
2390 * 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
2391 * \f$j \in N \setminus C\f$, if \f$j \in N_0 = \{j \in N : x^*_j = 0\}\f$, if one exists.
2392 */
2393static
2395 SCIP* scip, /**< SCIP data structure */
2396 SCIP_VAR** vars, /**< variables in knapsack constraint */
2397 int nvars, /**< number of variables in knapsack constraint */
2398 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2399 SCIP_Longint capacity, /**< capacity of knapsack */
2400 SCIP_Real* solvals, /**< solution values of all problem variables */
2401 int* covervars, /**< pointer to store cover variables */
2402 int* noncovervars, /**< pointer to store noncover variables */
2403 int* ncovervars, /**< pointer to store number of cover variables */
2404 int* nnoncovervars, /**< pointer to store number of noncover variables */
2405 SCIP_Longint* coverweight, /**< pointer to store weight of cover */
2406 SCIP_Bool* found, /**< pointer to store whether a cover was found */
2407 SCIP_Bool modtransused, /**< should modified transformed separation problem be used to find cover */
2408 int* ntightened, /**< pointer to store number of variables with tightened upper bound */
2409 SCIP_Bool* fractional /**< pointer to store whether the LP sol for knapsack vars is fractional */
2410 )
2411{
2412 SCIP_Longint* transweights;
2413 SCIP_Real* transprofits;
2414 SCIP_Longint transcapacity;
2415 SCIP_Longint fixedonesweight;
2416 SCIP_Longint itemsweight;
2417 SCIP_Bool infeasible;
2418 int* fixedones;
2419 int* fixedzeros;
2420 int* items;
2421 int nfixedones;
2422 int nfixedzeros;
2423 int nitems;
2424 int j;
2425
2426 assert(scip != NULL);
2427 assert(vars != NULL);
2428 assert(nvars > 0);
2429 assert(weights != NULL);
2430 assert(capacity >= 0);
2431 assert(solvals != NULL);
2432 assert(covervars != NULL);
2437 assert(found != NULL);
2438 assert(ntightened != NULL);
2440
2441 SCIPdebugMsg(scip, " get cover for knapsack constraint\n");
2442
2443 /* allocates temporary memory */
2449
2450 *found = FALSE;
2451 *ncovervars = 0;
2452 *nnoncovervars = 0;
2453 *coverweight = 0;
2454 *fractional = TRUE;
2455
2456 /* gets the following sets
2457 * N_1 = {j in N : x*_j = 1} (fixedones),
2458 * N_0 = {j in N : x*_j = 0} (fixedzeros) and
2459 * N\‍(N_0 & N_1) (items),
2460 * where x*_j is the solution value of variable x_j
2461 */
2462 nfixedones = 0;
2463 nfixedzeros = 0;
2464 nitems = 0;
2465 fixedonesweight = 0;
2466 itemsweight = 0;
2467 *ntightened = 0;
2468 for( j = 0; j < nvars; j++ )
2469 {
2471
2472 /* tightens upper bound of x_j if weight of x_j is greater than capacity of knapsack */
2473 if( weights[j] > capacity )
2474 {
2475 SCIP_CALL( SCIPtightenVarUb(scip, vars[j], 0.0, FALSE, &infeasible, NULL) );
2476 assert(!infeasible);
2477 (*ntightened)++;
2478 continue;
2479 }
2480
2481 /* variable x_j has solution value one */
2482 if( SCIPisFeasEQ(scip, solvals[j], 1.0) )
2483 {
2484 fixedones[nfixedones] = j;
2485 nfixedones++;
2486 fixedonesweight += weights[j];
2487 }
2488 /* variable x_j has solution value zero */
2489 else if( SCIPisFeasEQ(scip, solvals[j], 0.0) )
2490 {
2491 fixedzeros[nfixedzeros] = j;
2492 nfixedzeros++;
2493 }
2494 /* variable x_j has fractional solution value */
2495 else
2496 {
2497 assert( SCIPisFeasGT(scip, solvals[j], 0.0) && SCIPisFeasLT(scip, solvals[j], 1.0) );
2498 items[nitems] = j;
2499 nitems++;
2500 itemsweight += weights[j];
2501 }
2502 }
2503 assert(nfixedones + nfixedzeros + nitems == nvars - (*ntightened));
2504
2505 /* sets whether the LP solution x* for the knapsack variables is fractional; if it is not fractional we stop
2506 * the separation routine
2507 */
2508 assert(nitems >= 0);
2509 if( nitems == 0 )
2510 {
2511 *fractional = FALSE;
2512 goto TERMINATE;
2513 }
2515
2516 /* transforms the traditional separation problem (under consideration of the following fixing:
2517 * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2518 *
2519 * min sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) z_j
2520 * sum_{j in N\‍(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2521 * z_j in {0,1}, j in N\‍(N_0 & N_1)
2522 *
2523 * to a knapsack problem in maximization form by complementing the variables
2524 *
2525 * sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) -
2526 * max sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) z_j
2527 * sum_{j in N\‍(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2528 * z_j in {0,1}, j in N\‍(N_0 & N_1)
2529 */
2530
2531 /* gets weight and profit of variables in transformed knapsack problem */
2532 for( j = 0; j < nitems; j++ )
2533 {
2534 transweights[j] = weights[items[j]];
2535 transprofits[j] = 1.0 - solvals[items[j]];
2536 }
2537 /* gets capacity of transformed knapsack problem */
2538 transcapacity = fixedonesweight + itemsweight - capacity - 1;
2539
2540 /* if capacity of transformed knapsack problem is less than zero, there is no cover
2541 * (when variables fixed to zero are not used)
2542 */
2543 if( transcapacity < 0 )
2544 {
2545 assert(!(*found));
2546 goto TERMINATE;
2547 }
2548
2549 if( modtransused )
2550 {
2551 /* transforms the modified separation problem (under consideration of the following fixing:
2552 * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2553 *
2554 * min sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) a_j z_j
2555 * sum_{j in N\‍(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2556 * z_j in {0,1}, j in N\‍(N_0 & N_1)
2557 *
2558 * to a knapsack problem in maximization form by complementing the variables
2559 *
2560 * sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) a_j -
2561 * max sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) a_j z_j
2562 * sum_{j in N\‍(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2563 * z_j in {0,1}, j in N\‍(N_0 & N_1)
2564 */
2565
2566 /* gets weight and profit of variables in modified transformed knapsack problem */
2567 for( j = 0; j < nitems; j++ )
2568 {
2569 transprofits[j] *= weights[items[j]];
2571 }
2572 }
2573
2574 /* solves (modified) transformed knapsack problem approximately by solving the LP-relaxation of the (modified)
2575 * transformed knapsack problem using Dantzig's method and rounding down the solution.
2576 * let z* be the solution, then
2577 * j in C, if z*_j = 0 and
2578 * i in N\C, if z*_j = 1.
2579 */
2582 /*assert(checkSolveKnapsack(scip, nitems, transweights, transprofits, items, weights, solvals, modtransused));*/
2583
2584 /* constructs cover C (sum_{j in C} a_j > a_0) */
2585 for( j = 0; j < *ncovervars; j++ )
2586 {
2587 (*coverweight) += weights[covervars[j]];
2588 }
2589
2590 /* adds all variables from N_1 to C */
2591 for( j = 0; j < nfixedones; j++ )
2592 {
2594 (*ncovervars)++;
2595 (*coverweight) += weights[fixedones[j]];
2596 }
2597
2598 /* adds all variables from N_0 to N\C */
2599 for( j = 0; j < nfixedzeros; j++ )
2600 {
2602 (*nnoncovervars)++;
2603 }
2604 assert((*ncovervars) + (*nnoncovervars) == nvars - (*ntightened));
2605 assert((*coverweight) > capacity);
2606 *found = TRUE;
2607
2608 TERMINATE:
2609 /* frees temporary memory */
2615
2616 SCIPdebugMsg(scip, " get cover for knapsack constraint -- end\n");
2617
2618 return SCIP_OKAY;
2619}
2620
2621#ifndef NDEBUG
2622/** checks if minweightidx is set correctly
2623 */
2624static
2626 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2627 SCIP_Longint capacity, /**< capacity of knapsack */
2628 int* covervars, /**< pointer to store cover variables */
2629 int ncovervars, /**< pointer to store number of cover variables */
2630 SCIP_Longint coverweight, /**< pointer to store weight of cover */
2631 int minweightidx, /**< index of variable in cover variables with minimum weight */
2632 int j /**< current index in cover variables */
2633 )
2634{
2635 SCIP_Longint minweight;
2636 int i;
2637
2638 assert(weights != NULL);
2639 assert(covervars != NULL);
2640 assert(ncovervars > 0);
2641
2642 minweight = weights[covervars[minweightidx]];
2643
2644 /* checks if all cover variables before index j have weight greater than minweight */
2645 for( i = 0; i < j; i++ )
2646 {
2647 assert(weights[covervars[i]] > minweight);
2648 if( weights[covervars[i]] <= minweight )
2649 return FALSE;
2650 }
2651
2652 /* checks if all variables before index j cannot be removed, i.e. i cannot be the next minweightidx */
2653 for( i = 0; i < j; i++ )
2654 {
2655 assert(coverweight - weights[covervars[i]] <= capacity);
2656 if( coverweight - weights[covervars[i]] > capacity )
2657 return FALSE;
2658 }
2659 return TRUE;
2660}
2661#endif
2662
2663
2664/** 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$,
2665 * 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$
2666 */
2667static
2669 SCIP* scip, /**< SCIP data structure */
2670 SCIP_Real* solvals, /**< solution values of all problem variables */
2671 int* covervars, /**< cover variables */
2672 int ncovervars, /**< number of cover variables */
2673 int* varsC1, /**< pointer to store variables in C1 */
2674 int* varsC2, /**< pointer to store variables in C2 */
2675 int* nvarsC1, /**< pointer to store number of variables in C1 */
2676 int* nvarsC2 /**< pointer to store number of variables in C2 */
2677 )
2678{
2679 int j;
2680
2681 assert(scip != NULL);
2682 assert(ncovervars >= 0);
2683 assert(solvals != NULL);
2684 assert(covervars != NULL);
2685 assert(varsC1 != NULL);
2686 assert(varsC2 != NULL);
2687 assert(nvarsC1 != NULL);
2688 assert(nvarsC2 != NULL);
2689
2690 *nvarsC1 = 0;
2691 *nvarsC2 = 0;
2692 for( j = 0; j < ncovervars; j++ )
2693 {
2694 assert(SCIPisFeasGT(scip, solvals[covervars[j]], 0.0));
2695
2696 /* variable has solution value one */
2697 if( SCIPisGE(scip, solvals[covervars[j]], 1.0) )
2698 {
2700 (*nvarsC2)++;
2701 }
2702 /* variable has solution value less than one */
2703 else
2704 {
2705 assert(SCIPisLT(scip, solvals[covervars[j]], 1.0));
2707 (*nvarsC1)++;
2708 }
2709 }
2710 assert((*nvarsC1) + (*nvarsC2) == ncovervars);
2711}
2712
2713/** changes given partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one and two (if possible) variables from
2714 * C2 to C1 if |C1| = 1 and |C1| = 0, respectively.
2715 */
2716static
2718 SCIP* scip, /**< SCIP data structure */
2719 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2720 int* varsC1, /**< pointer to store variables in C1 */
2721 int* varsC2, /**< pointer to store variables in C2 */
2722 int* nvarsC1, /**< pointer to store number of variables in C1 */
2723 int* nvarsC2 /**< pointer to store number of variables in C2 */
2724 )
2725{
2726 SCIP_Real* sortkeysC2;
2727 int j;
2728
2729 assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2730 assert(*nvarsC2 > 0);
2731
2732 /* allocates temporary memory */
2734
2735 /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2736 for( j = 0; j < *nvarsC2; j++ )
2737 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2739
2740 /* adds one or two variable from C2 with smallest weight to C1 and removes them from C2 */
2741 assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2742 while( *nvarsC1 < 2 && *nvarsC2 > 0 )
2743 {
2744 varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2745 (*nvarsC1)++;
2746 (*nvarsC2)--;
2747 }
2748
2749 /* frees temporary memory */
2751
2752 return SCIP_OKAY;
2753}
2754
2755/** changes given partition (C_1,C_2) of feasible set C, if |C1| = 1, by moving one variable from C2 to C1 */
2756static
2758 SCIP* scip, /**< SCIP data structure */
2759 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2760 int* varsC1, /**< pointer to store variables in C1 */
2761 int* varsC2, /**< pointer to store variables in C2 */
2762 int* nvarsC1, /**< pointer to store number of variables in C1 */
2763 int* nvarsC2 /**< pointer to store number of variables in C2 */
2764 )
2765{
2766 SCIP_Real* sortkeysC2;
2767 int j;
2768
2769 assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2770 assert(*nvarsC2 > 0);
2771
2772 /* allocates temporary memory */
2774
2775 /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2776 for( j = 0; j < *nvarsC2; j++ )
2777 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2779
2780 /* adds variable from C2 with smallest weight to C1 and removes it from C2 */
2781 assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2782 varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2783 (*nvarsC1)++;
2784 (*nvarsC2)--;
2785
2786 /* frees temporary memory */
2788
2789 return SCIP_OKAY;
2790}
2791
2792
2793/** 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$
2794 * and \f$F \cap R = \emptyset\f$; chooses partition as follows \f$R = \{ j \in N \setminus C : x^*_j = 0 \}\f$ and
2795 * \f$F = (N \setminus C) \setminus F\f$
2796 */
2797static
2799 SCIP* scip, /**< SCIP data structure */
2800 SCIP_Real* solvals, /**< solution values of all problem variables */
2801 int* noncovervars, /**< noncover variables */
2802 int nnoncovervars, /**< number of noncover variables */
2803 int* varsF, /**< pointer to store variables in F */
2804 int* varsR, /**< pointer to store variables in R */
2805 int* nvarsF, /**< pointer to store number of variables in F */
2806 int* nvarsR /**< pointer to store number of variables in R */
2807 )
2808{
2809 int j;
2810
2811 assert(scip != NULL);
2812 assert(nnoncovervars >= 0);
2813 assert(solvals != NULL);
2815 assert(varsF != NULL);
2816 assert(varsR != NULL);
2817 assert(nvarsF != NULL);
2818 assert(nvarsR != NULL);
2819
2820 *nvarsF = 0;
2821 *nvarsR = 0;
2822
2823 for( j = 0; j < nnoncovervars; j++ )
2824 {
2825 /* variable has solution value zero */
2826 if( SCIPisFeasEQ(scip, solvals[noncovervars[j]], 0.0) )
2827 {
2829 (*nvarsR)++;
2830 }
2831 /* variable has solution value greater than zero */
2832 else
2833 {
2834 assert(SCIPisFeasGT(scip, solvals[noncovervars[j]], 0.0));
2836 (*nvarsF)++;
2837 }
2838 }
2839 assert((*nvarsF) + (*nvarsR) == nnoncovervars);
2840}
2841
2842/** sorts variables in F, C_2, and R according to the second level lifting sequence that will be used in the sequential
2843 * lifting procedure
2844 */
2845static
2847 SCIP* scip, /**< SCIP data structure */
2848 SCIP_Real* solvals, /**< solution values of all problem variables */
2849 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2850 int* varsF, /**< pointer to store variables in F */
2851 int* varsC2, /**< pointer to store variables in C2 */
2852 int* varsR, /**< pointer to store variables in R */
2853 int nvarsF, /**< number of variables in F */
2854 int nvarsC2, /**< number of variables in C2 */
2855 int nvarsR /**< number of variables in R */
2856 )
2857{
2860 SCIP_Real* sortkeysC2;
2861 SCIP_Real* sortkeysR;
2862 int j;
2863
2864 assert(scip != NULL);
2865 assert(solvals != NULL);
2866 assert(weights != NULL);
2867 assert(varsF != NULL);
2868 assert(varsC2 != NULL);
2869 assert(varsR != NULL);
2870 assert(nvarsF >= 0);
2871 assert(nvarsC2 >= 0);
2872 assert(nvarsR >= 0);
2873
2874 /* allocates temporary memory */
2879
2880 /* gets sorting key for variables in F corresponding to the following lifting sequence
2881 * sequence 1: non-increasing absolute difference between x*_j and the value the variable is fixed to, i.e.
2882 * x*_1 >= x*_2 >= ... >= x*_|F|
2883 * in case of equality uses
2884 * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2885 */
2886 for( j = 0; j < nvarsF; j++ )
2887 {
2889 sortkeypairsF[j]->key1 = solvals[varsF[j]];
2890 sortkeypairsF[j]->key2 = (SCIP_Real) weights[varsF[j]];
2891 }
2892
2893 /* gets sorting key for variables in C_2 corresponding to the following lifting sequence
2894 * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2895 */
2896 for( j = 0; j < nvarsC2; j++ )
2897 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2898
2899 /* gets sorting key for variables in R corresponding to the following lifting sequence
2900 * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|R|
2901 */
2902 for( j = 0; j < nvarsR; j++ )
2903 sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
2904
2905 /* sorts F, C2 and R */
2906 if( nvarsF > 0 )
2907 {
2909 }
2910 if( nvarsC2 > 0 )
2911 {
2913 }
2914 if( nvarsR > 0)
2915 {
2917 }
2918
2919 /* frees temporary memory */
2924
2925 return SCIP_OKAY;
2926}
2927
2928/** categorizes GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of the GUBs
2929 * for the sequential GUB wise lifting procedure
2930 */
2931static
2933 SCIP* scip, /**< SCIP data structure */
2934 SCIP_GUBSET* gubset, /**< GUB set data structure */
2935 SCIP_Real* solvals, /**< solution values of variables in knapsack constraint */
2936 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2937 int* varsC1, /**< variables in C1 */
2938 int* varsC2, /**< variables in C2 */
2939 int* varsF, /**< variables in F */
2940 int* varsR, /**< variables in R */
2941 int nvarsC1, /**< number of variables in C1 */
2942 int nvarsC2, /**< number of variables in C2 */
2943 int nvarsF, /**< number of variables in F */
2944 int nvarsR, /**< number of variables in R */
2945 int* gubconsGC1, /**< pointer to store GUBs in GC1(GNC1+GOC1) */
2946 int* gubconsGC2, /**< pointer to store GUBs in GC2 */
2947 int* gubconsGFC1, /**< pointer to store GUBs in GFC1(GNC1+GF) */
2948 int* gubconsGR, /**< pointer to store GUBs in GR */
2949 int* ngubconsGC1, /**< pointer to store number of GUBs in GC1(GNC1+GOC1) */
2950 int* ngubconsGC2, /**< pointer to store number of GUBs in GC2 */
2951 int* ngubconsGFC1, /**< pointer to store number of GUBs in GFC1(GNC1+GF) */
2952 int* ngubconsGR, /**< pointer to store number of GUBs in GR */
2953 int* ngubconscapexceed, /**< pointer to store number of GUBs with only capacity exceeding variables */
2954 int* maxgubvarssize /**< pointer to store the maximal size of GUB constraints */
2955 )
2956{
2959 SCIP_Real* sortkeysC1;
2960 SCIP_Real* sortkeysC2;
2961 SCIP_Real* sortkeysR;
2962 int* nC1varsingubcons;
2963 int var;
2964 int gubconsidx;
2965 int varidx;
2966 int ngubconss;
2967 int ngubconsGOC1;
2968 int targetvar;
2969#ifndef NDEBUG
2970 int nvarsprocessed = 0;
2971#endif
2972 int i;
2973 int j;
2974
2975#if GUBSPLITGNC1GUBS
2976 SCIP_Bool gubconswithF;
2977 int origngubconss;
2978 origngubconss = gubset->ngubconss;
2979#endif
2980
2981 assert(scip != NULL);
2982 assert(gubset != NULL);
2983 assert(solvals != NULL);
2984 assert(weights != NULL);
2985 assert(varsC1 != NULL);
2986 assert(varsC2 != NULL);
2987 assert(varsF != NULL);
2988 assert(varsR != NULL);
2989 assert(nvarsC1 > 0);
2990 assert(nvarsC2 >= 0);
2991 assert(nvarsF >= 0);
2992 assert(nvarsR >= 0);
2996 assert(gubconsGR != NULL);
3002
3003 ngubconss = gubset->ngubconss;
3004 ngubconsGOC1 = 0;
3005
3006 /* GUBs are categorized into different types according to the variables in volved
3007 * - GOC1: involves variables in C1 only -- no C2, R, F
3008 * - GNC1: involves variables in C1 and F (and R) -- no C2
3009 * - GF: involves variables in F (and R) only -- no C1, C2
3010 * - GC2: involves variables in C2 only -- no C1, R, F
3011 * - GR: involves variables in R only -- no C1, C2, F
3012 * which requires splitting GUBs in case they include variable in F and R.
3013 *
3014 * afterwards all GUBs (except GOC1 GUBs, which we do not need to lift) are sorted by a two level lifting sequence.
3015 * - first ordering level is: GFC1 (GNC1+GF), GC2, and GR.
3016 * - second ordering level is
3017 * GFC1: non-increasing number of variables in F and non-increasing max{x*_k : k in GFC1_j} in case of equality
3018 * GC2: non-increasing max{ a_k : k in GC2_j}; note that |GFC2_j| = 1
3019 * GR: non-increasing max{ a_k : k in GR_j}
3020 *
3021 * in additon, another GUB union, which is helpful for the lifting procedure, is formed
3022 * - GC1: GUBs of category GOC1 and GNC1
3023 * with second ordering level non-decreasing min{ a_k : k in GC1_j };
3024 * note that min{ a_k : k in GC1_j } always comes from the first variable in the GUB
3025 */
3026
3027 /* allocates temporary memory */
3031
3032 /* to get the GUB lifting sequence, we first sort all variables in F, C2, and R
3033 * - F: non-increasing x*_j and non-increasing a_j in case of equality
3034 * - C2: non-increasing a_j
3035 * - R: non-increasing a_j
3036 * furthermore, sort C1 variables as needed for initializing the minweight table (non-increasing a_j).
3037 */
3038
3039 /* gets sorting key for variables in C1 corresponding to the following ordering
3040 * non-decreasing a_j, i.e. a_1 <= a_2 <= ... <= a_|C_1|
3041 */
3042 for( j = 0; j < nvarsC1; j++ )
3043 {
3044 /* gets sortkeys */
3045 sortkeysC1[j] = (SCIP_Real) weights[varsC1[j]];
3046
3047 /* update status of variable in its gub constraint */
3048 gubconsidx = gubset->gubconssidx[varsC1[j]];
3049 varidx = gubset->gubvarsidx[varsC1[j]];
3050 gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C1;
3051 }
3052
3053 /* gets sorting key for variables in F corresponding to the following ordering
3054 * non-increasing x*_j, i.e., x*_1 >= x*_2 >= ... >= x*_|F|, and
3055 * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|F| in case of equality
3056 * and updates status of each variable in F in GUB set data structure
3057 */
3058 for( j = 0; j < nvarsF; j++ )
3059 {
3060 /* update status of variable in its gub constraint */
3061 gubconsidx = gubset->gubconssidx[varsF[j]];
3062 varidx = gubset->gubvarsidx[varsF[j]];
3063 gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_F;
3064 }
3065
3066 /* gets sorting key for variables in C2 corresponding to the following ordering
3067 * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|C2|
3068 * and updates status of each variable in F in GUB set data structure
3069 */
3070 for( j = 0; j < nvarsC2; j++ )
3071 {
3072 /* gets sortkeys */
3073 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
3074
3075 /* update status of variable in its gub constraint */
3076 gubconsidx = gubset->gubconssidx[varsC2[j]];
3077 varidx = gubset->gubvarsidx[varsC2[j]];
3078 gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C2;
3079 }
3080
3081 /* gets sorting key for variables in R corresponding to the following ordering
3082 * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|R|
3083 * and updates status of each variable in F in GUB set data structure
3084 */
3085 for( j = 0; j < nvarsR; j++ )
3086 {
3087 /* gets sortkeys */
3088 sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
3089
3090 /* update status of variable in its gub constraint */
3091 gubconsidx = gubset->gubconssidx[varsR[j]];
3092 varidx = gubset->gubvarsidx[varsR[j]];
3093 gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_R;
3094 }
3095
3096 /* sorts C1, F, C2 and R */
3097 assert(nvarsC1 > 0);
3099
3100 if( nvarsC2 > 0 )
3101 {
3103 }
3104 if( nvarsR > 0)
3105 {
3107 }
3108
3109 /* frees temporary memory */
3113
3114 /* allocate and initialize temporary memory for sorting GUB constraints */
3119 for( i = 0; i < ngubconss; i++)
3120 {
3122 sortkeypairsGFC1[i]->key1 = 0.0;
3123 sortkeypairsGFC1[i]->key2 = 0.0;
3124 }
3125 *ngubconsGC1 = 0;
3126 *ngubconsGC2 = 0;
3127 *ngubconsGFC1 = 0;
3128 *ngubconsGR = 0;
3129 *ngubconscapexceed = 0;
3130 *maxgubvarssize = 0;
3131
3132#ifndef NDEBUG
3133 for( i = 0; i < gubset->ngubconss; i++ )
3134 assert(gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL);
3135#endif
3136
3137 /* stores GUBs of group GC1 (GOC1+GNC1) and part of the GUBs of group GFC1 (GNC1 GUBs) and sorts variables in these GUBs
3138 * s.t. C1 variables come first (will automatically be sorted by non-decreasing weight).
3139 * gets sorting keys for GUBs of type GFC1 corresponding to the following ordering
3140 * non-increasing number of variables in F, and
3141 * non-increasing max{x*_k : k in GFC1_j} in case of equality
3142 */
3143 for( i = 0; i < nvarsC1; i++ )
3144 {
3145 int nvarsC1capexceed;
3146
3147 nvarsC1capexceed = 0;
3148
3149 var = varsC1[i];
3150 gubconsidx = gubset->gubconssidx[var];
3151 varidx = gubset->gubvarsidx[var];
3152
3154 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C1);
3155
3156 /* current C1 variable is put to the front of its GUB where C1 part is stored by non-decreasing weigth;
3157 * note that variables in C1 are already sorted by non-decreasing weigth
3158 */
3159 targetvar = gubset->gubconss[gubconsidx]->gubvars[nC1varsingubcons[gubconsidx]];
3162
3163 /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3164 if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3165 {
3167 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3168 continue;
3169 }
3170
3171 /* determine the status of the current GUB constraint, GOC1 or GNC1; GUBs involving R variables are split into
3172 * GOC1/GNC1 and GF, if wanted. also update sorting key if GUB is of type GFC1 (GNC1)
3173 */
3174#if GUBSPLITGNC1GUBS
3176#endif
3177 for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3178 {
3179 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2);
3180
3181 /* C1-variable: update number of C1/capacity exceeding variables */
3182 if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_C1 )
3183 {
3185#ifndef NDEBUG
3187#endif
3188 }
3189 /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3190 else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3191 {
3192#if GUBSPLITGNC1GUBS
3194#endif
3195 sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3196
3197 if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3198 sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3199 }
3200 else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_CAPACITYEXCEEDED )
3201 {
3203 }
3204 else
3205 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_R);
3206 }
3207
3208 /* update set of GC1 GUBs */
3210 (*ngubconsGC1)++;
3211
3212 /* update maximum size of all GUB constraints */
3213 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3214 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3215
3216 /* set status of GC1-GUB (GOC1 or GNC1) and update set of GFC1 GUBs */
3217 if( nvarsC1capexceed == gubset->gubconss[gubconsidx]->ngubvars )
3218 {
3220 ngubconsGOC1++;
3221 }
3222 else
3223 {
3224#if GUBSPLITGNC1GUBS
3225 /* only variables in C1 and R -- no in F: GUB will be split into GR and GOC1 GUBs */
3226 if( !gubconswithF )
3227 {
3229
3230 assert(gubset->ngubconss < gubset->nvars);
3231
3232 /* create a new GUB for GR part of splitting */
3233 SCIP_CALL( GUBconsCreate(scip, &gubset->gubconss[gubset->ngubconss]) );
3234 gubset->ngubconss++;
3235 ngubconss = gubset->ngubconss;
3236
3237 /* fill GR with R variables in current GUB */
3238 for( j = gubset->gubconss[gubconsidx]->ngubvars-1; j >= 0; j-- )
3239 {
3240 movevarstatus = gubset->gubconss[gubconsidx]->gubvarsstatus[j];
3242 {
3244 SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, gubset->gubconss[gubconsidx]->gubvars[j],
3245 gubconsidx, ngubconss-1) );
3246 gubset->gubconss[ngubconss-1]->gubvarsstatus[gubset->gubconss[ngubconss-1]->ngubvars-1] =
3248 }
3249 }
3250
3252 ngubconsGOC1++;
3253
3256 (*ngubconsGR)++;
3257 }
3258 /* variables in C1, F, and maybe R: GNC1 GUB */
3259 else
3260 {
3262
3265 (*ngubconsGFC1)++;
3266 }
3267#else
3270 (*ngubconsGFC1)++;
3271#endif
3272 }
3273 }
3274
3275 /* stores GUBs of group GC2 (only trivial GUBs); sorting is not required because the C2 variables (which we loop over)
3276 * are already sorted correctly
3277 */
3278 for( i = 0; i < nvarsC2; i++ )
3279 {
3280 var = varsC2[i];
3281 gubconsidx = gubset->gubconssidx[var];
3282 varidx = gubset->gubvarsidx[var];
3283
3285 assert(gubset->gubconss[gubconsidx]->ngubvars == 1);
3286 assert(varidx == 0);
3287 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C2);
3288 assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_UNINITIAL);
3289
3290 /* set status of GC2 GUB */
3292
3293 /* update group of GC2 GUBs */
3295 (*ngubconsGC2)++;
3296
3297 /* update maximum size of all GUB constraints */
3298 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3299 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3300
3301#ifndef NDEBUG
3303#endif
3304 }
3305
3306 /* stores remaining part of the GUBs of group GFC1 (GF GUBs) and gets GUB sorting keys corresp. to following ordering
3307 * non-increasing number of variables in F, and
3308 * non-increasing max{x*_k : k in GFC1_j} in case of equality
3309 */
3310 for( i = 0; i < nvarsF; i++ )
3311 {
3312 var = varsF[i];
3313 gubconsidx = gubset->gubconssidx[var];
3314 varidx = gubset->gubvarsidx[var];
3315
3317 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_F);
3318
3319#ifndef NDEBUG
3321#endif
3322
3323 /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3324 if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3325 {
3327 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3328 continue;
3329 }
3330
3331 /* set status of GF GUB */
3333
3334 /* update sorting key of corresponding GFC1 GUB */
3335 for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3336 {
3337 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2
3338 && gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C1);
3339
3340 /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3341 if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3342 {
3343 sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3344
3345 if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3346 sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3347 }
3348 }
3349
3350 /* update set of GFC1 GUBs */
3352 (*ngubconsGFC1)++;
3353
3354 /* update maximum size of all GUB constraints */
3355 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3356 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3357 }
3358
3359 /* stores GUBs of group GR; sorting is not required because the R variables (which we loop over) are already sorted
3360 * correctly
3361 */
3362 for( i = 0; i < nvarsR; i++ )
3363 {
3364 var = varsR[i];
3365 gubconsidx = gubset->gubconssidx[var];
3366 varidx = gubset->gubvarsidx[var];
3367
3369 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_R);
3370
3371#ifndef NDEBUG
3373#endif
3374
3375 /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3376 if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3377 {
3379 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3380 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3381 continue;
3382 }
3383
3384 /* set status of GR GUB */
3386
3387 /* update set of GR GUBs */
3389 (*ngubconsGR)++;
3390
3391 /* update maximum size of all GUB constraints */
3392 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3393 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3394 }
3396
3397 /* update number of GUBs with only capacity exceeding variables (will not be used for lifting) */
3398 (*ngubconscapexceed) = ngubconss - (ngubconsGOC1 + (*ngubconsGC2) + (*ngubconsGFC1) + (*ngubconsGR));
3400#ifndef NDEBUG
3401 {
3402 int check;
3403
3404 check = 0;
3405
3406 /* remaining not handled GUBs should only contain capacity exceeding variables */
3407 for( i = 0; i < ngubconss; i++ )
3408 {
3409 if( gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL )
3410 check++;
3411 }
3412 assert(check == *ngubconscapexceed);
3413 }
3414#endif
3415
3416 /* sort GFCI GUBs according to computed sorting keys */
3417 if( (*ngubconsGFC1) > 0 )
3418 {
3420 }
3421
3422 /* free temporary memory */
3423#if GUBSPLITGNC1GUBS
3425#endif
3429
3430 return SCIP_OKAY;
3431}
3432
3433/** enlarges minweight table to at least the given length */
3434static
3436 SCIP* scip, /**< SCIP data structure */
3437 SCIP_Longint** minweightsptr, /**< pointer to minweights table */
3438 int* minweightslen, /**< pointer to store number of entries in minweights table (incl. z=0) */
3439 int* minweightssize, /**< pointer to current size of minweights table */
3440 int newlen /**< new length of minweights table */
3441 )
3442{
3443 int j;
3444
3448 assert(*minweightslen >= 0);
3450 assert(*minweightssize >= 0);
3451
3452 if( newlen > *minweightssize )
3453 {
3454 int newsize;
3455
3456 /* reallocate table memory */
3460 }
3462
3463 /* initialize new elements */
3464 for( j = *minweightslen; j < newlen; ++j )
3467
3468 return SCIP_OKAY;
3469}
3470
3471/** lifts given inequality
3472 * sum_{j in M_1} x_j <= alpha_0
3473 * valid for
3474 * 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 }
3475 * to a valid inequality
3476 * 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
3477 * <= alpha_0 + sum_{j in M_2} alpha_j
3478 * for
3479 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 };
3480 * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in M_2, and
3481 * sequential up-lifting for the variables in R; procedure can be used to strengthen minimal cover inequalities and
3482 * extended weight inequalities.
3483 */
3484static
3486 SCIP* scip, /**< SCIP data structure */
3487 SCIP_VAR** vars, /**< variables in knapsack constraint */
3488 int nvars, /**< number of variables in knapsack constraint */
3489 int ntightened, /**< number of variables with tightened upper bound */
3490 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3491 SCIP_Longint capacity, /**< capacity of knapsack */
3492 SCIP_Real* solvals, /**< solution values of all problem variables */
3493 int* varsM1, /**< variables in M_1 */
3494 int* varsM2, /**< variables in M_2 */
3495 int* varsF, /**< variables in F */
3496 int* varsR, /**< variables in R */
3497 int nvarsM1, /**< number of variables in M_1 */
3498 int nvarsM2, /**< number of variables in M_2 */
3499 int nvarsF, /**< number of variables in F */
3500 int nvarsR, /**< number of variables in R */
3501 int alpha0, /**< rights hand side of given valid inequality */
3502 int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3503 SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3504 int* liftrhs /**< pointer to store right hand side of the lifted valid inequality */
3505 )
3506{
3507 SCIP_Longint* minweights;
3508 SCIP_Real* sortkeys;
3509 SCIP_Longint fixedonesweight;
3510 int minweightssize;
3511 int minweightslen;
3512 int j;
3513 int w;
3514
3515 assert(scip != NULL);
3516 assert(vars != NULL);
3517 assert(nvars >= 0);
3518 assert(weights != NULL);
3519 assert(capacity >= 0);
3520 assert(solvals != NULL);
3521 assert(varsM1 != NULL);
3522 assert(varsM2 != NULL);
3523 assert(varsF != NULL);
3524 assert(varsR != NULL);
3525 assert(nvarsM1 >= 0 && nvarsM1 <= nvars - ntightened);
3526 assert(nvarsM2 >= 0 && nvarsM2 <= nvars - ntightened);
3527 assert(nvarsF >= 0 && nvarsF <= nvars - ntightened);
3528 assert(nvarsR >= 0 && nvarsR <= nvars - ntightened);
3529 assert(nvarsM1 + nvarsM2 + nvarsF + nvarsR == nvars - ntightened);
3530 assert(alpha0 >= 0);
3531 assert(liftcoefs != NULL);
3532 assert(cutact != NULL);
3533 assert(liftrhs != NULL);
3534
3535 /* allocates temporary memory */
3536 minweightssize = nvarsM1 + 1;
3539
3540 /* initializes data structures */
3542 *cutact = 0.0;
3543
3544 /* sets lifting coefficient of variables in M1, sorts variables in M1 such that a_1 <= a_2 <= ... <= a_|M1|
3545 * and calculates activity of the current valid inequality
3546 */
3547 for( j = 0; j < nvarsM1; j++ )
3548 {
3549 assert(liftcoefs[varsM1[j]] == 0);
3550 liftcoefs[varsM1[j]] = 1;
3551 sortkeys[j] = (SCIP_Real) (weights[varsM1[j]]);
3552 (*cutact) += solvals[varsM1[j]];
3553 }
3554
3556
3557 /* initializes (i = 1) the minweight table, defined as: minweights_i[w] =
3558 * min sum_{j in M_1} a_j x_j + sum_{k=1}^{i-1} a_{j_k} x_{j_k}
3559 * s.t. sum_{j in M_1} x_j + sum_{k=1}^{i-1} alpha_{j_k} x_{j_k} >= w
3560 * x_j in {0,1} for j in M_1 & {j_i,...,j_i-1},
3561 * for i = 1,...,t with t = |N\M1| and w = 0,...,|M1| + sum_{k=1}^{i-1} alpha_{j_k};
3562 */
3563 minweights[0] = 0;
3564 for( w = 1; w <= nvarsM1; w++ )
3565 minweights[w] = minweights[w-1] + weights[varsM1[w-1]];
3566 minweightslen = nvarsM1 + 1;
3567
3568 /* gets sum of weights of variables fixed to one, i.e. sum of weights of variables in M_2 */
3569 fixedonesweight = 0;
3570 for( j = 0; j < nvarsM2; j++ )
3571 fixedonesweight += weights[varsM2[j]];
3572 assert(fixedonesweight >= 0);
3573
3574 /* initializes right hand side of lifted valid inequality */
3575 *liftrhs = alpha0;
3576
3577 /* sequentially up-lifts all variables in F: */
3578 for( j = 0; j < nvarsF; j++ )
3579 {
3580 SCIP_Longint weight;
3581 int liftvar;
3582 int liftcoef;
3583 int z;
3584
3585 liftvar = varsF[j];
3586 weight = weights[liftvar];
3587 assert(liftvar >= 0 && liftvar < nvars);
3588 assert(SCIPisFeasGT(scip, solvals[liftvar], 0.0));
3589 assert(weight > 0);
3590
3591 /* knapsack problem is infeasible:
3592 * sets z = 0
3593 */
3594 if( capacity - fixedonesweight - weight < 0 )
3595 {
3596 z = 0;
3597 }
3598 /* knapsack problem is feasible:
3599 * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
3600 * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
3601 */
3602 else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
3603 {
3604 z = *liftrhs;
3605 }
3606 /* knapsack problem is feasible:
3607 * uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} }
3608 */
3609 else
3610 {
3611 int left;
3612 int right;
3613 int middle;
3614
3615 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
3616 left = 0;
3617 right = (*liftrhs) + 1;
3618 while( left < right - 1 )
3619 {
3620 middle = (left + right) / 2;
3621 assert(0 <= middle && middle < minweightslen);
3622 if( minweights[middle] <= capacity - fixedonesweight - weight )
3623 left = middle;
3624 else
3625 right = middle;
3626 }
3627 assert(left == right - 1);
3628 assert(0 <= left && left < minweightslen);
3629 assert(minweights[left] <= capacity - fixedonesweight - weight );
3630 assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
3631
3632 /* now z = left */
3633 z = left;
3634 assert(z <= *liftrhs);
3635 }
3636
3637 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3638 liftcoef = (*liftrhs) - z;
3640 assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
3641
3642 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3643 if( liftcoef == 0 )
3644 continue;
3645
3646 /* updates activity of current valid inequality */
3647 (*cutact) += liftcoef * solvals[liftvar];
3648
3649 /* enlarges current minweight table:
3650 * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3651 * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3652 * and sets minweights_i[w] = infinity for
3653 * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3654 */
3656
3657 /* updates minweight table: minweight_i+1[w] =
3658 * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3659 * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3660 */
3661 for( w = minweightslen - 1; w >= 0; w-- )
3662 {
3663 SCIP_Longint min;
3664 if( w < liftcoef )
3665 {
3666 min = MIN(minweights[w], weight);
3667 minweights[w] = min;
3668 }
3669 else
3670 {
3671 assert(w >= liftcoef);
3672 min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3673 minweights[w] = min;
3674 }
3675 }
3676 }
3677 assert(minweights[0] == 0);
3678
3679 /* sequentially down-lifts all variables in M_2: */
3680 for( j = 0; j < nvarsM2; j++ )
3681 {
3682 SCIP_Longint weight;
3683 int liftvar;
3684 int liftcoef;
3685 int left;
3686 int right;
3687 int middle;
3688 int z;
3689
3690 liftvar = varsM2[j];
3691 weight = weights[liftvar];
3692 assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
3693 assert(liftvar >= 0 && liftvar < nvars);
3694 assert(weight > 0);
3695
3696 /* uses binary search to find
3697 * z = max { w : 0 <= w <= |M_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
3698 */
3699 left = 0;
3700 right = minweightslen;
3701 while( left < right - 1 )
3702 {
3703 middle = (left + right) / 2;
3704 assert(0 <= middle && middle < minweightslen);
3705 if( minweights[middle] <= capacity - fixedonesweight + weight )
3706 left = middle;
3707 else
3708 right = middle;
3709 }
3710 assert(left == right - 1);
3711 assert(0 <= left && left < minweightslen);
3712 assert(minweights[left] <= capacity - fixedonesweight + weight );
3713 assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight + weight);
3714
3715 /* now z = left */
3716 z = left;
3717 assert(z >= *liftrhs);
3718
3719 /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
3720 liftcoef = z - (*liftrhs);
3722 assert(liftcoef >= 0);
3723
3724 /* updates sum of weights of variables fixed to one */
3725 fixedonesweight -= weight;
3726
3727 /* updates right-hand side of current valid inequality */
3728 (*liftrhs) += liftcoef;
3729 assert(*liftrhs >= alpha0);
3730
3731 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3732 if( liftcoef == 0 )
3733 continue;
3734
3735 /* updates activity of current valid inequality */
3736 (*cutact) += liftcoef * solvals[liftvar];
3737
3738 /* enlarges current minweight table:
3739 * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3740 * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3741 * and sets minweights_i[w] = infinity for
3742 * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3743 */
3745
3746 /* updates minweight table: minweight_i+1[w] =
3747 * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3748 * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3749 */
3750 for( w = minweightslen - 1; w >= 0; w-- )
3751 {
3752 SCIP_Longint min;
3753 if( w < liftcoef )
3754 {
3755 min = MIN(minweights[w], weight);
3756 minweights[w] = min;
3757 }
3758 else
3759 {
3760 assert(w >= liftcoef);
3761 min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3762 minweights[w] = min;
3763 }
3764 }
3765 }
3766 assert(fixedonesweight == 0);
3767 assert(*liftrhs >= alpha0);
3768
3769 /* sequentially up-lifts all variables in R: */
3770 for( j = 0; j < nvarsR; j++ )
3771 {
3772 SCIP_Longint weight;
3773 int liftvar;
3774 int liftcoef;
3775 int z;
3776
3777 liftvar = varsR[j];
3778 weight = weights[liftvar];
3779 assert(liftvar >= 0 && liftvar < nvars);
3780 assert(SCIPisFeasEQ(scip, solvals[liftvar], 0.0));
3781 assert(weight > 0);
3782 assert(capacity - weight >= 0);
3783 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
3784
3785 /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
3786 * if minweights_i[liftrhs] <= a_0 - a_{j_i}
3787 */
3788 if( minweights[*liftrhs] <= capacity - weight )
3789 {
3790 z = *liftrhs;
3791 }
3792 /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
3793 */
3794 else
3795 {
3796 int left;
3797 int right;
3798 int middle;
3799
3800 left = 0;
3801 right = (*liftrhs) + 1;
3802 while( left < right - 1)
3803 {
3804 middle = (left + right) / 2;
3805 assert(0 <= middle && middle < minweightslen);
3806 if( minweights[middle] <= capacity - weight )
3807 left = middle;
3808 else
3809 right = middle;
3810 }
3811 assert(left == right - 1);
3812 assert(0 <= left && left < minweightslen);
3813 assert(minweights[left] <= capacity - weight );
3814 assert(left == minweightslen - 1 || minweights[left+1] > capacity - weight);
3815
3816 /* now z = left */
3817 z = left;
3818 assert(z <= *liftrhs);
3819 }
3820
3821 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3822 liftcoef = (*liftrhs) - z;
3824 assert(liftcoef >= 0 && liftcoef <= *liftrhs);
3825
3826 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3827 if( liftcoef == 0 )
3828 continue;
3829
3830 /* updates activity of current valid inequality */
3831 (*cutact) += liftcoef * solvals[liftvar];
3832
3833 /* updates minweight table: minweight_i+1[w] =
3834 * min{ minweight_i[w], a_{j_i}}, if w < alpha_j_i
3835 * min{ minweight_i[w], minweight_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3836 */
3837 for( w = *liftrhs; w >= 0; w-- )
3838 {
3839 SCIP_Longint min;
3840 if( w < liftcoef )
3841 {
3842 min = MIN(minweights[w], weight);
3843 minweights[w] = min;
3844 }
3845 else
3846 {
3847 assert(w >= liftcoef);
3848 min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3849 minweights[w] = min;
3850 }
3851 }
3852 }
3853
3854 /* frees temporary memory */
3857
3858 return SCIP_OKAY;
3859}
3860
3861/** adds two minweight values in a safe way, i.e,, ensures no overflow */
3862static
3864 SCIP_Longint val1, /**< first value to add */
3865 SCIP_Longint val2 /**< second value to add */
3866 )
3867{
3868 assert(val1 >= 0);
3869 assert(val2 >= 0);
3870
3872 return SCIP_LONGINT_MAX;
3873 else
3874 {
3876 return (val1 + val2);
3877 }
3878}
3879
3880/** computes minweights table for lifting with GUBs by combining unfished and fished tables */
3881static
3883 SCIP_Longint* minweights, /**< minweight table to compute */
3884 SCIP_Longint* finished, /**< given finished table */
3885 SCIP_Longint* unfinished, /**< given unfinished table */
3886 int minweightslen /**< length of minweight, finished, and unfinished tables */
3887 )
3888{
3889 int w1;
3890 int w2;
3891
3892 /* minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
3893 * note that finished and unfished arrays sorted by non-decreasing weight
3894 */
3895
3896 /* initialize minweight with w2 = 0 */
3897 w2 = 0;
3898 assert(unfinished[w2] == 0);
3899 for( w1 = 0; w1 < minweightslen; w1++ )
3901
3902 /* consider w2 = 1, ..., minweightslen-1 */
3903 for( w2 = 1; w2 < minweightslen; w2++ )
3904 {
3906 break;
3907
3908 for( w1 = 0; w1 < minweightslen - w2; w1++ )
3909 {
3910 SCIP_Longint temp;
3911
3913 if( temp <= minweights[w1+w2] )
3914 minweights[w1+w2] = temp;
3915 }
3916 }
3917}
3918
3919/** lifts given inequality
3920 * sum_{j in C_1} x_j <= alpha_0
3921 * valid for
3922 * 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;
3923 * sum_{j in Q_i} x_j <= 1, forall i in I }
3924 * to a valid inequality
3925 * 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
3926 * <= alpha_0 + sum_{j in C_2} alpha_j
3927 * for
3928 * 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 };
3929 * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
3930 * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
3931 * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
3932 */
3933static
3935 SCIP* scip, /**< SCIP data structure */
3936 SCIP_GUBSET* gubset, /**< GUB set data structure */
3937 SCIP_VAR** vars, /**< variables in knapsack constraint */
3938 int ngubconscapexceed, /**< number of GUBs with only capacity exceeding variables */
3939 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3940 SCIP_Longint capacity, /**< capacity of knapsack */
3941 SCIP_Real* solvals, /**< solution values of all knapsack variables */
3942 int* gubconsGC1, /**< GUBs in GC1(GNC1+GOC1) */
3943 int* gubconsGC2, /**< GUBs in GC2 */
3944 int* gubconsGFC1, /**< GUBs in GFC1(GNC1+GF) */
3945 int* gubconsGR, /**< GUBs in GR */
3946 int ngubconsGC1, /**< number of GUBs in GC1(GNC1+GOC1) */
3947 int ngubconsGC2, /**< number of GUBs in GC2 */
3948 int ngubconsGFC1, /**< number of GUBs in GFC1(GNC1+GF) */
3949 int ngubconsGR, /**< number of GUBs in GR */
3950 int alpha0, /**< rights hand side of given valid inequality */
3951 int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3952 SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3953 int* liftrhs, /**< pointer to store right hand side of the lifted valid inequality */
3954 int maxgubvarssize /**< maximal size of GUB constraints */
3955 )
3956{
3957 SCIP_Longint* minweights;
3958 SCIP_Longint* finished;
3959 SCIP_Longint* unfinished;
3960 int* gubconsGOC1;
3961 int* gubconsGNC1;
3962 int* liftgubvars;
3963 SCIP_Longint fixedonesweight;
3964 SCIP_Longint weight;
3965 SCIP_Longint weightdiff1;
3966 SCIP_Longint weightdiff2;
3967 SCIP_Longint min;
3968 int minweightssize;
3969 int minweightslen;
3970 int nvars;
3971 int varidx;
3972 int liftgubconsidx;
3973 int liftvar;
3974 int sumliftcoef;
3975 int liftcoef;
3976 int ngubconsGOC1;
3977 int ngubconsGNC1;
3978 int left;
3979 int right;
3980 int middle;
3981 int nliftgubvars;
3982 int tmplen;
3983 int tmpsize;
3984 int j;
3985 int k;
3986 int w;
3987 int z;
3988#ifndef NDEBUG
3989 int ngubconss;
3990 int nliftgubC1;
3991
3992 assert(gubset != NULL);
3993 ngubconss = gubset->ngubconss;
3994#else
3995 assert(gubset != NULL);
3996#endif
3997
3998 nvars = gubset->nvars;
3999
4000 assert(scip != NULL);
4001 assert(vars != NULL);
4002 assert(nvars >= 0);
4003 assert(weights != NULL);
4004 assert(capacity >= 0);
4005 assert(solvals != NULL);
4009 assert(gubconsGR != NULL);
4014 assert(alpha0 >= 0);
4015 assert(liftcoefs != NULL);
4016 assert(cutact != NULL);
4017 assert(liftrhs != NULL);
4018
4020
4021 /* allocates temporary memory */
4028
4029 /* initializes data structures */
4031 *cutact = 0.0;
4032
4033 /* gets GOC1 and GNC1 GUBs, sets lifting coefficient of variables in C1 and calculates activity of the current
4034 * valid inequality
4035 */
4036 ngubconsGOC1 = 0;
4037 ngubconsGNC1 = 0;
4038 for( j = 0; j < ngubconsGC1; j++ )
4039 {
4040 if( gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GOC1 )
4041 {
4043 ngubconsGOC1++;
4044 }
4045 else
4046 {
4049 ngubconsGNC1++;
4050 }
4051 for( k = 0; k < gubset->gubconss[gubconsGC1[j]]->ngubvars
4052 && gubset->gubconss[gubconsGC1[j]]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4053 {
4054 varidx = gubset->gubconss[gubconsGC1[j]]->gubvars[k];
4055 assert(varidx >= 0 && varidx < nvars);
4056 assert(liftcoefs[varidx] == 0);
4057
4058 liftcoefs[varidx] = 1;
4059 (*cutact) += solvals[varidx];
4060 }
4061 assert(k >= 1);
4062 }
4065
4066 /* initialize the minweight tables, defined as: for i = 1,...,m with m = |I| and w = 0,...,|gubconsGC1|;
4067 * - finished_i[w] =
4068 * min sum_{k = 1,2,...,i-1} sum_{j in Q_k} a_j x_j
4069 * s.t. sum_{k = 1,2,...,i-1} sum_{j in Q_k} alpha_j x_j >= w
4070 * sum_{j in Q_k} x_j <= 1
4071 * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4072 * - unfinished_i[w] =
4073 * min sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} a_j x_j
4074 * s.t. sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} x_j >= w
4075 * sum_{j in Q_k} x_j <= 1
4076 * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4077 * - minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
4078 */
4079
4080 /* initialize finished table; note that variables in GOC1 GUBs (includes C1 and capacity exceeding variables)
4081 * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4082 * 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
4083 * comes from the first variable in the GUB
4084 */
4086 finished[0] = 0;
4087 for( w = 1; w <= ngubconsGOC1; w++ )
4088 {
4090
4092 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4093
4094 varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4095
4096 assert(varidx >= 0 && varidx < nvars);
4097 assert(liftcoefs[varidx] == 1);
4098
4099 min = weights[varidx];
4100 finished[w] = finished[w-1] + min;
4101
4102#ifndef NDEBUG
4103 for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4104 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4105 {
4106 varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4107 assert(varidx >= 0 && varidx < nvars);
4108 assert(liftcoefs[varidx] == 1);
4109 assert(weights[varidx] >= min);
4110 }
4111#endif
4112 }
4113 for( w = ngubconsGOC1+1; w <= ngubconsGC1; w++ )
4115
4116 /* initialize unfinished table; note that variables in GNC1 GUBs
4117 * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4118 * 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
4119 * comes from the first variable in the GUB
4120 */
4122 unfinished[0] = 0;
4123 for( w = 1; w <= ngubconsGNC1; w++ )
4124 {
4126
4128 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4129
4130 varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4131
4132 assert(varidx >= 0 && varidx < nvars);
4133 assert(liftcoefs[varidx] == 1);
4134
4135 min = weights[varidx];
4136 unfinished[w] = unfinished[w-1] + min;
4137
4138#ifndef NDEBUG
4139 for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4140 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4141 {
4142 varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4143 assert(varidx >= 0 && varidx < nvars);
4144 assert(liftcoefs[varidx] == 1);
4145 assert(weights[varidx] >= min );
4146 }
4147#endif
4148 }
4149 for( w = ngubconsGNC1 + 1; w <= ngubconsGC1; w++ )
4151
4152 /* initialize minweights table; note that variables in GC1 GUBs
4153 * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4154 * we can directly initialize minweights instead of computing it from finished and unfinished (which would be more time
4155 * consuming) because is it has to be build using weights from C1 only.
4156 */
4158 minweights[0] = 0;
4159 for( w = 1; w <= ngubconsGC1; w++ )
4160 {
4162
4165 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4166
4167 varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4168
4169 assert(varidx >= 0 && varidx < nvars);
4170 assert(liftcoefs[varidx] == 1);
4171
4172 min = weights[varidx];
4173 minweights[w] = minweights[w-1] + min;
4174
4175#ifndef NDEBUG
4176 for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4177 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4178 {
4179 varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4180 assert(varidx >= 0 && varidx < nvars);
4181 assert(liftcoefs[varidx] == 1);
4182 assert(weights[varidx] >= min);
4183 }
4184#endif
4185 }
4187
4188 /* gets sum of weights of variables fixed to one, i.e. sum of weights of C2 variables GC2 GUBs */
4189 fixedonesweight = 0;
4190 for( j = 0; j < ngubconsGC2; j++ )
4191 {
4192 varidx = gubset->gubconss[gubconsGC2[j]]->gubvars[0];
4193
4194 assert(gubset->gubconss[gubconsGC2[j]]->ngubvars == 1);
4195 assert(varidx >= 0 && varidx < nvars);
4196 assert(gubset->gubconss[gubconsGC2[j]]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4197
4198 fixedonesweight += weights[varidx];
4199 }
4200 assert(fixedonesweight >= 0);
4201
4202 /* initializes right hand side of lifted valid inequality */
4203 *liftrhs = alpha0;
4204
4205 /* sequentially up-lifts all variables in GFC1 GUBs */
4206 for( j = 0; j < ngubconsGFC1; j++ )
4207 {
4210
4211 /* GNC1 GUB: update unfinished table (remove current GUB, i.e., remove min weight of C1 vars in GUB) and
4212 * compute minweight table via updated unfinished table and aleady upto date finished table;
4213 */
4214 k = 0;
4216 {
4218 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4219 assert(ngubconsGNC1 > 0);
4220
4221 /* get number of C1 variables of current GNC1 GUB and put them into array of variables in GUB that
4222 * are considered for the lifting, i.e., not capacity exceeding
4223 */
4224 for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars
4225 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4226 liftgubvars[k] = gubset->gubconss[liftgubconsidx]->gubvars[k];
4227 assert(k >= 1);
4228
4229 /* update unfinished table by removing current GNC1 GUB, i.e, remove C1 variable with minimal weight
4230 * unfinished[w] = MAX{unfinished[w], unfinished[w+1] - weight}, "weight" is the minimal weight of current GUB
4231 */
4232 weight = weights[liftgubvars[0]];
4233
4236 for( w = ngubconsGNC1-1; w >= 1; w-- )
4237 {
4239 weightdiff2 = unfinished[w] - weight;
4240
4241 if( unfinished[w] < weightdiff1 )
4243 else
4244 break;
4245 }
4246 ngubconsGNC1--;
4247
4248 /* computes minweights table by combining unfished and fished tables */
4250 assert(minweights[0] == 0);
4251 }
4252 /* GF GUB: no update of unfinished table (and minweight table) required because GF GUBs have no C1 variables and
4253 * are therefore not in the unfinished table
4254 */
4255 else
4257
4258#ifndef NDEBUG
4259 nliftgubC1 = k;
4260#endif
4261 nliftgubvars = k;
4262 sumliftcoef = 0;
4263
4264 /* compute lifting coefficient of F and R variables in GNC1 and GF GUBs (C1 vars have already liftcoef 1) */
4265 for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4266 {
4267 if( gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_F
4268 || gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4269 {
4270 liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4271 weight = weights[liftvar];
4272 assert(weight > 0);
4273 assert(liftvar >= 0 && liftvar < nvars);
4274 assert(capacity - weight >= 0);
4275
4276 /* put variable into array of variables in GUB that are considered for the lifting,
4277 * i.e., not capacity exceeding
4278 */
4280 nliftgubvars++;
4281
4282 /* knapsack problem is infeasible:
4283 * sets z = 0
4284 */
4285 if( capacity - fixedonesweight - weight < 0 )
4286 {
4287 z = 0;
4288 }
4289 /* knapsack problem is feasible:
4290 * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
4291 * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
4292 */
4293 else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
4294 {
4295 z = *liftrhs;
4296 }
4297 /* knapsack problem is feasible:
4298 * binary search to find z = max {w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i}}
4299 */
4300 else
4301 {
4302 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
4303 left = 0;
4304 right = (*liftrhs) + 1;
4305 while( left < right - 1 )
4306 {
4307 middle = (left + right) / 2;
4308 assert(0 <= middle && middle < minweightslen);
4309 if( minweights[middle] <= capacity - fixedonesweight - weight )
4310 left = middle;
4311 else
4312 right = middle;
4313 }
4314 assert(left == right - 1);
4315 assert(0 <= left && left < minweightslen);
4316 assert(minweights[left] <= capacity - fixedonesweight - weight);
4317 assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
4318
4319 /* now z = left */
4320 z = left;
4321 assert(z <= *liftrhs);
4322 }
4323
4324 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4325 liftcoef = (*liftrhs) - z;
4327 assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4328
4329 /* updates activity of current valid inequality */
4330 (*cutact) += liftcoef * solvals[liftvar];
4331
4332 /* updates sum of all lifting coefficients in GUB */
4334 }
4335 else
4336 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4337 }
4338 /* at least one variable is in F or R (j = number of C1 variables in current GUB) */
4340
4341 /* activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0
4342 * and finished and minweight table can be updated easily as only C1 variables need to be considered;
4343 * not needed for GF GUBs
4344 */
4345 if( sumliftcoef == 0 )
4346 {
4348 {
4349 weight = weights[liftgubvars[0]];
4350 /* update finished table and minweights table by applying special case of
4351 * finished[w] = MIN{finished[w], finished[w-1] + weight}, "weight" is the minimal weight of current GUB
4352 * minweights[w] = MIN{minweights[w], minweights[w-1] + weight}, "weight" is the minimal weight of current GUB
4353 */
4354 for( w = minweightslen-1; w >= 1; w-- )
4355 {
4356 SCIP_Longint tmpval;
4357
4358 tmpval = safeAddMinweightsGUB(finished[w-1], weight);
4359 finished[w] = MIN(finished[w], tmpval);
4360
4363 }
4364 }
4365 else
4367
4368 continue;
4369 }
4370
4371 /* enlarges current minweights tables(finished, unfinished, minweights):
4372 * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4373 * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4374 * and sets minweights_i[w] = infinity for
4375 * 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
4376 */
4377 tmplen = minweightslen; /* will be updated in enlargeMinweights() */
4384
4385 /* update finished table and minweight table;
4386 * note that instead of computing minweight table from updated finished and updated unfinished table again
4387 * (for the lifting coefficient, we had to update unfinished table and compute minweight table), we here
4388 * only need to update the minweight table and the updated finished in the same way (i.e., computing for minweight
4389 * not needed because only finished table changed at this point and the change was "adding" one weight)
4390 *
4391 * update formular for minweight table is: minweight_i+1[w] =
4392 * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4393 * formular for finished table has the same pattern.
4394 */
4395 for( w = minweightslen-1; w >= 0; w-- )
4396 {
4397 SCIP_Longint minminweight;
4398 SCIP_Longint minfinished;
4399
4400 for( k = 0; k < nliftgubvars; k++ )
4401 {
4403 weight = weights[liftgubvars[k]];
4404
4405 if( w < liftcoef )
4406 {
4407 minfinished = MIN(finished[w], weight);
4408 minminweight = MIN(minweights[w], weight);
4409
4412 }
4413 else
4414 {
4415 SCIP_Longint tmpval;
4416
4417 assert(w >= liftcoef);
4418
4421
4424
4427 }
4428 }
4429 }
4430 assert(minweights[0] == 0);
4431 }
4432 assert(ngubconsGNC1 == 0);
4433
4434 /* note: now the unfinished table no longer exists, i.e., it is "0, MAX, MAX, ..." and minweight equals to finished;
4435 * therefore, only work with minweight table from here on
4436 */
4437
4438 /* sequentially down-lifts C2 variables contained in trivial GC2 GUBs */
4439 for( j = 0; j < ngubconsGC2; j++ )
4440 {
4442
4445 assert(gubset->gubconss[liftgubconsidx]->ngubvars == 1);
4446 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4447
4448 liftvar = gubset->gubconss[liftgubconsidx]->gubvars[0]; /* C2 GUBs contain only one variable */
4449 weight = weights[liftvar];
4450
4451 assert(liftvar >= 0 && liftvar < nvars);
4452 assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
4453 assert(weight > 0);
4454
4455 /* uses binary search to find
4456 * z = max { w : 0 <= w <= |C_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
4457 */
4458 left = 0;
4459 right = minweightslen;
4460 while( left < right - 1 )
4461 {
4462 middle = (left + right) / 2;
4463 assert(0 <= middle && middle < minweightslen);
4464 if( minweights[middle] <= capacity - fixedonesweight + weight )
4465 left = middle;
4466 else
4467 right = middle;
4468 }
4469 assert(left == right - 1);
4470 assert(0 <= left && left < minweightslen);
4471 assert(minweights[left] <= capacity - fixedonesweight + weight);
4472 assert(left == minweightslen - 1 || minweights[left + 1] > capacity - fixedonesweight + weight);
4473
4474 /* now z = left */
4475 z = left;
4476 assert(z >= *liftrhs);
4477
4478 /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
4479 liftcoef = z - (*liftrhs);
4481 assert(liftcoef >= 0);
4482
4483 /* updates sum of weights of variables fixed to one */
4484 fixedonesweight -= weight;
4485
4486 /* updates right-hand side of current valid inequality */
4487 (*liftrhs) += liftcoef;
4488 assert(*liftrhs >= alpha0);
4489
4490 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
4491 if( liftcoef == 0 )
4492 continue;
4493
4494 /* updates activity of current valid inequality */
4495 (*cutact) += liftcoef * solvals[liftvar];
4496
4497 /* enlarges current minweight table:
4498 * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4499 * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4500 * and sets minweights_i[w] = infinity for
4501 * 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
4502 */
4504
4505 /* updates minweight table: minweight_i+1[w] =
4506 * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
4507 * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
4508 */
4509 for( w = minweightslen - 1; w >= 0; w-- )
4510 {
4511 if( w < liftcoef )
4512 {
4513 min = MIN(minweights[w], weight);
4514 minweights[w] = min;
4515 }
4516 else
4517 {
4518 SCIP_Longint tmpval;
4519
4520 assert(w >= liftcoef);
4521
4523 min = MIN(minweights[w], tmpval);
4524 minweights[w] = min;
4525 }
4526 }
4527 }
4528 assert(fixedonesweight == 0);
4529 assert(*liftrhs >= alpha0);
4530
4531 /* sequentially up-lifts variables in GUB constraints in GR GUBs */
4532 for( j = 0; j < ngubconsGR; j++ )
4533 {
4535
4538
4539 sumliftcoef = 0;
4540 nliftgubvars = 0;
4541 for( k = 0; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4542 {
4543 if(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4544 {
4545 liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4546 weight = weights[liftvar];
4547 assert(weight > 0);
4548 assert(liftvar >= 0 && liftvar < nvars);
4549 assert(capacity - weight >= 0);
4550 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
4551
4552 /* put variable into array of variables in GUB that are considered for the lifting,
4553 * i.e., not capacity exceeding
4554 */
4556 nliftgubvars++;
4557
4558 /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
4559 * if minweights_i[liftrhs] <= a_0 - a_{j_i}
4560 */
4561 if( minweights[*liftrhs] <= capacity - weight )
4562 {
4563 z = *liftrhs;
4564 }
4565 /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
4566 */
4567 else
4568 {
4569 left = 0;
4570 right = (*liftrhs) + 1;
4571 while( left < right - 1 )
4572 {
4573 middle = (left + right) / 2;
4574 assert(0 <= middle && middle < minweightslen);
4575 if( minweights[middle] <= capacity - weight )
4576 left = middle;
4577 else
4578 right = middle;
4579 }
4580 assert(left == right - 1);
4581 assert(0 <= left && left < minweightslen);
4582 assert(minweights[left] <= capacity - weight);
4583 assert(left == minweightslen - 1 || minweights[left + 1] > capacity - weight);
4584
4585 /* now z = left */
4586 z = left;
4587 assert(z <= *liftrhs);
4588 }
4589 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4590 liftcoef = (*liftrhs) - z;
4592 assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4593
4594 /* updates activity of current valid inequality */
4595 (*cutact) += liftcoef * solvals[liftvar];
4596
4597 /* updates sum of all lifting coefficients in GUB */
4599 }
4600 else
4601 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4602 }
4603 assert(nliftgubvars >= 1); /* at least one variable is in R */
4604
4605 /* minweight table and activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0 */
4606 if( sumliftcoef == 0 )
4607 continue;
4608
4609 /* updates minweight table: minweight_i+1[w] =
4610 * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4611 */
4612 for( w = *liftrhs; w >= 0; w-- )
4613 {
4614 for( k = 0; k < nliftgubvars; k++ )
4615 {
4617 weight = weights[liftgubvars[k]];
4618
4619 if( w < liftcoef )
4620 {
4621 min = MIN(minweights[w], weight);
4622 minweights[w] = min;
4623 }
4624 else
4625 {
4626 SCIP_Longint tmpval;
4627
4628 assert(w >= liftcoef);
4629
4631 min = MIN(minweights[w], tmpval);
4632 minweights[w] = min;
4633 }
4634 }
4635 }
4636 assert(minweights[0] == 0);
4637 }
4638
4639 /* frees temporary memory */
4646
4647 return SCIP_OKAY;
4648}
4649
4650/** lifts given minimal cover inequality
4651 * \f[
4652 * \sum_{j \in C} x_j \leq |C| - 1
4653 * \f]
4654 * valid for
4655 * \f[
4656 * S^0 = \{ x \in {0,1}^{|C|} : \sum_{j \in C} a_j x_j \leq a_0 \}
4657 * \f]
4658 * to a valid inequality
4659 * \f[
4660 * \sum_{j \in C} x_j + \sum_{j \in N \setminus C} \alpha_j x_j \leq |C| - 1
4661 * \f]
4662 * for
4663 * \f[
4664 * S = \{ x \in {0,1}^{|N|} : \sum_{j \in N} a_j x_j \leq a_0 \};
4665 * \f]
4666 * uses superadditive up-lifting for the variables in \f$N \setminus C\f$.
4667 */
4668static
4670 SCIP* scip, /**< SCIP data structure */
4671 SCIP_VAR** vars, /**< variables in knapsack constraint */
4672 int nvars, /**< number of variables in knapsack constraint */
4673 int ntightened, /**< number of variables with tightened upper bound */
4674 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4675 SCIP_Longint capacity, /**< capacity of knapsack */
4676 SCIP_Real* solvals, /**< solution values of all problem variables */
4677 int* covervars, /**< cover variables */
4678 int* noncovervars, /**< noncover variables */
4679 int ncovervars, /**< number of cover variables */
4680 int nnoncovervars, /**< number of noncover variables */
4681 SCIP_Longint coverweight, /**< weight of cover */
4682 SCIP_Real* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
4683 SCIP_Real* cutact /**< pointer to store activity of lifted valid inequality */
4684 )
4685{
4686 SCIP_Longint* maxweightsums;
4687 SCIP_Longint* intervalends;
4688 SCIP_Longint* rhos;
4689 SCIP_Real* sortkeys;
4690 SCIP_Longint lambda;
4691 int j;
4692 int h;
4693
4694 assert(scip != NULL);
4695 assert(vars != NULL);
4696 assert(nvars >= 0);
4697 assert(weights != NULL);
4698 assert(capacity >= 0);
4699 assert(solvals != NULL);
4700 assert(covervars != NULL);
4702 assert(ncovervars > 0 && ncovervars <= nvars);
4703 assert(nnoncovervars >= 0 && nnoncovervars <= nvars - ntightened);
4704 assert(ncovervars + nnoncovervars == nvars - ntightened);
4705 assert(liftcoefs != NULL);
4706 assert(cutact != NULL);
4707
4708 /* allocates temporary memory */
4713
4714 /* initializes data structures */
4716 *cutact = 0.0;
4717
4718 /* sets lifting coefficient of variables in C, sorts variables in C such that a_1 >= a_2 >= ... >= a_|C|
4719 * and calculates activity of current valid inequality
4720 */
4721 for( j = 0; j < ncovervars; j++ )
4722 {
4723 assert(liftcoefs[covervars[j]] == 0.0);
4724 liftcoefs[covervars[j]] = 1.0;
4725 sortkeys[j] = (SCIP_Real) weights[covervars[j]];
4726 (*cutact) += solvals[covervars[j]];
4727 }
4729
4730 /* calculates weight excess of cover C */
4731 lambda = coverweight - capacity;
4732 assert(lambda > 0);
4733
4734 /* calculates A_h for h = 0,...,|C|, I_h for h = 1,...,|C| and rho_h for h = 1,...,|C| */
4735 maxweightsums[0] = 0;
4736 for( h = 1; h <= ncovervars; h++ )
4737 {
4738 maxweightsums[h] = maxweightsums[h-1] + weights[covervars[h-1]];
4739 intervalends[h-1] = maxweightsums[h] - lambda;
4740 rhos[h-1] = MAX(0, weights[covervars[h-1]] - weights[covervars[0]] + lambda);
4741 }
4742
4743 /* sorts variables in N\C such that a_{j_1} <= a_{j_2} <= ... <= a_{j_t} */
4744 for( j = 0; j < nnoncovervars; j++ )
4745 sortkeys[j] = (SCIP_Real) (weights[noncovervars[j]]);
4747
4748 /* calculates lifting coefficient for all variables in N\C */
4749 h = 0;
4750 for( j = 0; j < nnoncovervars; j++ )
4751 {
4752 int liftvar;
4753 SCIP_Longint weight;
4754 SCIP_Real liftcoef;
4755
4757 weight = weights[liftvar];
4758
4759 while( intervalends[h] < weight )
4760 h++;
4761
4762 if( h == 0 )
4763 liftcoef = h;
4764 else
4765 {
4766 if( weight <= intervalends[h-1] + rhos[h] )
4767 {
4768 SCIP_Real tmp1;
4769 SCIP_Real tmp2;
4770 tmp1 = (SCIP_Real) (intervalends[h-1] + rhos[h] - weight);
4771 tmp2 = (SCIP_Real) rhos[1];
4772 liftcoef = h - ( tmp1 / tmp2 );
4773 }
4774 else
4775 liftcoef = h;
4776 }
4777
4778 /* sets lifting coefficient */
4779 assert(liftcoefs[liftvar] == 0.0);
4781
4782 /* updates activity of current valid inequality */
4783 (*cutact) += liftcoef * solvals[liftvar];
4784 }
4785
4786 /* frees temporary memory */
4791
4792 return SCIP_OKAY;
4793}
4794
4795
4796/** separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information, if wanted, for
4797 * given knapsack problem
4798*/
4799static
4801 SCIP* scip, /**< SCIP data structure */
4802 SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
4803 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
4804 SCIP_VAR** vars, /**< variables in knapsack constraint */
4805 int nvars, /**< number of variables in knapsack constraint */
4806 int ntightened, /**< number of variables with tightened upper bound */
4807 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4808 SCIP_Longint capacity, /**< capacity of knapsack */
4809 SCIP_Real* solvals, /**< solution values of all problem variables */
4810 int* mincovervars, /**< mincover variables */
4811 int* nonmincovervars, /**< nonmincover variables */
4812 int nmincovervars, /**< number of mincover variables */
4813 int nnonmincovervars, /**< number of nonmincover variables */
4814 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
4815 SCIP_GUBSET* gubset, /**< GUB set data structure, NULL if no GUB information should be used */
4816 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
4817 int* ncuts /**< pointer to add up the number of found cuts */
4818 )
4819{
4820 int* varsC1;
4821 int* varsC2;
4822 int* varsF;
4823 int* varsR;
4824 int nvarsC1;
4825 int nvarsC2;
4826 int nvarsF;
4827 int nvarsR;
4828 SCIP_Real cutact;
4829 int* liftcoefs;
4830 int liftrhs;
4831
4832 assert( cutoff != NULL );
4833 *cutoff = FALSE;
4834
4835 /* allocates temporary memory */
4841
4842 /* 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
4843 * as follows
4844 * C_2 = { j in C : x*_j = 1 } and
4845 * C_1 = C\C_2
4846 */
4849 assert(nmincovervars > 0);
4850 assert(nvarsC1 >= 0); /* nvarsC1 > 0 does not always hold, because relaxed knapsack conss may already be violated */
4851
4852 /* changes partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one variable from C2 to C1 */
4854 {
4856 assert(nvarsC1 >= 1);
4857 }
4858 assert(nvarsC2 == 0 || nvarsC1 >= 1);
4859
4860 /* gets partition (F,R) of N\C, i.e. F & R = N\C and F cap R = emptyset; chooses partition as follows
4861 * R = { j in N\C : x*_j = 0 } and
4862 * F = (N\C)\F
4863 */
4866 assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4867
4868 /* lift cuts without GUB information */
4869 if( gubset == NULL )
4870 {
4871 /* sorts variables in F, C_2, R according to the second level lifting sequence that will be used in the sequential
4872 * lifting procedure
4873 */
4875
4876 /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4877 *
4878 * 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 }
4879 *
4880 * 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
4881 *
4882 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
4883 *
4884 * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in C_2 and sequential
4885 * up-lifting for the variables in R according to the second level lifting sequence
4886 */
4887 SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsC1, varsC2,
4889 }
4890 /* lift cuts with GUB information */
4891 else
4892 {
4893 int* gubconsGC1;
4894 int* gubconsGC2;
4895 int* gubconsGFC1;
4896 int* gubconsGR;
4897 int ngubconsGC1;
4898 int ngubconsGC2;
4899 int ngubconsGFC1;
4900 int ngubconsGR;
4901 int ngubconss;
4902 int nconstightened;
4903 int maxgubvarssize;
4904
4905 assert(nvars == gubset->nvars);
4906
4907 ngubconsGC1 = 0;
4908 ngubconsGC2 = 0;
4909 ngubconsGFC1 = 0;
4910 ngubconsGR = 0;
4911 ngubconss = gubset->ngubconss;
4912 nconstightened = 0;
4913 maxgubvarssize = 0;
4914
4915 /* allocates temporary memory */
4920
4921 /* categorizies GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of
4922 * the GUBs for the sequential GUB wise lifting procedure
4923 */
4927
4928 /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4929 *
4930 * 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,
4931 * sum_{j in Q_i} x_j <= 1, forall i in I }
4932 *
4933 * 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
4934 *
4935 * 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 },
4936 *
4937 * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
4938 * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
4939 * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
4940 */
4944
4945 /* frees temporary memory */
4950 }
4951
4952 /* checks, if lifting yielded a violated cut */
4953 if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
4954 {
4955 SCIP_ROW* row;
4956 char name[SCIP_MAXSTRLEN];
4957 int j;
4958
4959 /* creates LP row */
4960 assert( cons == NULL || sepa == NULL );
4961 if ( cons != NULL )
4962 {
4964 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
4965 cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
4966 cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
4967 }
4968 else if ( sepa != NULL )
4969 {
4971 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4972 }
4973 else
4974 {
4975 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcseq_%d", *ncuts);
4977 }
4978
4979 /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
4981 assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4982 for( j = 0; j < nvarsC1; j++ )
4983 {
4984 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC1[j]], 1.0) );
4985 }
4986 for( j = 0; j < nvarsC2; j++ )
4987 {
4988 if( liftcoefs[varsC2[j]] > 0 )
4989 {
4990 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC2[j]], (SCIP_Real)liftcoefs[varsC2[j]]) );
4991 }
4992 }
4993 for( j = 0; j < nvarsF; j++ )
4994 {
4995 if( liftcoefs[varsF[j]] > 0 )
4996 {
4997 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
4998 }
4999 }
5000 for( j = 0; j < nvarsR; j++ )
5001 {
5002 if( liftcoefs[varsR[j]] > 0 )
5003 {
5004 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
5005 }
5006 }
5008
5009 /* checks, if cut is violated enough */
5010 if( SCIPisCutEfficacious(scip, sol, row) )
5011 {
5012 if( cons != NULL )
5013 {
5015 }
5017 (*ncuts)++;
5018 }
5019 SCIP_CALL( SCIPreleaseRow(scip, &row) );
5020 }
5021
5022 /* frees temporary memory */
5028
5029 return SCIP_OKAY;
5030}
5031
5032/** separates lifted extended weight inequalities using sequential up- and down-lifting for given knapsack problem */
5033static
5035 SCIP* scip, /**< SCIP data structure */
5036 SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5037 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5038 SCIP_VAR** vars, /**< variables in knapsack constraint */
5039 int nvars, /**< number of variables in knapsack constraint */
5040 int ntightened, /**< number of variables with tightened upper bound */
5041 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5042 SCIP_Longint capacity, /**< capacity of knapsack */
5043 SCIP_Real* solvals, /**< solution values of all problem variables */
5044 int* feassetvars, /**< variables in feasible set */
5045 int* nonfeassetvars, /**< variables not in feasible set */
5046 int nfeassetvars, /**< number of variables in feasible set */
5047 int nnonfeassetvars, /**< number of variables not in feasible set */
5048 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5049 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5050 int* ncuts /**< pointer to add up the number of found cuts */
5051 )
5052{
5053 int* varsT1;
5054 int* varsT2;
5055 int* varsF;
5056 int* varsR;
5057 int* liftcoefs;
5058 SCIP_Real cutact;
5059 int nvarsT1;
5060 int nvarsT2;
5061 int nvarsF;
5062 int nvarsR;
5063 int liftrhs;
5064 int j;
5065
5066 assert( cutoff != NULL );
5067 *cutoff = FALSE;
5068
5069 /* allocates temporary memory */
5075
5076 /* 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
5077 * as follows
5078 * T_2 = { j in T : x*_j = 1 } and
5079 * T_1 = T\T_2
5080 */
5083
5084 /* changes partition (T_1,T_2) of feasible set T, if |T1| = 0, by moving one variable from T2 to T1 */
5085 if( nvarsT1 == 0 && nvarsT2 > 0)
5086 {
5088 assert(nvarsT1 == 1);
5089 }
5090 assert(nvarsT2 == 0 || nvarsT1 > 0);
5091
5092 /* gets partition (F,R) of N\T, i.e. F & R = N\T and F cap R = emptyset; chooses partition as follows
5093 * R = { j in N\T : x*_j = 0 } and
5094 * F = (N\T)\F
5095 */
5098 assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5099
5100 /* sorts variables in F, T_2, and R according to the second level lifting sequence that will be used in the sequential
5101 * lifting procedure (the variable removed last from the initial cover does not have to be lifted first, therefore it
5102 * is included in the sorting routine)
5103 */
5105
5106 /* lifts extended weight inequality sum_{j in T_1} x_j <= |T_1| valid for
5107 *
5108 * 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 }
5109 *
5110 * 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
5111 *
5112 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5113 *
5114 * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in T_2 and sequential
5115 * up-lifting for the variabels in R according to the second level lifting sequence
5116 */
5117 SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsT1, varsT2, varsF, varsR,
5119
5120 /* checks, if lifting yielded a violated cut */
5121 if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5122 {
5123 SCIP_ROW* row;
5124 char name[SCIP_MAXSTRLEN];
5125
5126 /* creates LP row */
5127 assert( cons == NULL || sepa == NULL );
5128 if( cons != NULL )
5129 {
5132 cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5133 cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5134 }
5135 else if ( sepa != NULL )
5136 {
5138 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5139 }
5140 else
5141 {
5142 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_ewseq_%d", *ncuts);
5144 }
5145
5146 /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5148 assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5149 for( j = 0; j < nvarsT1; j++ )
5150 {
5151 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT1[j]], 1.0) );
5152 }
5153 for( j = 0; j < nvarsT2; j++ )
5154 {
5155 if( liftcoefs[varsT2[j]] > 0 )
5156 {
5157 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT2[j]], (SCIP_Real)liftcoefs[varsT2[j]]) );
5158 }
5159 }
5160 for( j = 0; j < nvarsF; j++ )
5161 {
5162 if( liftcoefs[varsF[j]] > 0 )
5163 {
5164 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
5165 }
5166 }
5167 for( j = 0; j < nvarsR; j++ )
5168 {
5169 if( liftcoefs[varsR[j]] > 0 )
5170 {
5171 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
5172 }
5173 }
5175
5176 /* checks, if cut is violated enough */
5177 if( SCIPisCutEfficacious(scip, sol, row) )
5178 {
5179 if( cons != NULL )
5180 {
5182 }
5184 (*ncuts)++;
5185 }
5186 SCIP_CALL( SCIPreleaseRow(scip, &row) );
5187 }
5188
5189 /* frees temporary memory */
5195
5196 return SCIP_OKAY;
5197}
5198
5199/** separates lifted minimal cover inequalities using superadditive up-lifting for given knapsack problem */
5200static
5202 SCIP* scip, /**< SCIP data structure */
5203 SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5204 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5205 SCIP_VAR** vars, /**< variables in knapsack constraint */
5206 int nvars, /**< number of variables in knapsack constraint */
5207 int ntightened, /**< number of variables with tightened upper bound */
5208 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5209 SCIP_Longint capacity, /**< capacity of knapsack */
5210 SCIP_Real* solvals, /**< solution values of all problem variables */
5211 int* mincovervars, /**< mincover variables */
5212 int* nonmincovervars, /**< nonmincover variables */
5213 int nmincovervars, /**< number of mincover variables */
5214 int nnonmincovervars, /**< number of nonmincover variables */
5215 SCIP_Longint mincoverweight, /**< weight of minimal cover */
5216 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5217 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5218 int* ncuts /**< pointer to add up the number of found cuts */
5219 )
5220{
5221 SCIP_Real* realliftcoefs;
5222 SCIP_Real cutact;
5223 int liftrhs;
5224
5225 assert( cutoff != NULL );
5226 *cutoff = FALSE;
5227 cutact = 0.0;
5228
5229 /* allocates temporary memory */
5231
5232 /* lifts minimal cover inequality sum_{j in C} x_j <= |C| - 1 valid for
5233 *
5234 * S^0 = { x in {0,1}^|C| : sum_{j in C} a_j x_j <= a_0 }
5235 *
5236 * to a valid inequality sum_{j in C} x_j + sum_{j in N\C} alpha_j x_j <= |C| - 1 for
5237 *
5238 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5239 *
5240 * uses superadditive up-lifting for the variables in N\C.
5241 */
5242 SCIP_CALL( superadditiveUpLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, mincovervars,
5244 liftrhs = nmincovervars - 1;
5245
5246 /* checks, if lifting yielded a violated cut */
5247 if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5248 {
5249 SCIP_ROW* row;
5250 char name[SCIP_MAXSTRLEN];
5251 int j;
5252
5253 /* creates LP row */
5254 assert( cons == NULL || sepa == NULL );
5255 if ( cons != NULL )
5256 {
5259 cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5260 cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5261 }
5262 else if ( sepa != NULL )
5263 {
5265 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5266 }
5267 else
5268 {
5269 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcsup_%d", *ncuts);
5271 }
5272
5273 /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5275 assert(nmincovervars + nnonmincovervars == nvars - ntightened);
5276 for( j = 0; j < nmincovervars; j++ )
5277 {
5279 }
5280 for( j = 0; j < nnonmincovervars; j++ )
5281 {
5284 {
5286 }
5287 }
5289
5290 /* checks, if cut is violated enough */
5291 if( SCIPisCutEfficacious(scip, sol, row) )
5292 {
5293 if( cons != NULL )
5294 {
5296 }
5298 (*ncuts)++;
5299 }
5300 SCIP_CALL( SCIPreleaseRow(scip, &row) );
5301 }
5302
5303 /* frees temporary memory */
5305
5306 return SCIP_OKAY;
5307}
5308
5309/** converts given cover C to a minimal cover by removing variables in the reverse order in which the variables were chosen
5310 * 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
5311 * C and in the order of non-increasing (1 - x*_j), if the modified transformed separation problem was used to find C;
5312 * note that all variables with x*_j = 1 will be removed last
5313 */
5314static
5316 SCIP* scip, /**< SCIP data structure */
5317 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5318 SCIP_Longint capacity, /**< capacity of knapsack */
5319 SCIP_Real* solvals, /**< solution values of all problem variables */
5320 int* covervars, /**< pointer to store cover variables */
5321 int* noncovervars, /**< pointer to store noncover variables */
5322 int* ncovervars, /**< pointer to store number of cover variables */
5323 int* nnoncovervars, /**< pointer to store number of noncover variables */
5324 SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5325 SCIP_Bool modtransused /**< TRUE if mod trans sepa prob was used to find cover */
5326 )
5327{
5330 SCIP_Longint minweight;
5331 int nsortkeypairs;
5332 int minweightidx;
5333 int j;
5334 int k;
5335
5336 assert(scip != NULL);
5337 assert(covervars != NULL);
5340 assert(*ncovervars > 0);
5342 assert(*nnoncovervars >= 0);
5344 assert(*coverweight > 0);
5345 assert(*coverweight > capacity);
5346
5347 /* allocates temporary memory; we need two arrays for the keypairs in order to be able to free them in the correct
5348 * order */
5352
5353 /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5354 * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5355 * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5356 * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5357 */
5359 if( modtransused )
5360 {
5361 for( j = 0; j < *ncovervars; j++ )
5362 {
5363 SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5365
5366 sortkeypairs[j]->key1 = solvals[covervars[j]];
5367 sortkeypairs[j]->key2 = (SCIP_Real) weights[covervars[j]];
5368 }
5369 }
5370 else
5371 {
5372 for( j = 0; j < *ncovervars; j++ )
5373 {
5374 SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5376
5377 sortkeypairs[j]->key1 = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5378 sortkeypairs[j]->key2 = (SCIP_Real) (-weights[covervars[j]]);
5379 }
5380 }
5382
5383 /* gets j' with a_j' = min{ a_j : j in C } */
5384 minweightidx = 0;
5385 minweight = weights[covervars[minweightidx]];
5386 for( j = 1; j < *ncovervars; j++ )
5387 {
5388 if( weights[covervars[j]] <= minweight )
5389 {
5390 minweightidx = j;
5391 minweight = weights[covervars[minweightidx]];
5392 }
5393 }
5395 assert(minweight > 0 && minweight <= *coverweight);
5396
5397 j = 0;
5398 /* removes variables from C until the remaining variables form a minimal cover */
5399 while( j < *ncovervars && ((*coverweight) - minweight > capacity) )
5400 {
5401 assert(minweightidx >= j);
5403
5404 /* if sum_{i in C} a_i - a_j <= a_0, j cannot be removed from C */
5405 if( (*coverweight) - weights[covervars[j]] <= capacity )
5406 {
5407 ++j;
5408 continue;
5409 }
5410
5411 /* adds j to N\C */
5413 (*nnoncovervars)++;
5414
5415 /* removes j from C */
5416 (*coverweight) -= weights[covervars[j]];
5417 for( k = j; k < (*ncovervars) - 1; k++ )
5418 covervars[k] = covervars[k+1];
5419 (*ncovervars)--;
5420
5421 /* updates j' with a_j' = min{ a_j : j in C } */
5422 if( j == minweightidx )
5423 {
5424 minweightidx = 0;
5425 minweight = weights[covervars[minweightidx]];
5426 for( k = 1; k < *ncovervars; k++ )
5427 {
5428 if( weights[covervars[k]] <= minweight )
5429 {
5430 minweightidx = k;
5431 minweight = weights[covervars[minweightidx]];
5432 }
5433 }
5434 assert(minweight > 0 && minweight <= *coverweight);
5436 }
5437 else
5438 {
5440 minweightidx--;
5441 }
5442 /* j needs to stay the same */
5443 }
5444 assert((*coverweight) > capacity);
5445 assert((*coverweight) - minweight <= capacity);
5446
5447 /* frees temporary memory */
5448 for( j = nsortkeypairs-1; j >= 0; j-- )
5449 SCIPfreeBuffer(scip, &(sortkeypairs[j])); /*lint !e866 */
5452
5453 return SCIP_OKAY;
5454}
5455
5456/** converts given initial cover C_init to a feasible set by removing variables in the reverse order in which
5457 * they were chosen to be in C_init:
5458 * non-increasing (1 - x*_j)/a_j, if transformed separation problem was used to find C_init
5459 * non-increasing (1 - x*_j), if modified transformed separation problem was used to find C_init.
5460 * separates lifted extended weight inequalities using sequential up- and down-lifting for this feasible set
5461 * and all subsequent feasible sets.
5462 */
5463static
5465 SCIP* scip, /**< SCIP data structure */
5466 SCIP_CONS* cons, /**< constraint that originates the knapsack problem */
5467 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5468 SCIP_VAR** vars, /**< variables in knapsack constraint */
5469 int nvars, /**< number of variables in knapsack constraint */
5470 int ntightened, /**< number of variables with tightened upper bound */
5471 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5472 SCIP_Longint capacity, /**< capacity of knapsack */
5473 SCIP_Real* solvals, /**< solution values of all problem variables */
5474 int* covervars, /**< pointer to store cover variables */
5475 int* noncovervars, /**< pointer to store noncover variables */
5476 int* ncovervars, /**< pointer to store number of cover variables */
5477 int* nnoncovervars, /**< pointer to store number of noncover variables */
5478 SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5479 SCIP_Bool modtransused, /**< TRUE if mod trans sepa prob was used to find cover */
5480 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5481 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5482 int* ncuts /**< pointer to add up the number of found cuts */
5483 )
5484{
5485 SCIP_Real* sortkeys;
5486 int j;
5487 int k;
5488
5489 assert(scip != NULL);
5490 assert(covervars != NULL);
5493 assert(*ncovervars > 0);
5495 assert(*nnoncovervars >= 0);
5497 assert(*coverweight > 0);
5498 assert(*coverweight > capacity);
5499 assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5500 assert(cutoff != NULL);
5501
5502 *cutoff = FALSE;
5503
5504 /* allocates temporary memory */
5506
5507 /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5508 * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5509 * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5510 * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5511 */
5512 if( modtransused )
5513 {
5514 for( j = 0; j < *ncovervars; j++ )
5515 {
5516 sortkeys[j] = solvals[covervars[j]];
5518 }
5519 }
5520 else
5521 {
5522 for( j = 0; j < *ncovervars; j++ )
5523 {
5524 sortkeys[j] = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5526 }
5527 }
5529
5530 /* removes variables from C_init and separates lifted extended weight inequalities using sequential up- and down-lifting;
5531 * in addition to an extended weight inequality this gives cardinality inequalities */
5532 while( *ncovervars >= 2 )
5533 {
5534 /* adds first element of C_init to N\C_init */
5536 (*nnoncovervars)++;
5537
5538 /* removes first element from C_init */
5539 (*coverweight) -= weights[covervars[0]];
5540 for( k = 0; k < (*ncovervars) - 1; k++ )
5541 covervars[k] = covervars[k+1];
5542 (*ncovervars)--;
5543
5544 assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5545 if( (*coverweight) <= capacity )
5546 {
5547 SCIP_CALL( separateSequLiftedExtendedWeightInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals,
5549 }
5550
5551 /* stop if cover is too large */
5553 break;
5554 }
5555
5556 /* frees temporary memory */
5558
5559 return SCIP_OKAY;
5560}
5561
5562/** separates different classes of valid inequalities for the 0-1 knapsack problem */
5564 SCIP* scip, /**< SCIP data structure */
5565 SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5566 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5567 SCIP_VAR** vars, /**< variables in knapsack constraint */
5568 int nvars, /**< number of variables in knapsack constraint */
5569 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5570 SCIP_Longint capacity, /**< capacity of knapsack */
5571 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5572 SCIP_Bool usegubs, /**< should GUB information be used for separation? */
5573 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
5574 int* ncuts /**< pointer to add up the number of found cuts */
5575 )
5576{
5577 SCIP_Real* solvals;
5578 int* covervars;
5579 int* noncovervars;
5580 SCIP_Bool coverfound;
5581 SCIP_Bool fractional;
5582 SCIP_Bool modtransused;
5583 SCIP_Longint coverweight;
5584 int ncovervars;
5585 int nnoncovervars;
5586 int ntightened;
5587
5588 assert(scip != NULL);
5589 assert(capacity >= 0);
5590 assert(cutoff != NULL);
5591 assert(ncuts != NULL);
5592
5593 *cutoff = FALSE;
5594
5595 if( nvars == 0 )
5596 return SCIP_OKAY;
5597
5598 assert(vars != NULL);
5599 assert(nvars > 0);
5600 assert(weights != NULL);
5601
5602 /* increase age of constraint (age is reset to zero, if a cut was found) */
5603 if( cons != NULL )
5604 {
5605 SCIP_CALL( SCIPincConsAge(scip, cons) );
5606 }
5607
5608 /* allocates temporary memory */
5612
5613 /* gets solution values of all problem variables */
5614 SCIP_CALL( SCIPgetSolVals(scip, sol, nvars, vars, solvals) );
5615
5616#ifdef SCIP_DEBUG
5617 {
5618 int i;
5619
5620 SCIPdebugMsg(scip, "separate cuts for knapsack constraint originated by cons <%s>:\n",
5621 cons == NULL ? "-" : SCIPconsGetName(cons));
5622 for( i = 0; i < nvars; ++i )
5623 {
5624 SCIPdebugMsgPrint(scip, "%+" SCIP_LONGINT_FORMAT "<%s>(%g)", weights[i], SCIPvarGetName(vars[i]), solvals[i]);
5625 }
5626 SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT "\n", capacity);
5627 }
5628#endif
5629
5630 /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting) using GUB information
5631 */
5632 if( usegubs )
5633 {
5635
5636 SCIPdebugMsg(scip, "separate LMCI1-GUB cuts:\n");
5637
5638 /* initializes partion of knapsack variables into nonoverlapping GUB constraints */
5639 SCIP_CALL( GUBsetCreate(scip, &gubset, nvars, weights, capacity) );
5640
5641 /* constructs sophisticated partition of knapsack variables into nonoverlapping GUBs */
5643 assert(gubset->ngubconss <= nvars);
5644
5645 /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5646 * MODIFIED transformed separation problem and taking into account the following fixing:
5647 * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5648 * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5649 * if one exists
5650 */
5652 SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5654
5655 assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5656
5657 /* if x* is not fractional we stop the separation routine */
5658 if( !fractional )
5659 {
5660 SCIPdebugMsg(scip, " LMCI1-GUB terminated by no variable with fractional LP value.\n");
5661
5662 /* frees memory for GUB set data structure */
5664
5665 goto TERMINATE;
5666 }
5667
5668 /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5669 if( coverfound )
5670 {
5671 /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5672 * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5673 */
5674 SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5676
5677 /* only separate with GUB information if we have at least one nontrivial GUB (with more than one variable) */
5678 if( gubset->ngubconss < nvars )
5679 {
5680 /* separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information */
5681 SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5683 }
5684 else
5685 {
5686 /* separates lifted minimal cover inequalities using sequential up- and down-lifting, but do not use trivial
5687 * GUB information
5688 */
5689 SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5690 solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5691 }
5692 }
5693
5694 /* frees memory for GUB set data structure */
5696 }
5697 else
5698 {
5699 /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting)
5700 * (and LMCI2 (lifted minimal cover inequalities using superadditive up-lifting))
5701 */
5702
5703 /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5704 * MODIFIED transformed separation problem and taking into account the following fixing:
5705 * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5706 * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5707 * if one exists
5708 */
5709 SCIPdebugMsg(scip, "separate LMCI1 cuts:\n");
5711 SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5713 assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5714
5715 /* if x* is not fractional we stop the separation routine */
5716 if( !fractional )
5717 goto TERMINATE;
5718
5719 /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5720 if( coverfound )
5721 {
5722 /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5723 * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5724 */
5725 SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5727
5728 /* separates lifted minimal cover inequalities using sequential up- and down-lifting */
5729 SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5730 solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5731
5732 if( USESUPADDLIFT ) /*lint !e506 !e774*/
5733 {
5734 SCIPdebugMsg(scip, "separate LMCI2 cuts:\n");
5735 /* separates lifted minimal cover inequalities using superadditive up-lifting */
5736 SCIP_CALL( separateSupLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5738 }
5739 }
5740 }
5741
5742 /* LEWI (lifted extended weight inequalities using sequential up- and down-lifting) */
5743 if ( ! (*cutoff) )
5744 {
5745 /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5746 * transformed separation problem and taking into account the following fixing:
5747 * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5748 * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5749 * if one exists
5750 */
5751 SCIPdebugMsg(scip, "separate LEWI cuts:\n");
5753 SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5756 assert(!coverfound || ncovervars + nnoncovervars == nvars - ntightened);
5757
5758 /* if no cover was found we stop the separation routine */
5759 if( coverfound )
5760 {
5761 /* converts initial cover C_init to a feasible set by removing variables in the reverse order in which
5762 * they were chosen to be in C_init and separates lifted extended weight inequalities using sequential
5763 * up- and down-lifting for this feasible set and all subsequent feasible sets.
5764 */
5765 SCIP_CALL( getFeasibleSet(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals, covervars, noncovervars,
5767 }
5768 }
5769
5770 TERMINATE:
5771 /* frees temporary memory */
5774 SCIPfreeBufferArray(scip, &solvals);
5775
5776 return SCIP_OKAY;
5777}
5778
5779/* relaxes given general linear constraint into a knapsack constraint and separates lifted knapsack cover inequalities */
5781 SCIP* scip, /**< SCIP data structure */
5782 SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5783 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5784 int nknapvars, /**< number of variables in the continuous knapsack constraint */
5785 SCIP_VAR** knapvars, /**< variables in the continuous knapsack constraint */
5786 SCIP_Real* knapvals, /**< coefficients of the variables in the continuous knapsack constraint */
5787 SCIP_Real valscale, /**< -1.0 if lhs of row is used as rhs of c. k. constraint, +1.0 otherwise */
5788 SCIP_Real rhs, /**< right hand side of the continuous knapsack constraint */
5789 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
5790 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff was found */
5791 int* ncuts /**< pointer to add up the number of found cuts */
5792 )
5793{
5794 SCIP_VAR** binvars;
5795 SCIP_VAR** consvars;
5796 SCIP_Real* binvals;
5797 SCIP_Longint* consvals;
5798 SCIP_Longint minact;
5799 SCIP_Longint maxact;
5800 SCIP_Real intscalar;
5801 SCIP_Bool success;
5802 int nbinvars;
5803 int nconsvars;
5804 int i;
5805
5806 int* tmpindices;
5807 int tmp;
5808 SCIP_CONSHDLR* conshdlr;
5809 SCIP_CONSHDLRDATA* conshdlrdata;
5810 SCIP_Bool noknapsackconshdlr;
5811 SCIP_Bool usegubs;
5812
5813 assert(nknapvars > 0);
5814 assert(knapvars != NULL);
5815 assert(cutoff != NULL);
5816
5817 tmpindices = NULL;
5818
5819 SCIPdebugMsg(scip, "separate linear constraint <%s> relaxed to knapsack\n", cons != NULL ? SCIPconsGetName(cons) : "-");
5820 SCIPdebug( if( cons != NULL ) { SCIPdebugPrintCons(scip, cons, NULL); } );
5821
5822 binvars = SCIPgetVars(scip);
5823
5824 /* all variables which are of integral type can be potentially of binary type; this can be checked via the method SCIPvarIsBinary(var) */
5826
5827 *cutoff = FALSE;
5828
5829 if( nbinvars == 0 )
5830 return SCIP_OKAY;
5831
5832 /* set up data structures */
5835
5836 /* get conshdlrdata to use cleared memory */
5837 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
5838 if( conshdlr == NULL )
5839 {
5841 usegubs = DEFAULT_USEGUBS;
5842
5845 }
5846 else
5847 {
5849 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5850 assert(conshdlrdata != NULL);
5851 usegubs = conshdlrdata->usegubs;
5852
5854
5855 /* increase array size to avoid an endless loop in the next block; this might happen if continuous variables
5856 * change their types to SCIP_VARTYPE_BINARY during presolving
5857 */
5858 if( conshdlrdata->reals1size == 0 )
5859 {
5860 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, conshdlrdata->reals1size, 1) );
5861 conshdlrdata->reals1size = 1;
5862 conshdlrdata->reals1[0] = 0.0;
5863 }
5864
5865 assert(conshdlrdata->reals1size > 0);
5866
5867 /* next if condition should normally not be true, because it means that presolving has created more binary
5868 * variables than binary + integer variables existed at the constraint initialization method, but for example if you would
5869 * transform all integers into their binary representation then it maybe happens
5870 */
5871 if( conshdlrdata->reals1size < nbinvars )
5872 {
5873 int oldsize = conshdlrdata->reals1size;
5874
5875 conshdlrdata->reals1size = nbinvars;
5876 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, oldsize, conshdlrdata->reals1size) );
5877 BMSclearMemoryArray(&(conshdlrdata->reals1[oldsize]), conshdlrdata->reals1size - oldsize); /*lint !e866 */
5878 }
5879 binvals = conshdlrdata->reals1;
5880
5881 /* check for cleared array, all entries have to be zero */
5882#ifndef NDEBUG
5883 for( tmp = nbinvars - 1; tmp >= 0; --tmp )
5884 {
5885 assert(binvals[tmp] == 0);
5886 }
5887#endif
5888 }
5889
5890 tmp = 0;
5891
5892 /* relax continuous knapsack constraint:
5893 * 1. make all variables binary:
5894 * if x_j is continuous or integer variable substitute:
5895 * - a_j < 0: x_j = lb or x_j = b*z + d with variable lower bound b*z + d with binary variable z
5896 * - a_j > 0: x_j = ub or x_j = b*z + d with variable upper bound b*z + d with binary variable z
5897 * 2. convert coefficients of all variables to positive integers:
5898 * - scale all coefficients a_j to a~_j integral
5899 * - substitute x~_j = 1 - x_j if a~_j < 0
5900 */
5901
5902 /* replace integer and continuous variables with binary variables */
5903 for( i = 0; i < nknapvars; i++ )
5904 {
5905 SCIP_VAR* var;
5906
5907 var = knapvars[i];
5908
5910 {
5911 SCIP_Real solval;
5913
5914 solval = SCIPgetSolVal(scip, sol, var);
5915
5916 /* knapsack relaxation assumes solution values between 0.0 and 1.0 for binary variables */
5917 if( SCIPisFeasLT(scip, solval, 0.0 )
5918 || SCIPisFeasGT(scip, solval, 1.0) )
5919 {
5920 SCIPdebugMsg(scip, "Solution value %.15g <%s> outside domain [0.0, 1.0]\n",
5921 solval, SCIPvarGetName(var));
5922 goto TERMINATE;
5923 }
5924
5926 if( !noknapsackconshdlr )
5927 {
5929
5931 ++tmp;
5932 }
5933 SCIPdebugMsg(scip, " -> binary variable %+.15g<%s>(%.15g)\n", valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var));
5934 }
5935 else if( valscale * knapvals[i] > 0.0 )
5936 {
5937 SCIP_VAR** zvlb;
5938 SCIP_Real* bvlb;
5939 SCIP_Real* dvlb;
5940 SCIP_Real bestlbsol;
5941 int bestlbtype;
5942 int nvlb;
5943 int j;
5944
5945 /* a_j > 0: substitution with lb or vlb */
5950
5951 /* search for lb or vlb with maximal bound value */
5953 bestlbtype = -1;
5954 for( j = 0; j < nvlb; j++ )
5955 {
5956 /* use only numerical stable vlb with binary variable z */
5958 {
5959 SCIP_Real vlbsol;
5960
5961 if( (bvlb[j] >= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetLbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) ||
5963 {
5964 *cutoff = TRUE;
5965 SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] >= %g<%s>[%g,%g] + %g implies local cutoff\n",
5968 goto TERMINATE;
5969 }
5970
5972 vlbsol = bvlb[j] * SCIPgetSolVal(scip, sol, zvlb[j]) + dvlb[j];
5973 if( SCIPisGE(scip, vlbsol, bestlbsol) )
5974 {
5975 bestlbsol = vlbsol;
5976 bestlbtype = j;
5977 }
5978 }
5979 }
5980
5981 /* if no lb or vlb with binary variable was found, we have to abort */
5983 goto TERMINATE;
5984
5985 if( bestlbtype == -1 )
5986 {
5987 rhs -= valscale * knapvals[i] * bestlbsol;
5988 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with lower bound %.15g (rhs=%.15g)\n",
5990 }
5991 else
5992 {
5994 rhs -= valscale * knapvals[i] * dvlb[bestlbtype];
5996
5998 goto TERMINATE;
5999
6000 if( !noknapsackconshdlr )
6001 {
6003
6005 ++tmp;
6006 }
6007 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable lower bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
6011 }
6012 }
6013 else
6014 {
6015 SCIP_VAR** zvub;
6016 SCIP_Real* bvub;
6017 SCIP_Real* dvub;
6018 SCIP_Real bestubsol;
6019 int bestubtype;
6020 int nvub;
6021 int j;
6022
6023 assert(valscale * knapvals[i] < 0.0);
6024
6025 /* a_j < 0: substitution with ub or vub */
6030
6031 /* search for ub or vub with minimal bound value */
6033 bestubtype = -1;
6034 for( j = 0; j < nvub; j++ )
6035 {
6036 /* use only numerical stable vub with active binary variable z */
6038 {
6039 SCIP_Real vubsol;
6040
6041 if( (bvub[j] >= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetUbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) ||
6043 {
6044 *cutoff = TRUE;
6045 SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] <= %g<%s>[%g,%g] + %g implies local cutoff\n",
6048 goto TERMINATE;
6049 }
6050
6052 vubsol = bvub[j] * SCIPgetSolVal(scip, sol, zvub[j]) + dvub[j];
6053 if( SCIPisLE(scip, vubsol, bestubsol) )
6054 {
6055 bestubsol = vubsol;
6056 bestubtype = j;
6057 }
6058 }
6059 }
6060
6061 /* if no ub or vub with binary variable was found, we have to abort */
6063 goto TERMINATE;
6064
6065 if( bestubtype == -1 )
6066 {
6067 rhs -= valscale * knapvals[i] * bestubsol;
6068 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with upper bound %.15g (rhs=%.15g)\n",
6070 }
6071 else
6072 {
6074 rhs -= valscale * knapvals[i] * dvub[bestubtype];
6076
6078 goto TERMINATE;
6079
6080 if( !noknapsackconshdlr )
6081 {
6083
6085 ++tmp;
6086 }
6087 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable upper bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
6091 }
6092 }
6093 }
6094
6095 /* convert coefficients of all (now binary) variables to positive integers:
6096 * - make all coefficients integral
6097 * - make all coefficients positive (substitute negated variable)
6098 */
6099 nconsvars = 0;
6100
6101 /* calculate scalar which makes all coefficients integral in relative allowed difference in between
6102 * -SCIPepsilon(scip) and KNAPSACKRELAX_MAXDELTA
6103 */
6106 SCIPdebugMsg(scip, " -> intscalar = %.15g\n", intscalar);
6107
6108 /* if coefficients cannot be made integral, we have to use a scalar of 1.0 and only round fractional coefficients down */
6109 if( !success )
6110 intscalar = 1.0;
6111
6112 /* make all coefficients integral and positive:
6113 * - scale a~_j = a_j * intscalar
6114 * - substitute x~_j = 1 - x_j if a~_j < 0
6115 */
6116 rhs = rhs * intscalar;
6117
6118 SCIPdebugMsg(scip, " -> rhs = %.15g\n", rhs);
6119 minact = 0;
6120 maxact = 0;
6121 for( i = 0; i < nbinvars; i++ )
6122 {
6123 SCIP_VAR* var;
6124 SCIP_Longint val;
6125
6127 if( val == 0 )
6128 continue;
6129
6130 if( val > 0 )
6131 {
6132 var = binvars[i];
6133 SCIPdebugMsg(scip, " -> positive scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): not changed (rhs=%.15g)\n",
6134 val, SCIPvarGetName(var), binvals[i], rhs);
6135 }
6136 else
6137 {
6138 assert(val < 0);
6139
6140 SCIP_CALL( SCIPgetNegatedVar(scip, binvars[i], &var) );
6141 val = -val; /*lint !e2704*/
6142 rhs += val;
6143 SCIPdebugMsg(scip, " -> negative scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): substituted by (1 - <%s>) (rhs=%.15g)\n",
6144 -val, SCIPvarGetName(binvars[i]), binvals[i], SCIPvarGetName(var), rhs);
6145 }
6146
6147 if( SCIPvarGetLbLocal(var) > 0.5 )
6148 minact += val;
6149 if( SCIPvarGetUbLocal(var) > 0.5 )
6150 maxact += val;
6151 consvals[nconsvars] = val;
6152 consvars[nconsvars] = var;
6153 nconsvars++;
6154 }
6155
6156 if( nconsvars > 0 )
6157 {
6158 SCIP_Longint capacity;
6159
6160 assert(consvars != NULL);
6161 assert(consvals != NULL);
6162 capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
6163
6164#ifdef SCIP_DEBUG
6165 {
6166 SCIP_Real act;
6167
6168 SCIPdebugMsg(scip, " -> linear constraint <%s> relaxed to knapsack:", cons != NULL ? SCIPconsGetName(cons) : "-");
6169 act = 0.0;
6170 for( i = 0; i < nconsvars; ++i )
6171 {
6172 SCIPdebugMsgPrint(scip, " %+" SCIP_LONGINT_FORMAT "<%s>(%.15g)", consvals[i], SCIPvarGetName(consvars[i]),
6173 SCIPgetSolVal(scip, sol, consvars[i]));
6174 act += consvals[i] * SCIPgetSolVal(scip, sol, consvars[i]);
6175 }
6176 SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT " (%.15g) [act: %.15g, min: %" SCIP_LONGINT_FORMAT " max: %" SCIP_LONGINT_FORMAT "]\n",
6177 capacity, rhs, act, minact, maxact);
6178 }
6179#endif
6180
6181 if( minact > capacity )
6182 {
6183 SCIPdebugMsg(scip, "minactivity of knapsack relaxation implies local cutoff\n");
6184 *cutoff = TRUE;
6185 goto TERMINATE;
6186 }
6187
6188 if( maxact > capacity )
6189 {
6190 /* separate lifted cut from relaxed knapsack constraint */
6191 SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, sepa, consvars, nconsvars, consvals, capacity, sol, usegubs, cutoff, ncuts) );
6192 }
6193 }
6194
6195 TERMINATE:
6196 /* free data structures */
6198 {
6200 }
6201 else
6202 {
6203 /* clear binvals */
6204 for( --tmp; tmp >= 0; --tmp)
6205 {
6207 binvals[tmpindices[tmp]] = 0;
6208 }
6210 }
6212 SCIPfreeBufferArray(scip, &consvars);
6213
6214 return SCIP_OKAY;
6215}
6216
6217/** separates given knapsack constraint */
6218static
6220 SCIP* scip, /**< SCIP data structure */
6221 SCIP_CONS* cons, /**< knapsack constraint */
6222 SCIP_SOL* sol, /**< primal SCIP solution, NULL for current LP solution */
6223 SCIP_Bool sepacuts, /**< should knapsack cuts be separated? */
6224 SCIP_Bool usegubs, /**< should GUB information be used for separation? */
6225 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
6226 int* ncuts /**< pointer to add up the number of found cuts */
6227 )
6228{
6229 SCIP_CONSDATA* consdata;
6230 SCIP_Bool violated;
6231
6232 assert(ncuts != NULL);
6233 assert(cutoff != NULL);
6234 *cutoff = FALSE;
6235
6236 consdata = SCIPconsGetData(cons);
6237 assert(consdata != NULL);
6238
6239 SCIPdebugMsg(scip, "separating knapsack constraint <%s>\n", SCIPconsGetName(cons));
6240
6241 /* check knapsack constraint itself for feasibility */
6242 SCIP_CALL( checkCons(scip, cons, sol, (sol != NULL), FALSE, &violated) );
6243
6244 if( violated )
6245 {
6246 /* add knapsack constraint as LP row to the LP */
6248 (*ncuts)++;
6249 }
6250 else if( sepacuts )
6251 {
6252 SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, NULL, consdata->vars, consdata->nvars, consdata->weights,
6253 consdata->capacity, sol, usegubs, cutoff, ncuts) );
6254 }
6255
6256 return SCIP_OKAY;
6257}
6258
6259/** adds coefficient to constraint data */
6260static
6262 SCIP* scip, /**< SCIP data structure */
6263 SCIP_CONS* cons, /**< knapsack constraint */
6264 SCIP_VAR* var, /**< variable to add to knapsack */
6265 SCIP_Longint weight /**< weight of variable in knapsack */
6266 )
6267{
6268 SCIP_CONSDATA* consdata;
6269
6270 consdata = SCIPconsGetData(cons);
6271 assert(consdata != NULL);
6273 assert(weight > 0);
6274
6275 /* add the new coefficient to the LP row */
6276 if( consdata->row != NULL )
6277 {
6278 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, (SCIP_Real)weight) );
6279 }
6280
6281 /* check for fixed variable */
6282 if( SCIPvarGetLbGlobal(var) > 0.5 )
6283 {
6284 /* variable is fixed to one: reduce capacity */
6285 consdata->capacity -= weight;
6286 }
6287 else if( SCIPvarGetUbGlobal(var) > 0.5 )
6288 {
6289 SCIP_Bool negated;
6290
6291 /* get binary representative of variable */
6293
6294 /* insert coefficient */
6295 SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1, SCIPconsIsTransformed(cons)) );
6296 consdata->vars[consdata->nvars] = var;
6297 consdata->weights[consdata->nvars] = weight;
6298 consdata->nvars++;
6299
6300 /* capture variable */
6302
6303 /* install the rounding locks of variable */
6304 SCIP_CALL( lockRounding(scip, cons, var) );
6305
6306 /* catch events */
6307 if( SCIPconsIsTransformed(cons) )
6308 {
6309 SCIP_CONSHDLRDATA* conshdlrdata;
6310
6311 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6312 assert(conshdlrdata != NULL);
6313 SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[consdata->nvars-1], cons, weight) );
6315 conshdlrdata->eventhdlr, consdata->eventdata[consdata->nvars-1],
6316 &consdata->eventdata[consdata->nvars-1]->filterpos) );
6317
6318 if( !consdata->existmultaggr && SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR )
6319 consdata->existmultaggr = TRUE;
6320
6321 /* mark constraint to be propagated and presolved */
6323 consdata->presolvedtiming = 0;
6324 consdata->cliquesadded = FALSE; /* new coefficient might lead to larger cliques */
6325 }
6326
6327 /* update weight sums */
6328 updateWeightSums(consdata, var, weight);
6329
6330 consdata->sorted = FALSE;
6331 consdata->cliquepartitioned = FALSE;
6332 consdata->negcliquepartitioned = FALSE;
6333 consdata->merged = FALSE;
6334 }
6335
6336 return SCIP_OKAY;
6337}
6338
6339/** deletes coefficient at given position from constraint data */
6340static
6342 SCIP* scip, /**< SCIP data structure */
6343 SCIP_CONS* cons, /**< knapsack constraint */
6344 int pos /**< position of coefficient to delete */
6345 )
6346{
6347 SCIP_CONSDATA* consdata;
6348 SCIP_VAR* var;
6349
6350 consdata = SCIPconsGetData(cons);
6351 assert(consdata != NULL);
6352 assert(0 <= pos && pos < consdata->nvars);
6353
6354 var = consdata->vars[pos];
6355 assert(var != NULL);
6357
6358 /* delete the coefficient from the LP row */
6359 if( consdata->row != NULL )
6360 {
6361 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, -(SCIP_Real)consdata->weights[pos]) );
6362 }
6363
6364 /* remove the rounding locks of variable */
6365 SCIP_CALL( unlockRounding(scip, cons, var) );
6366
6367 /* drop events and mark constraint to be propagated and presolved */
6368 if( SCIPconsIsTransformed(cons) )
6369 {
6370 SCIP_CONSHDLRDATA* conshdlrdata;
6371
6372 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6373 assert(conshdlrdata != NULL);
6375 conshdlrdata->eventhdlr, consdata->eventdata[pos], consdata->eventdata[pos]->filterpos) );
6376 SCIP_CALL( eventdataFree(scip, &consdata->eventdata[pos]) );
6377
6379 consdata->presolvedtiming = 0;
6380 consdata->sorted = (consdata->sorted && pos == consdata->nvars - 1);
6381 }
6382
6383 /* decrease weight sums */
6384 updateWeightSums(consdata, var, -consdata->weights[pos]);
6385
6386 /* move the last variable to the free slot */
6387 consdata->vars[pos] = consdata->vars[consdata->nvars-1];
6388 consdata->weights[pos] = consdata->weights[consdata->nvars-1];
6389 if( consdata->eventdata != NULL )
6390 consdata->eventdata[pos] = consdata->eventdata[consdata->nvars-1];
6391
6392 /* release variable */
6394
6395 /* try to use old clique partitions */
6396 if( consdata->cliquepartitioned )
6397 {
6398 assert(consdata->cliquepartition != NULL);
6399 /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6400 * change the clique number */
6401 if( consdata->cliquepartition[consdata->nvars - 1] != consdata->nvars - 1 )
6402 {
6403 int oldcliqenum;
6404
6405 oldcliqenum = consdata->cliquepartition[pos];
6406 consdata->cliquepartition[pos] = consdata->cliquepartition[consdata->nvars-1];
6407
6408 /* the following if and else cases assure that we have increasing clique numbers */
6409 if( consdata->cliquepartition[pos] > pos )
6410 consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6411 else
6412 {
6413 int i;
6414 int cliquenumbefore;
6415
6416 /* if the old clique number was greater than the new one we have to check that before a bigger clique number
6417 * occurs the same as the old one is still in the cliquepartition */
6418 if( oldcliqenum > consdata->cliquepartition[pos] )
6419 {
6420 for( i = 0; i < consdata->nvars; ++i )
6421 if( oldcliqenum == consdata->cliquepartition[i] )
6422 break;
6423 else if( oldcliqenum < consdata->cliquepartition[i] )
6424 {
6425 consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6426 break;
6427 }
6428 /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6429 * the biggest index, so decrease the number of cliques
6430 */
6431 if( i == consdata->nvars )
6432 --(consdata->ncliques);
6433 }
6434 /* if the old clique number was smaller than the new one we have to check the front for an element with
6435 * clique number minus 1 */
6436 else if( oldcliqenum < consdata->cliquepartition[pos] )
6437 {
6438 cliquenumbefore = consdata->cliquepartition[pos] - 1;
6439 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6440
6441 if( i < cliquenumbefore )
6442 consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6443 }
6444 /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6445 else if( pos == consdata->nvars - 1)
6446 {
6447 cliquenumbefore = consdata->cliquepartition[pos];
6448 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6449
6450 if( i < cliquenumbefore )
6451 --(consdata->ncliques);
6452 }
6453 /* if the old clique number is equal to the new one the cliquepartition should be ok */
6454 }
6455 }
6456 else
6457 --(consdata->ncliques);
6458 }
6459
6460 if( consdata->negcliquepartitioned )
6461 {
6462 assert(consdata->negcliquepartition != NULL);
6463 /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6464 * change the clique number */
6465 if( consdata->negcliquepartition[consdata->nvars-1] != consdata->nvars - 1 )
6466 {
6467 int oldcliqenum;
6468
6469 oldcliqenum = consdata->negcliquepartition[pos];
6470 consdata->negcliquepartition[pos] = consdata->negcliquepartition[consdata->nvars-1];
6471
6472 /* the following if and else cases assure that we have increasing clique numbers */
6473 if( consdata->negcliquepartition[pos] > pos )
6474 consdata->negcliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6475 else
6476 {
6477 int i;
6478 int cliquenumbefore;
6479
6480 /* if the old clique number was greater than the new one we have to check that, before a bigger clique number
6481 * occurs, the same as the old one occurs */
6482 if( oldcliqenum > consdata->negcliquepartition[pos] )
6483 {
6484 for( i = 0; i < consdata->nvars; ++i )
6485 if( oldcliqenum == consdata->negcliquepartition[i] )
6486 break;
6487 else if( oldcliqenum < consdata->negcliquepartition[i] )
6488 {
6489 consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6490 break;
6491 }
6492 /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6493 * the biggest index, so decrease the number of negated cliques
6494 */
6495 if( i == consdata->nvars )
6496 --(consdata->nnegcliques);
6497 }
6498 /* if the old clique number was smaller than the new one we have to check the front for an element with
6499 * clique number minus 1 */
6500 else if( oldcliqenum < consdata->negcliquepartition[pos] )
6501 {
6502 cliquenumbefore = consdata->negcliquepartition[pos] - 1;
6503 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6504
6505 if( i < cliquenumbefore )
6506 consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6507 }
6508 /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6509 else if( pos == consdata->nvars - 1)
6510 {
6511 cliquenumbefore = consdata->negcliquepartition[pos];
6512 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6513
6514 if( i < cliquenumbefore )
6515 --(consdata->nnegcliques);
6516 }
6517 /* otherwise if the old clique number is equal to the new one the cliquepartition should be ok */
6518 }
6519 }
6520 else
6521 --(consdata->nnegcliques);
6522 }
6523
6524 --(consdata->nvars);
6525
6526 return SCIP_OKAY;
6527}
6528
6529/** removes all items with weight zero from knapsack constraint */
6530static
6532 SCIP* scip, /**< SCIP data structure */
6533 SCIP_CONS* cons /**< knapsack constraint */
6534 )
6535{
6536 SCIP_CONSDATA* consdata;
6537 int v;
6538
6539 consdata = SCIPconsGetData(cons);
6540 assert(consdata != NULL);
6541
6542 for( v = consdata->nvars-1; v >= 0; --v )
6543 {
6544 if( consdata->weights[v] == 0 )
6545 {
6546 SCIP_CALL( delCoefPos(scip, cons, v) );
6547 }
6548 }
6549
6550 return SCIP_OKAY;
6551}
6552
6553/* perform deletion of variables in all constraints of the constraint handler */
6554static
6556 SCIP* scip, /**< SCIP data structure */
6557 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6558 SCIP_CONS** conss, /**< array of constraints */
6559 int nconss /**< number of constraints */
6560 )
6561{
6562 SCIP_CONSDATA* consdata;
6563 int i;
6564 int v;
6565
6566 assert(scip != NULL);
6567 assert(conshdlr != NULL);
6568 assert(conss != NULL);
6569 assert(nconss >= 0);
6571
6572 /* iterate over all constraints */
6573 for( i = 0; i < nconss; i++ )
6574 {
6575 consdata = SCIPconsGetData(conss[i]);
6576
6577 /* constraint is marked, that some of its variables were deleted */
6578 if( consdata->varsdeleted )
6579 {
6580 /* iterate over all variables of the constraint and delete them from the constraint */
6581 for( v = consdata->nvars - 1; v >= 0; --v )
6582 {
6583 if( SCIPvarIsDeleted(consdata->vars[v]) )
6584 {
6585 SCIP_CALL( delCoefPos(scip, conss[i], v) );
6586 }
6587 }
6588 consdata->varsdeleted = FALSE;
6589 }
6590 }
6591
6592 return SCIP_OKAY;
6593}
6594
6595/** replaces multiple occurrences of a variable or its negation by a single coefficient */
6596static
6598 SCIP* scip, /**< SCIP data structure */
6599 SCIP_CONS* cons, /**< knapsack constraint */
6600 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
6601 )
6602{
6603 SCIP_CONSDATA* consdata;
6604 int v;
6605 int prev;
6606
6607 assert(scip != NULL);
6608 assert(cons != NULL);
6609 assert(cutoff != NULL);
6610
6611 consdata = SCIPconsGetData(cons);
6612 assert(consdata != NULL);
6613
6614 *cutoff = FALSE;
6615
6616 if( consdata->merged )
6617 return SCIP_OKAY;
6618
6619 if( consdata->nvars <= 1 )
6620 {
6621 consdata->merged = TRUE;
6622 return SCIP_OKAY;
6623 }
6624
6625 assert(consdata->vars != NULL || consdata->nvars == 0);
6626
6627 /* sorting array after indices of variables, that's only for faster merging */
6628 SCIPsortPtrPtrLongIntInt((void**)consdata->vars, (void**)consdata->eventdata, consdata->weights,
6629 consdata->cliquepartition, consdata->negcliquepartition, SCIPvarCompActiveAndNegated, consdata->nvars);
6630
6631 /* knapsack-sorting (decreasing weights) now lost */
6632 consdata->sorted = FALSE;
6633
6634 v = consdata->nvars - 1;
6635 prev = v - 1;
6636 /* loop backwards through the items: deletion only affects rear items */
6637 while( prev >= 0 )
6638 {
6639 SCIP_VAR* var1;
6640 SCIP_VAR* var2;
6641 SCIP_Bool negated1;
6642 SCIP_Bool negated2;
6643
6644 negated1 = FALSE;
6645 negated2 = FALSE;
6646
6647 var1 = consdata->vars[v];
6651 {
6653 negated1 = TRUE;
6654 }
6655 assert(var1 != NULL);
6656
6657 var2 = consdata->vars[prev];
6661 {
6663 negated2 = TRUE;
6664 }
6665 assert(var2 != NULL);
6666
6667 if( var1 == var2 )
6668 {
6669 /* both variables are either active or negated */
6670 if( negated1 == negated2 )
6671 {
6672 /* variables var1 and var2 are equal: add weight of var1 to var2, and delete var1 */
6673 consdataChgWeight(consdata, prev, consdata->weights[v] + consdata->weights[prev]);
6674 SCIP_CALL( delCoefPos(scip, cons, v) );
6675 }
6676 /* variables var1 and var2 are opposite: subtract smaller weight from larger weight, reduce capacity,
6677 * and delete item of smaller weight
6678 */
6679 else if( consdata->weights[v] == consdata->weights[prev] )
6680 {
6681 /* both variables eliminate themselves: w*x + w*(1-x) == w */
6682 consdata->capacity -= consdata->weights[v];
6683 SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6684 SCIP_CALL( delCoefPos(scip, cons, prev) );
6685
6686 --prev;
6687 }
6688 else if( consdata->weights[v] < consdata->weights[prev] )
6689 {
6690 consdata->capacity -= consdata->weights[v];
6691 consdataChgWeight(consdata, prev, consdata->weights[prev] - consdata->weights[v]);
6692 assert(consdata->weights[prev] > 0);
6693 SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6694 }
6695 else
6696 {
6697 consdata->capacity -= consdata->weights[prev];
6698 consdataChgWeight(consdata, v, consdata->weights[v] - consdata->weights[prev]);
6699 assert(consdata->weights[v] > 0);
6700 SCIP_CALL( delCoefPos(scip, cons, prev) ); /* attention: normally we lose our order */
6701 /* restore order iff necessary */
6702 if( consdata->nvars != v ) /* otherwise the order still stands */
6703 {
6704 assert(prev == 0 || ((prev > 0) && (SCIPvarIsActive(consdata->vars[prev - 1]) || SCIPvarGetStatus(consdata->vars[prev - 1]) == SCIP_VARSTATUS_NEGATED)) );
6705 /* either that was the last pair or both, the negated and "normal" variable in front doesn't match var1, so the order is irrelevant */
6706 if( prev == 0 || (var1 != consdata->vars[prev - 1] && var1 != SCIPvarGetNegatedVar(consdata->vars[prev - 1])) )
6707 --prev;
6708 else /* we need to let v at the same position*/
6709 {
6710 consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6711 /* don't decrease v, the same variable may exist up front */
6712 --prev;
6713 continue;
6714 }
6715 }
6716 }
6717 consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6718 }
6719 v = prev;
6720 --prev;
6721 }
6722
6723 consdata->merged = TRUE;
6724
6725 /* check infeasibility */
6726 if( consdata->onesweightsum > consdata->capacity )
6727 {
6728 SCIPdebugMsg(scip, "merge multiples detected cutoff.\n");
6729 *cutoff = TRUE;
6730 return SCIP_OKAY;
6731 }
6732
6733 return SCIP_OKAY;
6734}
6735
6736/** in case the knapsack constraint is independent of every else, solve the knapsack problem (exactly) and apply the
6737 * fixings (dual reductions)
6738 */
6739static
6741 SCIP* scip, /**< SCIP data structure */
6742 SCIP_CONS* cons, /**< knapsack constraint */
6743 int* nfixedvars, /**< pointer to count number of fixings */
6744 int* ndelconss, /**< pointer to count number of deleted constraints */
6745 SCIP_Bool* deleted /**< pointer to store if the constraint is deleted */
6746 )
6747{
6748 SCIP_CONSDATA* consdata;
6749 SCIP_VAR** vars;
6750 SCIP_Real* profits;
6751 int* solitems;
6752 int* nonsolitems;
6753 int* items;
6754 SCIP_Real solval;
6755 SCIP_Bool infeasible;
6756 SCIP_Bool tightened;
6757 SCIP_Bool applicable;
6758 int nsolitems;
6759 int nnonsolitems;
6760 int nvars;
6761 int v;
6762
6764
6765 /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
6766 * use the locks to decide for a dual reduction using this constraint; for example after a restart the cuts which are
6767 * added to the problems have the check flag set to FALSE
6768 */
6769 if( !SCIPconsIsChecked(cons) )
6770 return SCIP_OKAY;
6771
6772 consdata = SCIPconsGetData(cons);
6773 assert(consdata != NULL);
6774
6775 nvars = consdata->nvars;
6776 vars = consdata->vars;
6777
6782
6783 applicable = TRUE;
6784
6785 /* check if we can apply the dual reduction; this can be done if the knapsack has the only locks on this constraint;
6786 * collect object values which are the profits of the knapsack problem
6787 */
6788 for( v = 0; v < nvars; ++v )
6789 {
6790 SCIP_VAR* var;
6791 SCIP_Bool negated;
6792
6793 var = vars[v];
6794 assert(var != NULL);
6795
6796 /* the variable should not be (globally) fixed */
6798
6801 {
6802 applicable = FALSE;
6803 break;
6804 }
6805
6806 negated = FALSE;
6807
6808 /* get the active variable */
6811
6812 if( negated )
6814 else
6815 profits[v] = -SCIPvarGetObj(var);
6816
6817 SCIPdebugMsg(scip, "variable <%s> -> item size %" SCIP_LONGINT_FORMAT ", profit <%g>\n",
6818 SCIPvarGetName(vars[v]), consdata->weights[v], profits[v]);
6819 items[v] = v;
6820 }
6821
6822 if( applicable )
6823 {
6824 SCIP_Bool success;
6825
6826 SCIPdebugMsg(scip, "the knapsack constraint <%s> is independent to rest of the problem\n", SCIPconsGetName(cons));
6828
6829 /* solve knapsack problem exactly */
6830 SCIP_CALL( SCIPsolveKnapsackExactly(scip, consdata->nvars, consdata->weights, profits, consdata->capacity,
6832
6833 if( success )
6834 {
6835 SCIP_VAR* var;
6836
6837 /* apply solution of the knapsack as dual reductions */
6838 for( v = 0; v < nsolitems; ++v )
6839 {
6840 var = vars[solitems[v]];
6841 assert(var != NULL);
6842
6843 SCIPdebugMsg(scip, "variable <%s> only locked up in knapsack constraints: dual presolve <%s>[%.15g,%.15g] >= 1.0\n",
6845 SCIP_CALL( SCIPtightenVarLb(scip, var, 1.0, TRUE, &infeasible, &tightened) );
6846 assert(!infeasible);
6847 assert(tightened);
6848 (*nfixedvars)++;
6849 }
6850
6851 for( v = 0; v < nnonsolitems; ++v )
6852 {
6853 var = vars[nonsolitems[v]];
6854 assert(var != NULL);
6855
6856 SCIPdebugMsg(scip, "variable <%s> has no down locks: dual presolve <%s>[%.15g,%.15g] <= 0.0\n",
6858 SCIP_CALL( SCIPtightenVarUb(scip, var, 0.0, TRUE, &infeasible, &tightened) );
6859 assert(!infeasible);
6860 assert(tightened);
6861 (*nfixedvars)++;
6862 }
6863
6864 SCIP_CALL( SCIPdelCons(scip, cons) );
6865 (*ndelconss)++;
6866 (*deleted) = TRUE;
6867 }
6868 }
6869
6874
6875 return SCIP_OKAY;
6876}
6877
6878/** check if the knapsack constraint is parallel to objective function; if so update the cutoff bound and avoid that the
6879 * constraint enters the LP by setting the initial and separated flag to FALSE
6880 */
6881static
6883 SCIP* scip, /**< SCIP data structure */
6884 SCIP_CONS* cons, /**< knapsack constraint */
6885 SCIP_CONSHDLRDATA* conshdlrdata /**< knapsack constraint handler data */
6886 )
6887{
6888 SCIP_CONSDATA* consdata;
6889 SCIP_VAR** vars;
6890 SCIP_VAR* var;
6891 SCIP_Real offset;
6892 SCIP_Real scale;
6893 SCIP_Real objval;
6894 SCIP_Bool applicable;
6895 SCIP_Bool negated;
6896 int nobjvars;
6897 int nvars;
6898 int v;
6899
6900 assert(scip != NULL);
6901 assert(cons != NULL);
6902 assert(conshdlrdata != NULL);
6903
6904 consdata = SCIPconsGetData(cons);
6905 assert(consdata != NULL);
6906
6907 nvars = consdata->nvars;
6908 nobjvars = SCIPgetNObjVars(scip);
6909
6910 /* check if the knapsack constraints has the same number of variables as the objective function and if the initial
6911 * and/or separated flag is set to FALSE
6912 */
6913 if( nvars != nobjvars || (!SCIPconsIsInitial(cons) && !SCIPconsIsSeparated(cons)) )
6914 return SCIP_OKAY;
6915
6916 /* There are no variables in the ojective function and in the constraint. Thus, the constraint is redundant. Since we
6917 * have a pure feasibility problem, we do not want to set a cutoff or lower bound.
6918 */
6919 if( nobjvars == 0 )
6920 return SCIP_OKAY;
6921
6922 vars = consdata->vars;
6923 assert(vars != NULL);
6924
6925 applicable = TRUE;
6926 offset = 0.0;
6927 scale = 1.0;
6928
6929 for( v = 0; v < nvars && applicable; ++v )
6930 {
6931 negated = FALSE;
6932 var = vars[v];
6933 assert(var != NULL);
6934
6935 if( SCIPvarIsNegated(var) )
6936 {
6937 negated = TRUE;
6939 assert(var != NULL);
6940 }
6941
6943
6944 /* if a variable has a zero objective coefficient the knapsack constraint is not parallel to objective function */
6945 if( SCIPisZero(scip, objval) )
6946 applicable = FALSE;
6947 else
6948 {
6949 SCIP_Real weight;
6950
6951 weight = (SCIP_Real)consdata->weights[v];
6952
6953 if( negated )
6954 {
6955 if( v == 0 )
6956 {
6957 /* the first variable defines the scale */
6958 scale = weight / -objval;
6959
6960 offset += weight;
6961 }
6962 else if( SCIPisEQ(scip, -objval * scale, weight) )
6963 offset += weight;
6964 else
6965 applicable = FALSE;
6966 }
6967 else if( v == 0 )
6968 {
6969 /* the first variable define the scale */
6970 scale = weight / objval;
6971 }
6972 else if( !SCIPisEQ(scip, objval * scale, weight) )
6973 applicable = FALSE;
6974 }
6975 }
6976
6977 if( applicable )
6978 {
6979 if( SCIPisPositive(scip, scale) && conshdlrdata->detectcutoffbound )
6980 {
6981 SCIP_Real cutoffbound;
6982
6983 /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
6986
6987 cutoffbound = (consdata->capacity - offset) / scale;
6988
6989 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
6990 SCIPconsGetName(cons), cutoffbound);
6991
6992 /* increase the cutoff bound value by an epsilon to ensue that solution with the value of the cutoff bound are
6993 * still excepted
6994 */
6995 cutoffbound += SCIPcutoffbounddelta(scip);
6996
6997 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
6998 SCIPconsGetName(cons), cutoffbound);
6999
7000 if( cutoffbound < SCIPgetCutoffbound(scip) )
7001 {
7002 SCIPdebugMsg(scip, "update cutoff bound <%g>\n", cutoffbound);
7003
7004 SCIP_CALL( SCIPupdateCutoffbound(scip, cutoffbound) );
7005 }
7006 else
7007 {
7008 /* in case the cutoff bound is worse then currently known one we avoid additionaly enforcement and
7009 * propagation
7010 */
7013 }
7014 }
7015 else if( SCIPisNegative(scip, scale) && conshdlrdata->detectlowerbound )
7016 {
7017 SCIP_Real lowerbound;
7018
7019 /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
7022
7023 lowerbound = (consdata->capacity - offset) / scale;
7024
7025 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a lower bound <%g>\n",
7026 SCIPconsGetName(cons), lowerbound);
7027
7029 }
7030 }
7031
7032 return SCIP_OKAY;
7033}
7034
7035/** sort the variables and weights w.r.t. the clique partition; thereby ensure the current order of the variables when a
7036 * weight of one variable is greater or equal another weight and both variables are in the same cliques */
7037static
7039 SCIP* scip, /**< SCIP data structure */
7040 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
7041 SCIP_VAR** vars, /**< array for sorted variables */
7042 SCIP_Longint* weights, /**< array for sorted weights */
7043 int* cliquestartposs, /**< starting position array for each clique */
7044 SCIP_Bool usenegatedclique /**< should negated or normal clique partition be used */
7045 )
7046{
7047 SCIP_VAR** origvars;
7048 int norigvars;
7049 SCIP_Longint* origweights;
7050 int* cliquepartition;
7051 int ncliques;
7052
7054 SCIP_Longint** weightpointers;
7055 int* cliquecount;
7056
7057 int nextpos;
7058 int c;
7059 int v;
7060
7061 assert(scip != NULL);
7062 assert(consdata != NULL);
7063 assert(vars != NULL);
7064 assert(weights != NULL);
7066
7067 origweights = consdata->weights;
7068 origvars = consdata->vars;
7069 norigvars = consdata->nvars;
7070
7071 assert(origvars != NULL || norigvars == 0);
7072 assert(origweights != NULL || norigvars == 0);
7073
7074 if( norigvars == 0 )
7075 return SCIP_OKAY;
7076
7077 if( usenegatedclique )
7078 {
7079 assert(consdata->negcliquepartitioned);
7080
7081 cliquepartition = consdata->negcliquepartition;
7082 ncliques = consdata->nnegcliques;
7083 }
7084 else
7085 {
7086 assert(consdata->cliquepartitioned);
7087
7088 cliquepartition = consdata->cliquepartition;
7089 ncliques = consdata->ncliques;
7090 }
7091
7092 assert(cliquepartition != NULL);
7093 assert(ncliques > 0);
7094
7095 /* we first count all clique items and alloc temporary memory for a bucket sort */
7098
7099 /* first we count for each clique the number of elements */
7100 for( v = norigvars - 1; v >= 0; --v )
7101 {
7102 assert(0 <= cliquepartition[v] && cliquepartition[v] < ncliques);
7103 ++(cliquecount[cliquepartition[v]]);
7104 }
7105
7106 /*@todo: maybe it is better to put largest cliques up front */
7107
7108#ifndef NDEBUG
7111#endif
7114
7115 nextpos = 0;
7116 /* now we initialize all start pointers for each clique, so they will be ordered */
7117 for( c = 0; c < ncliques; ++c )
7118 {
7119 /* to reach the goal that all variables of each clique will be standing next to each other we will initialize the
7120 * starting pointers for each clique by adding the number of each clique to the last clique starting pointer
7121 * e.g. clique1 has 4 elements and clique2 has 3 elements the the starting pointer for clique1 will be the pointer
7122 * to vars[0], the starting pointer to clique2 will be the pointer to vars[4] and to clique3 it will be
7123 * vars[7]
7124 *
7125 */
7126 varpointers[c] = (SCIP_VAR**) (vars + nextpos);
7127 cliquestartposs[c] = nextpos;
7128 weightpointers[c] = (SCIP_Longint*) (weights + nextpos);
7129 assert(cliquecount[c] > 0);
7130 nextpos += cliquecount[c];
7131 assert(nextpos > 0);
7132 }
7133 assert(nextpos == norigvars);
7134 cliquestartposs[c] = nextpos;
7135
7136 /* now we copy all variable and weights to the right order */
7137 for( v = 0; v < norigvars; ++v )
7138 {
7139 *(varpointers[cliquepartition[v]]) = origvars[v]; /*lint !e613*/
7140 ++(varpointers[cliquepartition[v]]);
7141 *(weightpointers[cliquepartition[v]]) = origweights[v]; /*lint !e613*/
7142 ++(weightpointers[cliquepartition[v]]);
7143 }
7144#ifndef NDEBUG
7145 for( v = 0; v < norigvars; ++v )
7146 {
7147 assert(vars[v] != NULL);
7148 assert(weights[v] > 0);
7149 }
7150#endif
7151
7152 /* free temporary memory */
7156
7157 return SCIP_OKAY;
7158}
7159
7160/** deletes all fixed variables from knapsack constraint, and replaces variables with binary representatives */
7161static
7163 SCIP* scip, /**< SCIP data structure */
7164 SCIP_CONS* cons, /**< knapsack constraint */
7165 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off, or NULL if this
7166 * information is not needed; in this case, we apply all fixings
7167 * instead of stopping after the first infeasible one */
7168 )
7169{
7170 SCIP_CONSDATA* consdata;
7171 int v;
7172
7173 assert(scip != NULL);
7174 assert(cons != NULL);
7175
7176 consdata = SCIPconsGetData(cons);
7177 assert(consdata != NULL);
7178 assert(consdata->nvars == 0 || consdata->vars != NULL);
7179
7180 if( cutoff != NULL )
7181 *cutoff = FALSE;
7182
7183 SCIPdebugMsg(scip, "apply fixings:\n");
7185
7186 /* check infeasibility */
7187 if ( consdata->onesweightsum > consdata->capacity )
7188 {
7189 SCIPdebugMsg(scip, "apply fixings detected cutoff.\n");
7190
7191 if( cutoff != NULL )
7192 *cutoff = TRUE;
7193
7194 return SCIP_OKAY;
7195 }
7196
7197 /* all multi-aggregations should be resolved */
7198 consdata->existmultaggr = FALSE;
7199
7200 v = 0;
7201 while( v < consdata->nvars )
7202 {
7203 SCIP_VAR* var;
7204
7205 var = consdata->vars[v];
7207
7208 if( SCIPvarGetLbGlobal(var) > 0.5 )
7209 {
7211 consdata->capacity -= consdata->weights[v];
7212 SCIP_CALL( delCoefPos(scip, cons, v) );
7213 consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
7214 }
7215 else if( SCIPvarGetUbGlobal(var) < 0.5 )
7216 {
7218 SCIP_CALL( delCoefPos(scip, cons, v) );
7219 }
7220 else
7221 {
7225 SCIP_Longint weight;
7226 SCIP_Bool negated;
7227
7228 weight = consdata->weights[v];
7229
7230 /* get binary representative of variable */
7232 assert(repvar != NULL);
7233
7234 /* check for multi-aggregation */
7236 {
7238 assert(workvar != NULL);
7239 negated = TRUE;
7240 }
7241 else
7242 {
7243 workvar = repvar;
7244 negated = FALSE;
7245 }
7246
7247 /* @todo maybe resolve the problem that the eliminating of the multi-aggregation leads to a non-knapsack
7248 * constraint (converting into a linear constraint), for example the multi-aggregation consist of a non-binary
7249 * variable or due to resolving now their are non-integral coefficients or a non-integral capacity
7250 *
7251 * If repvar is not negated so workvar = repvar, otherwise workvar = 1 - repvar. This means,
7252 * weight * workvar = weight * (a_1*y_1 + ... + a_n*y_n + c)
7253 *
7254 * The explanation for the following block:
7255 * 1a) If repvar is a multi-aggregated variable weight * repvar should be replaced by
7256 * weight * (a_1*y_1 + ... + a_n*y_n + c).
7257 * 1b) If repvar is a negated variable of a multi-aggregated variable weight * repvar should be replaced by
7258 * weight - weight * (a_1*y_1 + ... + a_n*y_n + c), for better further use here we switch the sign of weight
7259 * so now we have the replacement -weight + weight * (a_1*y_1 + ... + a_n*y_n + c).
7260 * 2) For all replacement variable we check:
7261 * 2a) weight * a_i < 0 than we add -weight * a_i * y_i_neg to the constraint and adjust the capacity through
7262 * capacity -= weight * a_i caused by the negation of y_i.
7263 * 2b) weight * a_i >= 0 than we add weight * a_i * y_i to the constraint.
7264 * 3a) If repvar was not negated we need to subtract weight * c from capacity.
7265 * 3b) If repvar was negated we need to subtract weight * (c - 1) from capacity(note we switched the sign of
7266 * weight in this case.
7267 */
7269 {
7271 SCIP_Real* aggrscalars;
7272 SCIP_Real aggrconst;
7273 int naggrvars;
7274 int i;
7275
7277 naggrvars = SCIPvarGetMultaggrNVars(workvar);
7281 assert((aggrvars != NULL && aggrscalars != NULL) || naggrvars == 0);
7282
7283 if( !SCIPisIntegral(scip, weight * aggrconst) )
7284 {
7285 SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrconst = %g\n", weight*aggrconst);
7286 return SCIP_ERROR;
7287 }
7288
7289 /* if workvar was negated, we have to flip the weight */
7290 if( negated )
7291 weight *= -1;
7292
7293 for( i = naggrvars - 1; i >= 0; --i )
7294 {
7295 assert(aggrvars != NULL);
7297
7298 if( !SCIPvarIsBinary(aggrvars[i]) )
7299 {
7300 SCIPerrorMessage("try to resolve a multi-aggregation with a non-binary %svariable <%s> with bounds [%g,%g]\n",
7302 return SCIP_ERROR;
7303 }
7304 if( !SCIPisIntegral(scip, weight * aggrscalars[i]) )
7305 {
7306 SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrscalars = %g\n", weight*aggrscalars[i]);
7307 return SCIP_ERROR;
7308 }
7309 /* if the new coefficient is smaller than zero, we need to add the negated variable instead and adjust the capacity */
7310 if( SCIPisNegative(scip, weight * aggrscalars[i]) )
7311 {
7313 assert(negvar != NULL);
7314 SCIP_CALL( addCoef(scip, cons, negvar, (SCIP_Longint)(SCIPfloor(scip, -weight * aggrscalars[i] + 0.5))) );
7315 consdata->capacity -= (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5));
7316 }
7317 else
7318 {
7319 SCIP_CALL( addCoef(scip, cons, aggrvars[i], (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5))) );
7320 }
7321 }
7322 /* delete old coefficient */
7323 SCIP_CALL( delCoefPos(scip, cons, v) );
7324
7325 /* adjust the capacity with the aggregation constant and if necessary the extra weight through the negation */
7326 if( negated )
7327 consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * (aggrconst - 1) + 0.5);
7328 else
7329 consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * aggrconst + 0.5);
7330
7331 if( consdata->capacity < 0 )
7332 {
7333 if( cutoff != NULL )
7334 {
7335 *cutoff = TRUE;
7336 break;
7337 }
7338 }
7339 }
7340 /* check, if the variable should be replaced with the representative */
7341 else if( repvar != var )
7342 {
7343 /* delete old (aggregated) variable */
7344 SCIP_CALL( delCoefPos(scip, cons, v) );
7345
7346 /* add representative instead */
7347 SCIP_CALL( addCoef(scip, cons, repvar, weight) );
7348 }
7349 else
7350 ++v;
7351 }
7352 }
7353 assert(consdata->onesweightsum == 0);
7354
7355 SCIPdebugMsg(scip, "after applyFixings, before merging:\n");
7357
7358 /* if aggregated variables have been replaced, multiple entries of the same variable are possible and we have to
7359 * clean up the constraint
7360 */
7361 if( cutoff != NULL && !(*cutoff) )
7362 {
7364 SCIPdebugMsg(scip, "after applyFixings and merging:\n");
7366 }
7367
7368 return SCIP_OKAY;
7369}
7370
7371
7372/** propagation method for knapsack constraints */
7373static
7375 SCIP* scip, /**< SCIP data structure */
7376 SCIP_CONS* cons, /**< knapsack constraint */
7377 SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
7378 SCIP_Bool* redundant, /**< pointer to store whether constraint is redundant */
7379 int* nfixedvars, /**< pointer to count number of fixings */
7380 SCIP_Bool usenegatedclique /**< should negated clique information be used */
7381 )
7382{
7383 SCIP_CONSDATA* consdata;
7384 SCIP_Bool infeasible;
7385 SCIP_Bool tightened;
7386 SCIP_Longint* secondmaxweights;
7387 SCIP_Longint minweightsum;
7388 SCIP_Longint residualcapacity;
7389
7390 int nvars;
7391 int i;
7392 int nnegcliques;
7393
7394 SCIP_VAR** myvars;
7395 SCIP_Longint* myweights;
7396 int* cliquestartposs;
7397 int* cliqueendposs;
7398 SCIP_Longint localminweightsum;
7399 SCIP_Bool foundmax;
7400 int c;
7401
7402 assert(scip != NULL);
7403 assert(cons != NULL);
7404 assert(cutoff != NULL);
7405 assert(redundant != NULL);
7406 assert(nfixedvars != NULL);
7407
7408 consdata = SCIPconsGetData(cons);
7409 assert(consdata != NULL);
7410
7411 *cutoff = FALSE;
7412 *redundant = FALSE;
7413
7414 SCIPdebugMsg(scip, "propagating knapsack constraint <%s>\n", SCIPconsGetName(cons));
7415
7416 /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */
7418 {
7419 SCIP_CALL( SCIPincConsAge(scip, cons) );
7420 }
7421
7422#ifndef NDEBUG
7423 /* assert that only active or negated variables are present */
7424 for( i = 0; i < consdata->nvars && consdata->merged; ++i )
7425 {
7426 assert(SCIPvarIsActive(consdata->vars[i]) || SCIPvarIsNegated(consdata->vars[i]) || SCIPvarGetStatus(consdata->vars[i]) == SCIP_VARSTATUS_FIXED);
7427 }
7428#endif
7429
7430 usenegatedclique = usenegatedclique && consdata->merged;
7431
7432 /* init for debugging */
7433 myvars = NULL;
7434 myweights = NULL;
7437 minweightsum = 0;
7438 nvars = consdata->nvars;
7439 /* make sure, the items are sorted by non-increasing weight */
7440 sortItems(consdata);
7441
7442 do
7443 {
7445
7446 /* (1) compute the minimum weight of the knapsack constraint using negated clique information;
7447 * a negated clique means, that at most one of the clique variables can be zero
7448 * - minweightsum = sum_{negated cliques C} ( sum(wi : i \in C) - W_max(C) ), where W_max(C) is the maximal weight of C
7449 *
7450 * if for i \in C (a negated clique) oneweightsum + minweightsum - wi + W_max(C) > capacity => xi = 1
7451 * since replacing i with the element of maximal weight leads to infeasibility
7452 */
7453 if( usenegatedclique && nvars > 0 )
7454 {
7455 SCIP_CONSHDLRDATA* conshdlrdata;
7456 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7457 assert(conshdlrdata != NULL);
7458
7459 /* compute clique partitions */
7460 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
7461 nnegcliques = consdata->nnegcliques;
7462
7463 /* if we have no real negated cliques we can stop here */
7464 if( nnegcliques == nvars )
7465 {
7466 /* run the standard algorithm that does not involve cliques */
7467 usenegatedclique = FALSE;
7468 break;
7469 }
7470
7471 /* allocate temporary memory and initialize it */
7472 SCIP_CALL( SCIPduplicateBufferArray(scip, &myvars, consdata->vars, nvars) );
7473 SCIP_CALL( SCIPduplicateBufferArray(scip, &myweights, consdata->weights, nvars) ) ;
7474 SCIP_CALL( SCIPallocBufferArray(scip, &cliquestartposs, nnegcliques + 1) );
7478
7479 /* resort variables to avoid quadratic algorithm later on */
7481
7482 /* save the end positions of the cliques because start positions are moved in the following loop */
7483 for( c = 0; c < nnegcliques; ++c )
7484 {
7485 cliqueendposs[c] = cliquestartposs[c+1] - 1;
7487 }
7488
7489 c = 0;
7490 foundmax = FALSE;
7491 i = 0;
7492
7493 while( i < nvars )
7494 {
7495 /* ignore variables of the negated clique which are fixed to one since these are counted in
7496 * consdata->onesweightsum
7497 */
7498
7499 /* if there are only one variable negated cliques left we can stop */
7500 if( nnegcliques - c == nvars - i )
7501 {
7504 break;
7505 }
7506
7507 /* for summing up the minimum active weights due to cliques we have to omit the biggest weights of each
7508 * clique, we can only skip this clique if this variables is not fixed to zero, otherwise we have to fix all
7509 * other clique variables to one
7510 */
7511 if( cliquestartposs[c] == i )
7512 {
7513 assert(myweights[i] > 0);
7514 ++c;
7517 foundmax = TRUE;
7518
7519 if( SCIPvarGetLbLocal(myvars[i]) > 0.5 )
7520 foundmax = FALSE;
7521
7522 if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7523 {
7524 ++i;
7525 continue;
7526 }
7527 }
7528
7529 if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7530 {
7531 assert(myweights[i] > 0);
7532
7533 if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7534 {
7536
7537 if( !foundmax )
7538 {
7539 foundmax = TRUE;
7540
7541 /* overwrite cliquestartpos to the position of the first unfixed variable in this clique */
7542 cliquestartposs[c - 1] = i;
7543 ++i;
7544
7545 continue;
7546 }
7547 /* memorize second max weight for each clique */
7548 if( secondmaxweights[c - 1] == 0 )
7549 secondmaxweights[c - 1] = myweights[i];
7550
7552 }
7553 /* we found a fixed variable to zero so all other variables in this negated clique have to be fixed to one */
7554 else
7555 {
7556 int v;
7557 /* fix all other variables of the negated clique to 1 */
7558 for( v = cliquestartposs[c - 1]; v < cliquestartposs[c]; ++v )
7559 {
7560 if( v != i && SCIPvarGetLbLocal(myvars[v]) < 0.5 )
7561 {
7562 SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[v]));
7563 SCIP_CALL( SCIPinferBinvarCons(scip, myvars[v], TRUE, cons, SCIPvarGetIndex(myvars[i]), &infeasible, &tightened) );
7564
7565 if( infeasible )
7566 {
7567 assert( SCIPvarGetUbLocal(myvars[v]) < 0.5 );
7568
7569 /* analyze the infeasibility if conflict analysis is applicable */
7571 {
7572 /* conflict analysis can only be applied in solving stage */
7574
7575 /* initialize the conflict analysis */
7577
7578 /* add the two variables which are fixed to zero within a negated clique */
7581
7582 /* start the conflict analysis */
7584 }
7585 *cutoff = TRUE;
7586 break;
7587 }
7588 assert(tightened);
7589 ++(*nfixedvars);
7591 }
7592 }
7593
7594 /* reset local minweightsum for clique because all fixed to one variables are now counted in consdata->onesweightsum */
7596 /* we can jump to the end of this clique */
7597 i = cliqueendposs[c - 1];
7598
7599 if( *cutoff )
7600 break;
7601 }
7602 }
7603 ++i;
7604 }
7605 /* add last clique minweightsum */
7607
7608 SCIPdebugMsg(scip, "knapsack constraint <%s> has minimum weight sum of <%" SCIP_LONGINT_FORMAT ">\n",
7609 SCIPconsGetName(cons), minweightsum + consdata->onesweightsum );
7610
7611 /* check, if weights of fixed variables don't exceeds knapsack capacity */
7612 if( !(*cutoff) && consdata->capacity >= minweightsum + consdata->onesweightsum )
7613 {
7614 SCIP_Longint maxcliqueweight = -1LL;
7615
7616 /* loop over cliques */
7617 for( c = 0; c < nnegcliques; ++c )
7618 {
7620 SCIP_Bool maxvarfixed;
7621 int endvarposclique;
7623
7624 assert(myvars != NULL);
7625 assert(nnegcliques == consdata->nnegcliques);
7626 assert(myweights != NULL);
7629
7632
7634
7635 /* no need to process this negated clique because all variables are already fixed (which we detect from a fixed maxvar) */
7637 continue;
7638
7641 /* if the sum of all weights of fixed variables to one plus the minimalweightsum (minimal weight which is already
7642 * used in this knapsack due to negated cliques) plus any weight minus the second largest weight in this clique
7643 * exceeds the capacity the maximum weight variable can be fixed to zero.
7644 */
7645 if( consdata->onesweightsum + minweightsum + (maxcliqueweight - secondmaxweights[c]) > consdata->capacity )
7646 {
7647#ifndef NDEBUG
7648 SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7649#endif
7652
7653 SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(maxvar));
7655 SCIP_CALL( SCIPinferBinvarCons(scip, maxvar, FALSE, cons, cliquestartposs[c], &infeasible, &tightened) );
7656 assert(consdata->onesweightsum == oldonesweightsum);
7657 assert(!infeasible);
7658 assert(tightened);
7659 (*nfixedvars)++;
7660 maxvarfixed = TRUE;
7661 }
7662 /* the remaining cliques are singletons such that all subsequent variables have a weight that
7663 * fits into the knapsack
7664 */
7665 else if( nnegcliques - c == nvars - startvarposclique )
7666 break;
7667 /* early termination of the remaining loop because no further variable fixings are possible:
7668 *
7669 * the gain in any of the following negated cliques (the additional term if the maximum weight variable was set to 1, and the second
7670 * largest was set to 0) does not suffice to infer additional variable fixings because
7671 *
7672 * - the cliques are sorted by decreasing maximum weight -> for all c' >= c: maxweights[c'] <= maxcliqueweight
7673 * - their second largest elements are at least as large as the smallest weight of the knapsack
7674 */
7675 else if( consdata->onesweightsum + minweightsum + (maxcliqueweight - consdata->weights[nvars - 1]) <= consdata->capacity )
7676 break;
7677
7678 /* loop over items with non-maximal weight (omitting the first position) */
7679 for( i = endvarposclique; i > startvarposclique; --i )
7680 {
7681 /* there should be no variable fixed to 0 between startvarposclique + 1 and endvarposclique unless we
7682 * messed up the clique preprocessing in the previous loop to filter those variables out */
7684
7685 /* only check variables of negated cliques for which no variable is locally fixed */
7686 if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7687 {
7690
7691 /* we fix the members of this clique with non-maximal weight in two cases to 1:
7692 *
7693 * the maxvar was already fixed to 0 because it has a huge gain.
7694 *
7695 * if for i \in C (a negated clique) onesweightsum - wi + W_max(c) > capacity => xi = 1
7696 * since replacing i with the element of maximal weight leads to infeasibility */
7697 if( maxvarfixed || consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity )
7698 {
7699#ifndef NDEBUG
7700 SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7701#endif
7702 SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[i]));
7703 SCIP_CALL( SCIPinferBinvarCons(scip, myvars[i], TRUE, cons, -i, &infeasible, &tightened) );
7704 assert(consdata->onesweightsum == oldonesweightsum + myweights[i]);
7705 assert(!infeasible);
7706 assert(tightened);
7707 ++(*nfixedvars);
7709
7710 /* update minweightsum because now the variable is fixed to one and its weight is counted by
7711 * consdata->onesweightsum
7712 */
7714 assert(minweightsum >= 0);
7715 }
7716 else
7717 break;
7718 }
7719 }
7720#ifndef NDEBUG
7721 /* in debug mode, we assert that we did not miss possible fixings by the break above */
7722 for( ; i > startvarposclique; --i )
7723 {
7725 SCIP_Bool exceedscapacity = consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity;
7726
7729 }
7730#endif
7731 }
7732 }
7738 }
7739
7740 assert(consdata->negcliquepartitioned || minweightsum == 0);
7741 }
7742 while( FALSE );
7743
7744 assert(usenegatedclique || minweightsum == 0);
7745 /* check, if weights of fixed variables already exceed knapsack capacity */
7746 if( consdata->capacity < minweightsum + consdata->onesweightsum )
7747 {
7748 SCIPdebugMsg(scip, " -> cutoff - fixed weight: %" SCIP_LONGINT_FORMAT ", capacity: %" SCIP_LONGINT_FORMAT " \n",
7749 consdata->onesweightsum, consdata->capacity);
7750
7752 *cutoff = TRUE;
7753
7754 /* analyze the cutoff in SOLVING stage and if conflict analysis is turned on */
7756 {
7757 /* start conflict analysis with the fixed-to-one variables, add only as many as needed to exceed the capacity */
7758 SCIP_Longint weight;
7759
7760 weight = 0;
7761
7763
7764 for( i = 0; i < nvars && weight <= consdata->capacity; i++ )
7765 {
7766 if( SCIPvarGetLbLocal(consdata->vars[i]) > 0.5)
7767 {
7768 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
7769 weight += consdata->weights[i];
7770 }
7771 }
7772
7774 }
7775
7776 return SCIP_OKAY;
7777 }
7778
7779 /* the algorithm below is a special case of propagation involving negated cliques */
7780 if( !usenegatedclique )
7781 {
7782 assert(consdata->sorted);
7783 residualcapacity = consdata->capacity - consdata->onesweightsum;
7784
7785 /* fix all variables to zero, that don't fit into the knapsack anymore */
7786 for( i = 0; i < nvars && consdata->weights[i] > residualcapacity; ++i )
7787 {
7788 /* if all weights of fixed variables to one plus any weight exceeds the capacity the variables have to be fixed
7789 * to zero
7790 */
7791 if( SCIPvarGetLbLocal(consdata->vars[i]) < 0.5 )
7792 {
7793 if( SCIPvarGetUbLocal(consdata->vars[i]) > 0.5 )
7794 {
7795 assert(consdata->onesweightsum + consdata->weights[i] > consdata->capacity);
7796 SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(consdata->vars[i]));
7798 SCIP_CALL( SCIPinferBinvarCons(scip, consdata->vars[i], FALSE, cons, i, &infeasible, &tightened) );
7799 assert(!infeasible);
7800 assert(tightened);
7801 (*nfixedvars)++;
7802 }
7803 }
7804 }
7805 }
7806
7807 /* check if the knapsack is now redundant */
7808 if( !SCIPconsIsModifiable(cons) )
7809 {
7810 SCIP_Longint unfixedweightsum = consdata->onesweightsum;
7811
7812 /* sum up the weights of all unfixed variables, plus the weight sum of all variables fixed to one already */
7813 for( i = 0; i < nvars; ++i )
7814 {
7815 if( SCIPvarGetLbLocal(consdata->vars[i]) + 0.5 < SCIPvarGetUbLocal(consdata->vars[i]) )
7816 {
7817 unfixedweightsum += consdata->weights[i];
7818
7819 /* the weight sum is larger than the capacity, so the constraint is not redundant */
7820 if( unfixedweightsum > consdata->capacity )
7821 return SCIP_OKAY;
7822 }
7823 }
7824 /* we summed up all (unfixed and fixed to one) weights and did not exceed the capacity, so the constraint is redundant */
7825 SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", unfixedweightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
7826 SCIPconsGetName(cons), consdata->weightsum, unfixedweightsum, consdata->capacity);
7828 *redundant = TRUE;
7829 }
7830
7831 return SCIP_OKAY;
7832}
7833
7834/** all but one variable fit into the knapsack constraint, so we can upgrade this constraint to an logicor constraint
7835 * containing all negated variables of this knapsack constraint
7836 */
7837static
7839 SCIP* scip, /**< SCIP data structure */
7840 SCIP_CONS* cons, /**< knapsack constraint */
7841 int* ndelconss, /**< pointer to store the amount of deleted constraints */
7842 int* naddconss /**< pointer to count number of added constraints */
7843 )
7844{
7846 SCIP_CONSDATA* consdata;
7847
7848 assert(scip != NULL);
7849 assert(cons != NULL);
7850 assert(ndelconss != NULL);
7851 assert(naddconss != NULL);
7852
7853 consdata = SCIPconsGetData(cons);
7854 assert(consdata != NULL);
7855 assert(consdata->nvars > 1);
7856
7857 /* if the knapsack constraint consists only of two variables, we can upgrade it to a set-packing constraint */
7858 if( consdata->nvars == 2 )
7859 {
7860 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
7861
7862 SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
7866 SCIPconsIsStickingAtNode(cons)) );
7867 }
7868 /* if the knapsack constraint consists of at least three variables, we can upgrade it to a logicor constraint
7869 * containing all negated variables of the knapsack
7870 */
7871 else
7872 {
7873 SCIP_VAR** consvars;
7874
7875 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a logicor constraint", SCIPconsGetName(cons));
7876
7877 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, consdata->nvars) );
7878 SCIP_CALL( SCIPgetNegatedVars(scip, consdata->nvars, consdata->vars, consvars) );
7879
7880 SCIP_CALL( SCIPcreateConsLogicor(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consvars,
7884 SCIPconsIsStickingAtNode(cons)) );
7885
7886 SCIPfreeBufferArray(scip, &consvars);
7887 }
7888
7891 ++(*naddconss);
7892
7893 SCIP_CALL( SCIPdelCons(scip, cons) );
7894 ++(*ndelconss);
7895
7896 return SCIP_OKAY;
7897}
7898
7899/** delete redundant variables
7900 *
7901 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
7902 *
7903 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
7904 * => x4, x5 always fits into the knapsack, so we can delete them
7905 *
7906 * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
7907 * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
7908 */
7909static
7911 SCIP* scip, /**< SCIP data structure */
7912 SCIP_CONS* cons, /**< knapsack constraint */
7913 SCIP_Longint frontsum, /**< sum of front items which fit if we try to take from the first till the last */
7914 int splitpos, /**< split position till when all front items are fitting, splitpos is the
7915 * first which did not fit */
7916 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
7917 int* nchgsides, /**< pointer to store the amount of changed sides */
7918 int* naddconss /**< pointer to count number of added constraints */
7919 )
7920{
7921 SCIP_CONSHDLRDATA* conshdlrdata;
7922 SCIP_CONSDATA* consdata;
7923 SCIP_VAR** vars;
7924 SCIP_Longint* weights;
7925 SCIP_Longint capacity;
7926 SCIP_Longint gcd;
7927 int nvars;
7928 int w;
7929
7930 assert(scip != NULL);
7931 assert(cons != NULL);
7932 assert(nchgcoefs != NULL);
7933 assert(nchgsides != NULL);
7934 assert(naddconss != NULL);
7935
7936 consdata = SCIPconsGetData(cons);
7937 assert(consdata != NULL);
7938 assert(0 < frontsum && frontsum < consdata->weightsum);
7940
7941 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7942 assert(conshdlrdata != NULL);
7943
7944 vars = consdata->vars;
7945 weights = consdata->weights;
7946 nvars = consdata->nvars;
7947 capacity = consdata->capacity;
7948
7949 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
7950 * weight must not be sorted by their index
7951 */
7952#ifndef NDEBUG
7953 for( w = nvars - 1; w > 0; --w )
7954 assert(weights[w] <= weights[w-1]);
7955#endif
7956
7957 /* if there are no variables rear to splitpos, the constraint has no redundant variables */
7958 if( consdata->nvars - 1 == splitpos )
7959 return SCIP_OKAY;
7960
7961 assert(frontsum + weights[splitpos] > capacity);
7962
7963 /* detect redundant variables */
7964 if( consdata->weightsum - weights[splitpos] <= capacity )
7965 {
7966 /* all rear items are redundant, because leaving one item in front and incl. of splitpos out the rear itmes always
7967 * fit
7968 */
7969 SCIPdebugMsg(scip, "Found redundant variables in constraint <%s>.\n", SCIPconsGetName(cons));
7970
7971 /* delete items and update capacity */
7972 for( w = nvars - 1; w > splitpos; --w )
7973 {
7974 consdata->capacity -= weights[w];
7975 SCIP_CALL( delCoefPos(scip, cons, w) );
7976 }
7977 assert(w == splitpos);
7978
7979 ++(*nchgsides);
7980 *nchgcoefs += (nvars - splitpos);
7981
7982 /* division by greatest common divisor */
7983 gcd = weights[w];
7984 for( ; w >= 0 && gcd > 1; --w )
7985 {
7986 gcd = SCIPcalcGreComDiv(gcd, weights[w]);
7987 }
7988
7989 /* normalize if possible */
7990 if( gcd > 1 )
7991 {
7992 for( w = splitpos; w >= 0; --w )
7993 {
7994 consdataChgWeight(consdata, w, weights[w]/gcd);
7995 }
7996 (*nchgcoefs) += nvars;
7997
7998 consdata->capacity /= gcd;
7999 ++(*nchgsides);
8000 }
8001
8002 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8003 * weight must not be sorted by their index
8004 */
8005#ifndef NDEBUG
8006 for( w = consdata->nvars - 1; w > 0; --w )
8007 assert(weights[w] <= weights[w - 1]);
8008#endif
8009 }
8010 /* rear items can only be redundant, when the sum is smaller to the weight at splitpos and all rear items would
8011 * always fit into the knapsack, therefor the item directly after splitpos needs to be smaller than the one at
8012 * splitpos and needs to fit into the knapsack
8013 */
8014 else if( conshdlrdata->disaggregation && frontsum + weights[splitpos + 1] <= capacity )
8015 {
8016 int* clqpart;
8017 int nclq;
8018 int len;
8019
8020 len = nvars - (splitpos + 1);
8021 /* allocate temporary memory */
8023
8024 /* calculate clique partition */
8025 SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[splitpos+1]), len, clqpart, &nclq) );
8026
8027 /* check if we found at least one clique */
8028 if( nclq < len )
8029 {
8030 SCIP_Longint maxactduetoclq;
8031 int cliquenum;
8032
8033 maxactduetoclq = 0;
8034 cliquenum = 0;
8035
8036 /* calculate maximum activity due to cliques */
8037 for( w = 0; w < len; ++w )
8038 {
8039 assert(clqpart[w] >= 0 && clqpart[w] <= w);
8040 if( clqpart[w] == cliquenum )
8041 {
8042 maxactduetoclq += weights[w + splitpos + 1];
8043 ++cliquenum;
8044 }
8045 }
8046
8047 /* all rear items are redundant due to clique information, if maxactduetoclq is smaller than the weight before,
8048 * so delete them and create for all clique the corresponding clique constraints and update the capacity
8049 */
8050 if( frontsum + maxactduetoclq <= capacity )
8051 {
8052 SCIP_VAR** clqvars;
8053 int nclqvars;
8054 int c;
8055
8056 assert(maxactduetoclq < weights[splitpos]);
8057
8058 SCIPdebugMsg(scip, "Found redundant variables in constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8059
8060 /* allocate temporary memory */
8062
8063 for( c = 0; c < nclq; ++c )
8064 {
8065 nclqvars = 0;
8066 for( w = 0; w < len; ++w )
8067 {
8068 if( clqpart[w] == c )
8069 {
8070 clqvars[nclqvars] = vars[w + splitpos + 1];
8071 ++nclqvars;
8072 }
8073 }
8074
8075 /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8076 if( nclqvars > 1 )
8077 {
8079 char name[SCIP_MAXSTRLEN];
8080
8081 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8086 SCIPconsIsStickingAtNode(cons)) );
8087 SCIPdebugMsg(scip, " -> adding clique constraint: ");
8091 ++(*naddconss);
8092 }
8093 }
8094
8095 /* delete items and update capacity */
8096 for( w = nvars - 1; w > splitpos; --w )
8097 {
8098 SCIP_CALL( delCoefPos(scip, cons, w) );
8099 ++(*nchgcoefs);
8100 }
8101 consdata->capacity -= maxactduetoclq;
8103 ++(*nchgsides);
8104
8105 assert(w == splitpos);
8106
8107 /* renew weights pointer */
8108 weights = consdata->weights;
8109
8110 /* division by greatest common divisor */
8111 gcd = weights[w];
8112 for( ; w >= 0 && gcd > 1; --w )
8113 {
8114 gcd = SCIPcalcGreComDiv(gcd, weights[w]);
8115 }
8116
8117 /* normalize if possible */
8118 if( gcd > 1 )
8119 {
8120 for( w = splitpos; w >= 0; --w )
8121 {
8122 consdataChgWeight(consdata, w, weights[w]/gcd);
8123 }
8124 (*nchgcoefs) += nvars;
8125
8126 consdata->capacity /= gcd;
8127 ++(*nchgsides);
8128 }
8129
8130 /* free temporary memory */
8132
8133 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8134 * weight must not be sorted by their index
8135 */
8136#ifndef NDEBUG
8137 for( w = consdata->nvars - 1; w > 0; --w )
8138 assert(weights[w] <= weights[w - 1]);
8139#endif
8140 }
8141 }
8142
8143 /* free temporary memory */
8145 }
8146
8147 return SCIP_OKAY;
8148}
8149
8150/* detect redundant variables which always fits into the knapsack
8151 *
8152 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
8153 *
8154 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
8155 * => x4, x5 always fits into the knapsack, so we can delete them
8156 *
8157 * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
8158 * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
8159 */
8160static
8162 SCIP* scip, /**< SCIP data structure */
8163 SCIP_CONS* cons, /**< knapsack constraint */
8164 int* ndelconss, /**< pointer to store the amount of deleted constraints */
8165 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8166 int* nchgsides, /**< pointer to store the amount of changed sides */
8167 int* naddconss /**< pointer to count number of added constraints */
8168 )
8169{
8170 SCIP_CONSHDLRDATA* conshdlrdata;
8171 SCIP_CONSDATA* consdata;
8172 SCIP_VAR** vars;
8173 SCIP_Longint* weights;
8174 SCIP_Longint capacity;
8175 SCIP_Longint sum;
8176 int noldchgcoefs;
8177 int nvars;
8178 int v;
8179 int w;
8180
8181 assert(scip != NULL);
8182 assert(cons != NULL);
8183 assert(ndelconss != NULL);
8184 assert(nchgcoefs != NULL);
8185 assert(nchgsides != NULL);
8186 assert(naddconss != NULL);
8187
8188 consdata = SCIPconsGetData(cons);
8189 assert(consdata != NULL);
8190 assert(consdata->nvars >= 2);
8191 assert(consdata->weightsum > consdata->capacity);
8192
8193 noldchgcoefs = *nchgcoefs;
8194 vars = consdata->vars;
8195 weights = consdata->weights;
8196 nvars = consdata->nvars;
8197 capacity = consdata->capacity;
8198 sum = 0;
8199
8200 /* search for maximal fitting items */
8201 for( v = 0; v < nvars && sum + weights[v] <= capacity; ++v )
8202 sum += weights[v];
8203
8204 assert(v < nvars);
8205
8206 /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8207 if( v == nvars - 1 )
8208 {
8209 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8211
8212 return SCIP_OKAY;
8213 }
8214
8215 if( v < nvars - 1 )
8216 {
8217 /* try to delete variables */
8218 SCIP_CALL( deleteRedundantVars(scip, cons, sum, v, nchgcoefs, nchgsides, naddconss) );
8219 assert(consdata->nvars > 1);
8220
8221 /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8222 if( v == consdata->nvars - 1 )
8223 {
8224 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8226 }
8227
8228 return SCIP_OKAY;
8229 }
8230
8231 /* if we already found some redundant variables, stop here */
8232 if( *nchgcoefs > noldchgcoefs )
8233 return SCIP_OKAY;
8234
8235 assert(vars == consdata->vars);
8236 assert(weights == consdata->weights);
8237 assert(nvars == consdata->nvars);
8238 assert(capacity == consdata->capacity);
8239
8240 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
8241 assert(conshdlrdata != NULL);
8242 /* calculate clique partition */
8243 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
8244
8245 /* check for real existing cliques */
8246 if( consdata->cliquepartition[v] < v )
8247 {
8248 SCIP_Longint sumfront;
8249 SCIP_Longint maxactduetoclqfront;
8250 int* clqpart;
8251 int cliquenum;
8252
8253 sumfront = 0;
8255
8256 clqpart = consdata->cliquepartition;
8257 cliquenum = 0;
8258
8259 /* calculate maximal activity due to cliques */
8260 for( w = 0; w < nvars; ++w )
8261 {
8262 assert(clqpart[w] >= 0 && clqpart[w] <= w);
8263 if( clqpart[w] == cliquenum )
8264 {
8265 if( maxactduetoclqfront + weights[w] <= capacity )
8266 {
8267 maxactduetoclqfront += weights[w];
8268 ++cliquenum;
8269 }
8270 else
8271 break;
8272 }
8273 sumfront += weights[w];
8274 }
8275 assert(w >= v);
8276
8277 /* if all items fit, then delete the whole constraint but create clique constraints which led to this
8278 * information
8279 */
8280 if( conshdlrdata->disaggregation && w == nvars )
8281 {
8282 SCIP_VAR** clqvars;
8283 int nclqvars;
8284 int c;
8285 int ncliques;
8286
8287 assert(maxactduetoclqfront <= capacity);
8288
8289 SCIPdebugMsg(scip, "Found redundant constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8290
8291 ncliques = consdata->ncliques;
8292
8293 /* allocate temporary memory */
8294 SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, nvars - ncliques + 1) );
8295
8296 for( c = 0; c < ncliques; ++c )
8297 {
8298 nclqvars = 0;
8299 for( w = 0; w < nvars; ++w )
8300 {
8301 if( clqpart[w] == c )
8302 {
8303 clqvars[nclqvars] = vars[w];
8304 ++nclqvars;
8305 }
8306 }
8307
8308 /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8309 if( nclqvars > 1 )
8310 {
8312 char name[SCIP_MAXSTRLEN];
8313
8314 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8319 SCIPconsIsStickingAtNode(cons)) );
8320 SCIPdebugMsg(scip, " -> adding clique constraint: ");
8324 ++(*naddconss);
8325 }
8326 }
8327
8328 /* delete old constraint */
8330 ++(*ndelconss);
8331
8333
8334 return SCIP_OKAY;
8335 }
8336
8337 if( w > v && w < nvars - 1 )
8338 {
8339 /* try to delete variables */
8340 SCIP_CALL( deleteRedundantVars(scip, cons, sumfront, w, nchgcoefs, nchgsides, naddconss) );
8341 }
8342 }
8343
8344 return SCIP_OKAY;
8345}
8346
8347/** divides weights by their greatest common divisor and divides capacity by the same value, rounding down the result */
8348static
8350 SCIP_CONS* cons, /**< knapsack constraint */
8351 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
8352 int* nchgsides /**< pointer to count number of side changes */
8353 )
8354{
8355 SCIP_CONSDATA* consdata;
8356 SCIP_Longint gcd;
8357 int i;
8358
8359 assert(nchgcoefs != NULL);
8360 assert(nchgsides != NULL);
8362
8363 consdata = SCIPconsGetData(cons);
8364 assert(consdata != NULL);
8365 assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
8366 assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
8367 assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
8368 assert(consdata->nvars >= 1);
8369
8370 /* sort items, because we can stop earlier if the smaller weights are evaluated first */
8371 sortItems(consdata);
8372
8373 gcd = consdata->weights[consdata->nvars-1];
8374 for( i = consdata->nvars-2; i >= 0 && gcd >= 2; --i )
8375 {
8376 assert(SCIPvarGetLbLocal(consdata->vars[i]) < 0.5);
8377 assert(SCIPvarGetUbLocal(consdata->vars[i]) > 0.5); /* all fixed variables should have been removed */
8378
8379 gcd = SCIPcalcGreComDiv(gcd, consdata->weights[i]);
8380 }
8381
8382 if( gcd >= 2 )
8383 {
8384 SCIPdebugMessage("knapsack constraint <%s>: dividing weights by %" SCIP_LONGINT_FORMAT "\n", SCIPconsGetName(cons), gcd);
8385
8386 for( i = 0; i < consdata->nvars; ++i )
8387 {
8388 consdataChgWeight(consdata, i, consdata->weights[i]/gcd);
8389 }
8390 consdata->capacity /= gcd;
8391 (*nchgcoefs) += consdata->nvars;
8392 (*nchgsides)++;
8393
8394 /* weight should still be sorted, because the reduction preserves this */
8395#ifndef NDEBUG
8396 for( i = consdata->nvars - 1; i > 0; --i )
8397 assert(consdata->weights[i] <= consdata->weights[i - 1]);
8398#endif
8399 consdata->sorted = TRUE;
8400 }
8401}
8402
8403/** dual weights tightening for knapsack constraints
8404 *
8405 * 1. a) check if all two pairs exceed the capacity, then we can upgrade this constraint to a set-packing constraint
8406 * b) check if all but the smallest weight fit into the knapsack, then we can upgrade this constraint to a logicor
8407 * constraint
8408 *
8409 * 2. check if besides big coefficients, that fit only by itself, for a certain amount of variables all combination of
8410 * these are a minimal cover, then might reduce the weights and the capacity, e.g.
8411 *
8412 * +219y1 + 180y2 + 74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8413 *
8414 * 3. use the duality between a^Tx <= capacity <=> a^T~x >= weightsum - capacity to tighten weights, e.g.
8415 *
8416 * 11x1 + 10x2 + 7x3 + 7x4 + 5x5 <= 27 <=> 11~x1 + 10~x2 + 7~x3 + 7~x4 + 5~x5 >= 13
8417 *
8418 * the above constraint can be changed to 8~x1 + 8~x2 + 6.5~x3 + 6.5~x4 + 5~x5 >= 13
8419 *
8420 * 16~x1 + 16~x2 + 13~x3 + 13~x4 + 10~x5 >= 26 <=> 16x1 + 16x2 + 13x3 + 13x4 + 10x5 <= 42
8421 */
8422static
8424 SCIP* scip, /**< SCIP data structure */
8425 SCIP_CONS* cons, /**< knapsack constraint */
8426 int* ndelconss, /**< pointer to store the amount of deleted constraints */
8427 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8428 int* nchgsides, /**< pointer to store the amount of changed sides */
8429 int* naddconss /**< pointer to count number of added constraints */
8430 )
8431{
8432 SCIP_CONSDATA* consdata;
8433 SCIP_Longint* weights;
8434 SCIP_Longint dualcapacity;
8435 SCIP_Longint reductionsum;
8436 SCIP_Longint capacity;
8437 SCIP_Longint exceedsum;
8438 int oldnchgcoefs;
8439 int nvars;
8440 int vbig;
8441 int v;
8442 int w;
8443#ifndef NDEBUG
8444 int oldnchgsides;
8445#endif
8446
8447 assert(scip != NULL);
8448 assert(cons != NULL);
8449 assert(ndelconss != NULL);
8450 assert(nchgcoefs != NULL);
8451 assert(nchgsides != NULL);
8452 assert(naddconss != NULL);
8453
8454#ifndef NDEBUG
8455 oldnchgsides = *nchgsides;
8456#endif
8457
8458 consdata = SCIPconsGetData(cons);
8459 assert(consdata != NULL);
8460 assert(consdata->weightsum > consdata->capacity);
8461 assert(consdata->nvars >= 2);
8462 assert(consdata->sorted);
8463
8464 /* constraint should be merged */
8465 assert(consdata->merged);
8466
8467 nvars = consdata->nvars;
8468 weights = consdata->weights;
8469 capacity = consdata->capacity;
8470
8471 oldnchgcoefs = *nchgcoefs;
8472
8473 /* case 1. */
8474 if( weights[nvars - 1] + weights[nvars - 2] > capacity )
8475 {
8477
8478 /* two variable are enough to exceed the constraint, so we can update it to a set-packing
8479 *
8480 * e.g. 5x1 + 4x2 + 3x3 <= 5 <=> x1 + x2 + x3 <= 1
8481 */
8482 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
8483
8484 SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
8488 SCIPconsIsStickingAtNode(cons)) );
8489
8492 ++(*naddconss);
8493
8494 SCIP_CALL( SCIPdelCons(scip, cons) );
8495 ++(*ndelconss);
8496
8497 return SCIP_OKAY;
8498 }
8499
8500 /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8501 if( consdata->weightsum - weights[nvars - 1] <= consdata->capacity )
8502 {
8503 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8505
8506 return SCIP_OKAY;
8507 }
8508
8509 /* early termination, if the pair with biggest coeffcients together does not exceed the dualcapacity */
8510 /* @todo might be changed/removed when improving the coeffcients tightening */
8511 if( consdata->weightsum - capacity > weights[0] + weights[1] )
8512 return SCIP_OKAY;
8513
8514 /* case 2. */
8515
8516 v = 0;
8517
8518 /* @todo generalize the following algorithm for several parts of the knapsack
8519 *
8520 * the following is done without looking at the dualcapacity; it is enough to check whether for a certain amount of
8521 * variables each combination is a minimal cover, some examples
8522 *
8523 * +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 74~x1 + 70~x2 + 63~x3 + 62~x4 + 53~x5 >= 103
8524 * <=> ~x1 + ~x2 + ~x3 + ~x4 + ~x5 >= 2
8525 * <=> x1 + x2 + x3 + x4 + x5 <= 3
8526 *
8527 * +219y1 + 180y_2 +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8528 *
8529 */
8530
8531 /* determine big weights that fit only by itself */
8532 while( v < nvars && weights[v] + weights[nvars - 1] > capacity )
8533 ++v;
8534
8535 vbig = v;
8536 assert(vbig < nvars - 1);
8537 exceedsum = 0;
8538
8539 /* determine the amount needed to exceed the capacity */
8540 while( v < nvars && exceedsum <= capacity )
8541 {
8542 exceedsum += weights[v];
8543 ++v;
8544 }
8545
8546 /* if we exceeded the capacity we might reduce the weights */
8547 if( exceedsum > capacity )
8548 {
8549 assert(vbig > 0 || v < nvars);
8550
8551 /* all small weights were needed to exceed the capacity */
8552 if( v == nvars )
8553 {
8554 SCIP_Longint newweight = (SCIP_Longint)nvars - vbig - 1;
8555 assert(newweight > 0);
8556
8557 /* reduce big weights */
8558 for( v = 0; v < vbig; ++v )
8559 {
8560 if( weights[v] > newweight )
8561 {
8562 consdataChgWeight(consdata, v, newweight);
8563 ++(*nchgcoefs);
8564 }
8565 }
8566
8567 /* reduce small weights */
8568 for( ; v < nvars; ++v )
8569 {
8570 if( weights[v] > 1 )
8571 {
8572 consdataChgWeight(consdata, v, 1LL);
8573 ++(*nchgcoefs);
8574 }
8575 }
8576
8577 consdata->capacity = newweight;
8578
8579 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8580 * weight must not be sorted by their index
8581 */
8582#ifndef NDEBUG
8583 for( v = nvars - 1; v > 0; --v )
8584 assert(weights[v] <= weights[v-1]);
8585#endif
8586
8587 return SCIP_OKAY;
8588 }
8589 /* a certain amount of small variables exceed the capacity, so check if this holds for all combinations of the
8590 * small weights
8591 */
8592 else
8593 {
8594 SCIP_Longint exceedsumback = 0;
8595 int nexceed = v - vbig;
8596
8597 assert(nexceed > 1);
8598
8599 /* determine weightsum of the same amount as before but of the smallest weight */
8600 for( w = nvars - 1; w >= nvars - nexceed; --w )
8601 exceedsumback += weights[w];
8602
8603 assert(w >= 0);
8604
8605 /* if the same amount but with the smallest possible weights also exceed the capacity, it holds for all
8606 * combinations of all small weights
8607 */
8608 if( exceedsumback > capacity )
8609 {
8610 SCIP_Longint newweight = nexceed - 1;
8611
8612 /* taking out the smallest element needs to fit */
8613 assert(exceedsumback - weights[nvars - 1] <= capacity);
8614
8615 /* reduce big weights */
8616 for( v = 0; v < vbig; ++v )
8617 {
8618 if( weights[v] > newweight )
8619 {
8620 consdataChgWeight(consdata, v, newweight);
8621 ++(*nchgcoefs);
8622 }
8623 }
8624
8625 /* reduce small weights */
8626 for( ; v < nvars; ++v )
8627 {
8628 if( weights[v] > 1 )
8629 {
8630 consdataChgWeight(consdata, v, 1LL);
8631 ++(*nchgcoefs);
8632 }
8633 }
8634
8635 consdata->capacity = newweight;
8636
8637 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8638 * weight must not be sorted by their index
8639 */
8640#ifndef NDEBUG
8641 for( v = nvars - 1; v > 0; --v )
8642 assert(weights[v] <= weights[v-1]);
8643#endif
8644 return SCIP_OKAY;
8645 }
8646 }
8647 }
8648 else
8649 {
8650 /* if the following assert fails we have either a redundant constraint or a set-packing constraint, this should
8651 * not happen here
8652 */
8653 assert(vbig > 0 && vbig < nvars);
8654
8655 /* either choose a big coefficients or all other variables
8656 *
8657 * 973x1 + 189x2 + 189x3 + 145x4 + 110x5 + 104x6 + 93x7 + 71x8 + 68x9 + 10x10 <= 979
8658 *
8659 * either choose x1, or all other variables (weightsum of x2 to x10 is 979 above), so we can tighten this
8660 * constraint to
8661 *
8662 * 9x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 <= 9
8663 */
8664
8665 if( weights[vbig - 1] > (SCIP_Longint)nvars - vbig || weights[vbig] > 1 )
8666 {
8667 SCIP_Longint newweight = (SCIP_Longint)nvars - vbig;
8668#ifndef NDEBUG
8669 SCIP_Longint resweightsum = consdata->weightsum;
8670
8671 for( v = 0; v < vbig; ++v )
8672 resweightsum -= weights[v];
8673
8675#endif
8676 assert(newweight > 0);
8677
8678 /* reduce big weights */
8679 for( v = 0; v < vbig; ++v )
8680 {
8681 if( weights[v] > newweight )
8682 {
8683 consdataChgWeight(consdata, v, newweight);
8684 ++(*nchgcoefs);
8685 }
8686 }
8687
8688 /* reduce small weights */
8689 for( ; v < nvars; ++v )
8690 {
8691 if( weights[v] > 1 )
8692 {
8693 consdataChgWeight(consdata, v, 1LL);
8694 ++(*nchgcoefs);
8695 }
8696 }
8697
8698 consdata->capacity = newweight;
8699
8700 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8701 * weight must not be sorted by their index
8702 */
8703#ifndef NDEBUG
8704 for( v = nvars - 1; v > 0; --v )
8705 assert(weights[v] <= weights[v-1]);
8706#endif
8707 return SCIP_OKAY;
8708 }
8709 }
8710
8711 /* case 3. */
8712
8713 dualcapacity = consdata->weightsum - capacity;
8714 reductionsum = 0;
8715 v = 0;
8716
8717 /* reduce big weights
8718 *
8719 * e.g. 11x0 + 11x1 + 10x2 + 10x3 <= 32 <=> 11~x0 + 11~x1 + 10~x2 + 10~x3 >= 10
8720 * <=> 10~x0 + 10~x1 + 10~x2 + 10~x3 >= 10
8721 * <=> x0 + x1 + x2 + x3 <= 3
8722 */
8723 while( weights[v] > dualcapacity )
8724 {
8725 reductionsum += (weights[v] - dualcapacity);
8726 consdataChgWeight(consdata, v, dualcapacity);
8727 ++v;
8728 assert(v < nvars);
8729 }
8730 (*nchgcoefs) += v;
8731
8732 /* skip weights equal to the dualcapacity, because we cannot change them */
8733 while( v < nvars && weights[v] == dualcapacity )
8734 ++v;
8735
8736 /* any negated variable out of the first n - 1 items is enough to fulfill the constraint, so we can update it to a logicor
8737 * after a possible removal of the last, redundant item
8738 *
8739 * e.g. 10x1 + 10x2 + 10x3 <= 20 <=> 10~x1 + 10~x2 + 10~x3 >= 10 <=> ~x1 + ~x2 + ~x3 >= 1
8740 */
8741 if( v >= nvars - 1 )
8742 {
8743 /* the last weight is not enough to satisfy the dual capacity -> remove this redundant item */
8744 if( v == nvars - 1 )
8745 {
8746 SCIP_CALL( delCoefPos(scip, cons, nvars - 1) );
8747 }
8748 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8750
8751 return SCIP_OKAY;
8752 }
8753 else /* v < nvars - 1 <=> at least two items with weight smaller than the dual capacity */
8754 {
8755 /* @todo generalize the following algorithm for more than two variables */
8756
8757 if( weights[nvars - 1] + weights[nvars - 2] >= dualcapacity )
8758 {
8759 /* we have a dual-knapsack constraint where we either need to choose one variable out of a subset (big
8760 * coefficients) of all or two variables of the rest
8761 *
8762 * e.g. 9x1 + 9x2 + 6x3 + 4x4 <= 19 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 >= 9
8763 * <=> 2~x1 + 2~x2 + ~x3 + ~x4 >= 2
8764 * <=> 2x1 + 2x2 + x3 + x4 <= 4
8765 *
8766 * 3x1 + 3x2 + 2x3 + 2x4 + 2x5 + 2x6 + x7 <= 12 <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + 2~x5 + 2~x6 + ~x7 >= 3
8767 * <=> 2~x1 + 2~x2 + ~x3 + ~x4 + ~x5 + ~x6 + ~x7 >= 2
8768 * <=> 2 x1 + 2 x2 + x3 + x4 + x5 + x6 + x7 <= 7
8769 *
8770 */
8771 if( v > 0 && weights[nvars - 2] > 1 )
8772 {
8773 int ncoefchg = 0;
8774
8775 /* reduce all bigger weights */
8776 for( w = 0; w < v; ++w )
8777 {
8778 if( weights[w] > 2 )
8779 {
8780 consdataChgWeight(consdata, w, 2LL);
8781 ++ncoefchg;
8782 }
8783 else
8784 {
8785 assert(weights[0] == 2);
8786 assert(weights[v - 1] == 2);
8787 break;
8788 }
8789 }
8790
8791 /* reduce all smaller weights */
8792 for( w = v; w < nvars; ++w )
8793 {
8794 if( weights[w] > 1 )
8795 {
8796 consdataChgWeight(consdata, w, 1LL);
8797 ++ncoefchg;
8798 }
8799 }
8800 assert(ncoefchg > 0);
8801
8802 (*nchgcoefs) += ncoefchg;
8803
8804 /* correct the capacity */
8805 consdata->capacity = (-2 + v * 2 + nvars - v); /*lint !e647*/
8806 assert(consdata->capacity > 0);
8807 assert(weights[0] <= consdata->capacity);
8808 assert(consdata->weightsum > consdata->capacity);
8809 /* reset the reductionsum */
8810 reductionsum = 0;
8811 }
8812 else if( v == 0 )
8813 {
8814 assert(weights[nvars - 2] == 1);
8815 }
8816 }
8817 else
8818 {
8819 SCIP_Longint minweight = weights[nvars - 1];
8820 SCIP_Longint newweight = dualcapacity - minweight;
8821 SCIP_Longint restsumweights = 0;
8822 SCIP_Longint sumcoef;
8823 SCIP_Bool sumcoefcase = FALSE;
8824 int startv = v;
8825 int end;
8826 int k;
8827
8828 assert(weights[nvars - 1] + weights[nvars - 2] <= capacity);
8829
8830 /* reduce big weights of pairs that exceed the dualcapacity
8831 *
8832 * e.g. 9x1 + 9x2 + 6x3 + 4x4 + 4x5 + 4x6 <= 27 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8833 * <=> 9~x1 + 9~x2 + 5~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8834 * <=> 9x1 + 9x2 + 5x3 + 4x4 + 4x5 + 4x6 <= 27
8835 */
8836 while( weights[v] > newweight )
8837 {
8838 reductionsum += (weights[v] - newweight);
8839 consdataChgWeight(consdata, v, newweight);
8840 ++v;
8841 assert(v < nvars);
8842 }
8843 (*nchgcoefs) += (v - startv);
8844
8845 /* skip equal weights */
8846 while( weights[v] == newweight )
8847 ++v;
8848
8849 if( v > 0 )
8850 {
8851 for( w = v; w < nvars; ++w )
8852 restsumweights += weights[w];
8853 }
8854 else
8855 restsumweights = consdata->weightsum;
8856
8858 {
8859 /* we found redundant variables, which does not influence the feasibility of any integral solution, e.g.
8860 *
8861 * +61x1 + 61x2 + 61x3 + 61x4 + 61x5 + 61x6 + 35x7 + 10x8 <= 350 <=>
8862 * +61~x1 + 61~x2 + 61~x3 + 61~x4 + 61~x5 + 61~x6 + 35~x7 + 10~x8 >= 61
8863 */
8864 if( startv == v )
8865 {
8866 /* remove redundant variables */
8867 for( w = nvars - 1; w >= v; --w )
8868 {
8869 SCIP_CALL( delCoefPos(scip, cons, v) );
8870 ++(*nchgcoefs);
8871 }
8872
8873#ifndef NDEBUG
8874 /* each coefficients should exceed the dualcapacity by itself */
8875 for( ; w >= 0; --w )
8876 assert(weights[w] == dualcapacity);
8877#endif
8878 /* for performance reasons we do not update the capacity(, i.e. reduce it by reductionsum) and directly
8879 * upgrade this constraint
8880 */
8881 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8883
8884 return SCIP_OKAY;
8885 }
8886
8887 /* special case where we have three different coefficient types
8888 *
8889 * e.g. 9x1 + 9x2 + 6x3 + 6x4 + 4x5 + 4x6 <= 29 <=> 9~x1 + 9~x2 + 6~x3 + 6~x4 + 4~x5 + 4~x6 >= 9
8890 * <=> 9~x1 + 9~x2 + 5~x3 + 5~x4 + 4~x5 + 4~x6 >= 9
8891 * <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + ~x5 + ~x6 >= 3
8892 * <=> 3x1 + 3x2 + 2x3 + 2x4 + x5 + x6 <= 9
8893 */
8894 if( weights[v] > 1 || (weights[startv] > (SCIP_Longint)nvars - v) || (startv > 0 && weights[0] == (SCIP_Longint)nvars - v + 1) )
8895 {
8896 SCIP_Longint newcap;
8897
8898 /* adjust smallest coefficients, which all together do not exceed the dualcapacity */
8899 for( w = nvars - 1; w >= v; --w )
8900 {
8901 if( weights[w] > 1 )
8902 {
8903 consdataChgWeight(consdata, w, 1LL);
8904 ++(*nchgcoefs);
8905 }
8906 }
8907
8908 /* adjust middle sized coefficients, which when choosing also one small coefficients exceed the
8909 * dualcapacity
8910 */
8912 assert(newweight > 1);
8913 for( ; w >= startv; --w )
8914 {
8915 if( weights[w] > newweight )
8916 {
8917 consdataChgWeight(consdata, w, newweight);
8918 ++(*nchgcoefs);
8919 }
8920 else
8921 assert(weights[w] == newweight);
8922 }
8923
8924 /* adjust big sized coefficients, where each of them exceeds the dualcapacity by itself */
8925 ++newweight;
8926 assert(newweight > 2);
8927 for( ; w >= 0; --w )
8928 {
8929 if( weights[w] > newweight )
8930 {
8931 consdataChgWeight(consdata, w, newweight);
8932 ++(*nchgcoefs);
8933 }
8934 else
8935 assert(weights[w] == newweight);
8936 }
8937
8938 /* update the capacity */
8939 newcap = ((SCIP_Longint)startv - 1) * newweight + ((SCIP_Longint)v - startv) * (newweight - 1) + ((SCIP_Longint)nvars - v);
8940 if( consdata->capacity > newcap )
8941 {
8942 consdata->capacity = newcap;
8943 ++(*nchgsides);
8944 }
8945 else
8946 assert(consdata->capacity == newcap);
8947 }
8948 assert(weights[v] == 1 && (weights[startv] == (SCIP_Longint)nvars - v) && (startv == 0 || weights[0] == (SCIP_Longint)nvars - v + 1));
8949
8950 /* the new dualcapacity should still be equal to the (nvars - v + 1) */
8951 assert(consdata->weightsum - consdata->capacity == (SCIP_Longint)nvars - v + 1);
8952
8953 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8954 * weight must not be sorted by their index
8955 */
8956#ifndef NDEBUG
8957 for( w = nvars - 1; w > 0; --w )
8958 assert(weights[w] <= weights[w - 1]);
8959#endif
8960 return SCIP_OKAY;
8961 }
8962
8963 /* check if all rear items have the same weight as the last one, so we cannot tighten the constraint further */
8964 end = nvars - 2;
8965 while( end >= 0 && weights[end] == weights[end + 1] )
8966 {
8967 assert(end >= v);
8968 --end;
8969 }
8970
8971 if( v >= end )
8972 goto TERMINATE;
8973
8974 end = nvars - 2;
8975
8976 /* can we stop early, another special reduction case might exist */
8977 if( 2 * weights[end] > dualcapacity )
8978 {
8979 restsumweights = 0;
8980
8981 /* determine capacity of the small items */
8982 for( w = end + 1; w < nvars; ++w )
8983 restsumweights += weights[w];
8984
8985 if( restsumweights * 2 <= dualcapacity )
8986 {
8987 /* check for further posssible reductions in the middle */
8988 while( v < end && restsumweights + weights[v] >= dualcapacity )
8989 ++v;
8990
8991 if( v >= end )
8992 goto TERMINATE;
8993
8994 /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
8995 if( (dualcapacity & 1) == 0 )
8996 {
8997 newweight = dualcapacity / 2;
8998
8999 /* set all middle coefficients */
9000 for( ; v <= end; ++v )
9001 {
9002 if( weights[v] > newweight )
9003 {
9004 reductionsum += (weights[v] - newweight);
9005 consdataChgWeight(consdata, v, newweight);
9006 ++(*nchgcoefs);
9007 }
9008 }
9009 }
9010 /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
9011 * other coefficients by 2
9012 */
9013 else
9014 {
9015 /* correct the reductionsum */
9016 reductionsum *= 2;
9017
9018 /* multiply big coefficients by 2 */
9019 for( w = 0; w < v; ++w )
9020 {
9021 consdataChgWeight(consdata, w, weights[w] * 2);
9022 }
9023
9025 /* set all middle coefficients */
9026 for( ; v <= end; ++v )
9027 {
9028 reductionsum += (2 * weights[v] - newweight);
9029 consdataChgWeight(consdata, v, newweight);
9030 }
9031
9032 /* multiply small coefficients by 2 */
9033 for( w = end + 1; w < nvars; ++w )
9034 {
9035 consdataChgWeight(consdata, w, weights[w] * 2);
9036 }
9037 (*nchgcoefs) += nvars;
9038
9039 dualcapacity *= 2;
9040 consdata->capacity *= 2;
9041 ++(*nchgsides);
9042 }
9043 }
9044
9045 goto TERMINATE;
9046 }
9047
9048 /* further reductions using the next possible coefficient sum
9049 *
9050 * e.g. 9x1 + 8x2 + 7x3 + 3x4 + x5 <= 19 <=> 9~x1 + 8~x2 + 7~x3 + 3~x4 + ~x5 >= 9
9051 * <=> 9~x1 + 8~x2 + 6~x3 + 3~x4 + ~x5 >= 9
9052 * <=> 9x1 + 8x2 + 6x3 + 3x4 + x5 <= 18
9053 */
9054 /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
9055 for( k = 0; k < 4; ++k )
9056 {
9057 /* determine next minimal coefficient sum */
9058 switch( k )
9059 {
9060 case 0:
9061 sumcoef = weights[nvars - 1] + weights[nvars - 2];
9062 break;
9063 case 1:
9064 assert(nvars >= 3);
9065 sumcoef = weights[nvars - 1] + weights[nvars - 3];
9066 break;
9067 case 2:
9068 assert(nvars >= 4);
9069 if( weights[nvars - 1] + weights[nvars - 4] < weights[nvars - 2] + weights[nvars - 3] )
9070 {
9071 sumcoefcase = TRUE;
9072 sumcoef = weights[nvars - 1] + weights[nvars - 4];
9073 }
9074 else
9075 {
9077 sumcoef = weights[nvars - 2] + weights[nvars - 3];
9078 }
9079 break;
9080 case 3:
9081 assert(nvars >= 5);
9082 if( sumcoefcase )
9083 {
9084 sumcoef = MIN(weights[nvars - 1] + weights[nvars - 5], weights[nvars - 2] + weights[nvars - 3]);
9085 }
9086 else
9087 {
9088 sumcoef = MIN(weights[nvars - 1] + weights[nvars - 4], weights[nvars - 1] + weights[nvars - 2] + weights[nvars - 3]);
9089 }
9090 break;
9091 default:
9092 return SCIP_ERROR;
9093 }
9094
9095 /* tighten next coefficients that, pair with the current small coefficient, exceed the dualcapacity */
9096 minweight = weights[end];
9097 while( minweight <= sumcoef )
9098 {
9099 newweight = dualcapacity - minweight;
9100 startv = v;
9101 assert(v < nvars);
9102
9103 /* @todo check for further reductions, when two times the minweight exceeds the dualcapacity */
9104 /* shrink big coefficients */
9105 while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9106 {
9107 reductionsum += (weights[v] - newweight);
9108 consdataChgWeight(consdata, v, newweight);
9109 ++v;
9110 assert(v < nvars);
9111 }
9112 (*nchgcoefs) += (v - startv);
9113
9114 /* skip unchangable weights */
9115 while( weights[v] + minweight == dualcapacity )
9116 {
9117 assert(v < nvars);
9118 ++v;
9119 }
9120
9121 --end;
9122 /* skip same end weights */
9123 while( end >= 0 && weights[end] == weights[end + 1] )
9124 --end;
9125
9126 if( v >= end )
9127 goto TERMINATE;
9128
9129 minweight = weights[end];
9130 }
9131
9132 if( v >= end )
9133 goto TERMINATE;
9134
9135 /* now check if a combination of small coefficients allows us to tighten big coefficients further */
9136 if( sumcoef < minweight )
9137 {
9138 minweight = sumcoef;
9139 newweight = dualcapacity - minweight;
9140 startv = v;
9141 assert(v < nvars);
9142
9143 /* shrink big coefficients */
9144 while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9145 {
9146 reductionsum += (weights[v] - newweight);
9147 consdataChgWeight(consdata, v, newweight);
9148 ++v;
9149 assert(v < nvars);
9150 }
9151 (*nchgcoefs) += (v - startv);
9152
9153 /* skip unchangable weights */
9154 while( weights[v] + minweight == dualcapacity )
9155 {
9156 assert(v < nvars);
9157 ++v;
9158 }
9159 }
9160
9161 if( v >= end )
9162 goto TERMINATE;
9163
9164 /* can we stop early, another special reduction case might exist */
9165 if( 2 * weights[end] > dualcapacity )
9166 {
9167 restsumweights = 0;
9168
9169 /* determine capacity of the small items */
9170 for( w = end + 1; w < nvars; ++w )
9171 restsumweights += weights[w];
9172
9173 if( restsumweights * 2 <= dualcapacity )
9174 {
9175 /* check for further posssible reductions in the middle */
9176 while( v < end && restsumweights + weights[v] >= dualcapacity )
9177 ++v;
9178
9179 if( v >= end )
9180 goto TERMINATE;
9181
9182 /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
9183 if( (dualcapacity & 1) == 0 )
9184 {
9185 newweight = dualcapacity / 2;
9186
9187 /* set all middle coefficients */
9188 for( ; v <= end; ++v )
9189 {
9190 if( weights[v] > newweight )
9191 {
9192 reductionsum += (weights[v] - newweight);
9193 consdataChgWeight(consdata, v, newweight);
9194 ++(*nchgcoefs);
9195 }
9196 }
9197 }
9198 /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
9199 * other coefficients by 2
9200 */
9201 else
9202 {
9203 /* correct the reductionsum */
9204 reductionsum *= 2;
9205
9206 /* multiply big coefficients by 2 */
9207 for( w = 0; w < v; ++w )
9208 {
9209 consdataChgWeight(consdata, w, weights[w] * 2);
9210 }
9211
9213 /* set all middle coefficients */
9214 for( ; v <= end; ++v )
9215 {
9216 reductionsum += (2 * weights[v] - newweight);
9217 consdataChgWeight(consdata, v, newweight);
9218 }
9219
9220 /* multiply small coefficients by 2 */
9221 for( w = end + 1; w < nvars; ++w )
9222 {
9223 consdataChgWeight(consdata, w, weights[w] * 2);
9224 }
9225 (*nchgcoefs) += nvars;
9226
9227 dualcapacity *= 2;
9228 consdata->capacity *= 2;
9229 ++(*nchgsides);
9230 }
9231 }
9232
9233 goto TERMINATE;
9234 }
9235
9236 /* cannot tighten any further */
9237 if( 2 * sumcoef > dualcapacity )
9238 goto TERMINATE;
9239 }
9240 }
9241 }
9242
9243 TERMINATE:
9244 /* correct capacity */
9245 if( reductionsum > 0 )
9246 {
9247 assert(v > 0);
9248
9249 consdata->capacity -= reductionsum;
9250 ++(*nchgsides);
9251
9252 assert(consdata->weightsum - dualcapacity == consdata->capacity);
9253 }
9254 assert(weights[0] <= consdata->capacity);
9255
9256 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
9257 * weight must not be sorted by their index
9258 */
9259#ifndef NDEBUG
9260 for( w = nvars - 1; w > 0; --w )
9261 assert(weights[w] <= weights[w - 1]);
9262#endif
9263
9264 if( oldnchgcoefs < *nchgcoefs )
9265 {
9266 assert(!SCIPconsIsDeleted(cons));
9267
9268 /* it might be that we can divide the weights by their greatest common divisor */
9269 normalizeWeights(cons, nchgcoefs, nchgsides);
9270 }
9271 else
9272 {
9273 assert(oldnchgcoefs == *nchgcoefs);
9274 assert(oldnchgsides == *nchgsides);
9275 }
9276
9277 return SCIP_OKAY;
9278}
9279
9280
9281/** fixes variables with weights bigger than the capacity and delete redundant constraints, also sort weights */
9282static
9284 SCIP* scip, /**< SCIP data structure */
9285 SCIP_CONS* cons, /**< knapsack constraint */
9286 int* nfixedvars, /**< pointer to store the amount of fixed variables */
9287 int* ndelconss, /**< pointer to store the amount of deleted constraints */
9288 int* nchgcoefs /**< pointer to store the amount of changed coefficients */
9289 )
9290{
9291 SCIP_VAR** vars;
9292 SCIP_CONSDATA* consdata;
9293 SCIP_Longint* weights;
9294 SCIP_Longint capacity;
9295 SCIP_Bool infeasible;
9296 SCIP_Bool fixed;
9297 int nvars;
9298 int v;
9299
9300 assert(scip != NULL);
9301 assert(cons != NULL);
9302 assert(nfixedvars != NULL);
9303 assert(ndelconss != NULL);
9304 assert(nchgcoefs != NULL);
9305
9306 consdata = SCIPconsGetData(cons);
9307 assert(consdata != NULL);
9308
9309 nvars = consdata->nvars;
9310
9311 /* no variables left, then delete constraint */
9312 if( nvars == 0 )
9313 {
9314 assert(consdata->capacity >= 0);
9315
9316 SCIP_CALL( SCIPdelCons(scip, cons) );
9317 ++(*ndelconss);
9318
9319 return SCIP_OKAY;
9320 }
9321
9322 /* sort items */
9323 sortItems(consdata);
9324
9325 vars = consdata->vars;
9326 weights = consdata->weights;
9327 capacity = consdata->capacity;
9328 v = 0;
9329
9330 /* check for weights bigger than the capacity */
9331 while( v < nvars && weights[v] > capacity )
9332 {
9333 SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, &infeasible, &fixed) );
9334 assert(!infeasible);
9335
9336 if( fixed )
9337 ++(*nfixedvars);
9338
9339 ++v;
9340 }
9341
9342 /* if we fixed at least one variable we need to delete them from the constraint */
9343 if( v > 0 )
9344 {
9345 if( v == nvars )
9346 {
9347 SCIP_CALL( SCIPdelCons(scip, cons) );
9348 ++(*ndelconss);
9349
9350 return SCIP_OKAY;
9351 }
9352
9353 /* delete all position from back to front */
9354 for( --v; v >= 0; --v )
9355 {
9356 SCIP_CALL( delCoefPos(scip, cons, v) );
9357 ++(*nchgcoefs);
9358 }
9359
9360 /* sort items again because of deletion */
9361 sortItems(consdata);
9362 assert(vars == consdata->vars);
9363 assert(weights == consdata->weights);
9364 }
9365 assert(consdata->sorted);
9366 assert(weights[0] <= capacity);
9367
9368 if( !SCIPisHugeValue(scip, (SCIP_Real) capacity) && consdata->weightsum <= capacity )
9369 {
9370 SCIP_CALL( SCIPdelCons(scip, cons) );
9371 ++(*ndelconss);
9372 }
9373
9374 return SCIP_OKAY;
9375}
9376
9377
9378/** tries to simplify weights and delete redundant variables in knapsack a^Tx <= capacity
9379 *
9380 * 1. use the duality between a^Tx <= capacity <=> -a^T~x <= capacity - weightsum to tighten weights, e.g.
9381 *
9382 * 11x1 + 10x2 + 7x3 + 5x4 + 5x5 <= 25 <=> -10~x1 - 10~x2 - 7~x3 - 5~x4 - 5~x5 <= -13
9383 *
9384 * the above constraint can be changed to
9385 *
9386 * -8~x1 - 8~x2 - 7~x3 - 5~x4 - 5~x5 <= -12 <=> 8x1 + 8x2 + 7x3 + 5x4 + 5x5 <= 20
9387 *
9388 * 2. if variables in a constraint do not affect the (in-)feasibility of the constraint, we can delete them, e.g.
9389 *
9390 * 7x1 + 6x2 + 5x3 + 5x4 + x5 + x6 <= 20 => x5 and x6 are redundant and can be removed
9391 *
9392 * 3. Tries to use gcd information an all but one weight to change this not-included weight and normalize the
9393 * constraint further, e.g.
9394 *
9395 * 9x1 + 6x2 + 6x3 + 5x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => 3x1 + 2x2 + 2x3 + 2x4 <= 4 => 4x1 + 2x2 + 2x3 + 2x4 <= 4
9396 * => 2x1 + x2 + x3 + x4 <= 2
9397 * 9x1 + 6x2 + 6x3 + 7x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => see above
9398 */
9399static
9401 SCIP* scip, /**< SCIP data structure */
9402 SCIP_CONS* cons, /**< knapsack constraint */
9403 int* nfixedvars, /**< pointer to store the amount of fixed variables */
9404 int* ndelconss, /**< pointer to store the amount of deleted constraints */
9405 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
9406 int* nchgsides, /**< pointer to store the amount of changed sides */
9407 int* naddconss, /**< pointer to count number of added constraints */
9408 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9409 )
9410{
9411 SCIP_VAR** vars;
9412 SCIP_CONSDATA* consdata;
9413 SCIP_Longint* weights;
9414 SCIP_Longint restweight;
9415 SCIP_Longint newweight;
9416 SCIP_Longint weight;
9417 SCIP_Longint oldgcd;
9418 SCIP_Longint rest;
9419 SCIP_Longint gcd;
9420 int oldnchgcoefs;
9421 int oldnchgsides;
9422 int candpos;
9423 int candpos2;
9424 int offsetv;
9425 int nvars;
9426 int v;
9427
9428 assert(scip != NULL);
9429 assert(cons != NULL);
9430 assert(nfixedvars != NULL);
9431 assert(ndelconss != NULL);
9432 assert(nchgcoefs != NULL);
9433 assert(nchgsides != NULL);
9434 assert(naddconss != NULL);
9435 assert(cutoff != NULL);
9437
9438 consdata = SCIPconsGetData(cons);
9439 assert( consdata != NULL );
9440
9441 *cutoff = FALSE;
9442
9443 /* remove double enties and also combinations of active and negated variables */
9445 assert(consdata->merged);
9446 if( *cutoff )
9447 return SCIP_OKAY;
9448
9449 assert(consdata->capacity >= 0);
9450
9451 /* fix variables with big coefficients and remove redundant constraints, sort weights */
9452 SCIP_CALL( prepareCons(scip, cons, nfixedvars, ndelconss, nchgcoefs) );
9453
9454 if( SCIPconsIsDeleted(cons) )
9455 return SCIP_OKAY;
9456
9457 if( !SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
9458 {
9459 /* 1. dual weights tightening */
9460 SCIP_CALL( dualWeightsTightening(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9461
9462 if( SCIPconsIsDeleted(cons) )
9463 return SCIP_OKAY;
9464 /* 2. delete redundant variables */
9465 SCIP_CALL( detectRedundantVars(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9466
9467 if( SCIPconsIsDeleted(cons) )
9468 return SCIP_OKAY;
9469 }
9470
9471 weights = consdata->weights;
9472 nvars = consdata->nvars;
9473
9474#ifndef NDEBUG
9475 /* constraint might not be sorted, but the weights are already sorted */
9476 for( v = nvars - 1; v > 0; --v )
9477 assert(weights[v] <= weights[v-1]);
9478#endif
9479
9480 /* determine greatest common divisor */
9481 gcd = weights[nvars - 1];
9482 for( v = nvars - 2; v >= 0 && gcd > 1; --v )
9483 {
9484 gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9485 }
9486
9487 /* divide the constraint by their greatest common divisor */
9488 if( gcd >= 2 )
9489 {
9490 for( v = nvars - 1; v >= 0; --v )
9491 {
9492 consdataChgWeight(consdata, v, weights[v]/gcd);
9493 }
9494 (*nchgcoefs) += nvars;
9495
9496 consdata->capacity /= gcd;
9497 (*nchgsides)++;
9498 }
9499 assert(consdata->nvars == nvars);
9500
9501 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal weight
9502 * must not be sorted by their index
9503 */
9504#ifndef NDEBUG
9505 for( v = nvars - 1; v > 0; --v )
9506 assert(weights[v] <= weights[v-1]);
9507#endif
9508
9509 /* 3. start gcd procedure for all variables */
9510 do
9511 {
9512 SCIPdebug( oldnchgcoefs = *nchgcoefs; )
9513 SCIPdebug( oldnchgsides = *nchgsides; )
9514
9515 vars = consdata->vars;
9516 weights = consdata->weights;
9517 nvars = consdata->nvars;
9518
9519 /* stop if we have two coefficients which are one in absolute value */
9520 if( weights[nvars - 1] == 1 && weights[nvars - 2] == 1 )
9521 return SCIP_OKAY;
9522
9523 v = 0;
9524 /* determine coefficients as big as the capacity, these we do not need to take into account when calculating the
9525 * gcd
9526 */
9527 while( weights[v] == consdata->capacity )
9528 {
9529 ++v;
9530 assert(v < nvars);
9531 }
9532
9533 /* all but one variable are as big as the capacity, this is handled elsewhere */
9534 if( v == nvars - 1 )
9535 return SCIP_OKAY;
9536
9537 offsetv = v;
9538
9539 gcd = -1;
9540 candpos = -1;
9541 candpos2 = -1;
9542
9543 /* calculate greatest common divisor over all integer and binary variables and determine the candidate where we might
9544 * change the coefficient
9545 */
9546 for( v = nvars - 1; v >= offsetv; --v )
9547 {
9548 weight = weights[v];
9549 assert(weight >= 1);
9550
9551 oldgcd = gcd;
9552
9553 if( gcd == -1 )
9554 {
9555 gcd = weights[v];
9556 assert(gcd >= 1);
9557 }
9558 else
9559 {
9560 /* calculate greatest common divisor for all variables */
9561 gcd = SCIPcalcGreComDiv(gcd, weight);
9562 }
9563
9564 /* if the greatest commmon divisor has become 1, we might have found the possible coefficient to change or we
9565 * can terminate
9566 */
9567 if( gcd == 1 )
9568 {
9569 /* found candidate */
9570 if( candpos == -1 )
9571 {
9572 gcd = oldgcd;
9573 candpos = v;
9574
9575 /* if both first coefficients have a gcd of 1, both are candidates for the coefficient change */
9576 if( v == nvars - 2 )
9577 candpos2 = v + 1;
9578 }
9579 /* two different variables lead to a gcd of one, so we cannot change a coefficient */
9580 else
9581 {
9582 if( candpos == v + 1 && candpos2 == v + 2 )
9583 {
9584 assert(candpos2 == nvars - 1);
9585
9586 /* take new candidates */
9587 candpos = candpos2;
9588
9589 /* recalculate gcd from scratch */
9590 gcd = weights[v+1];
9591 assert(gcd >= 1);
9592
9593 /* calculate greatest common divisor for variables */
9594 gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9595 if( gcd == 1 )
9596 return SCIP_OKAY;
9597 }
9598 else
9599 /* cannot determine a possible coefficient for reduction */
9600 return SCIP_OKAY;
9601 }
9602 }
9603 }
9604 assert(gcd >= 2);
9605
9606 /* we should have found one coefficient, that led to a gcd of 1, otherwise we could normalize the constraint
9607 * further
9608 */
9609 assert(((candpos >= offsetv) || (candpos == -1 && offsetv > 0)) && candpos < nvars);
9610
9611 /* determine the remainder of the capacity and the gcd */
9612 rest = consdata->capacity % gcd;
9613 assert(rest >= 0);
9614 assert(rest < gcd);
9615
9616 if( candpos == -1 )
9617 {
9618 /* we assume that the constraint was normalized */
9619 assert(rest > 0);
9620
9621 /* replace old with new capacity */
9622 consdata->capacity -= rest;
9623 ++(*nchgsides);
9624
9625 /* replace old big coefficients with new capacity */
9626 for( v = 0; v < offsetv; ++v )
9627 {
9628 consdataChgWeight(consdata, v, consdata->capacity);
9629 }
9630
9631 *nchgcoefs += offsetv;
9632 goto CONTINUE;
9633 }
9634
9635 /* determine the remainder of the coefficient candidate and the gcd */
9636 restweight = weights[candpos] % gcd;
9637 assert(restweight >= 1);
9639
9640 /* calculate new coefficient */
9641 if( restweight > rest )
9642 newweight = weights[candpos] - restweight + gcd;
9643 else
9644 newweight = weights[candpos] - restweight;
9645
9647
9648 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);
9649
9650 /* must not change weights and capacity if one variable would be removed and we have a big coefficient,
9651 * e.g., 11x1 + 6x2 + 6x3 + 5x4 <= 11 => gcd = 6, offsetv = 1 => newweight = 0, but we would lose x1 = 1 => x4 = 0
9652 */
9653 if( newweight == 0 && offsetv > 0 )
9654 return SCIP_OKAY;
9655
9656 if( rest > 0 )
9657 {
9658 /* replace old with new capacity */
9659 consdata->capacity -= rest;
9660 ++(*nchgsides);
9661
9662 /* replace old big coefficients with new capacity */
9663 for( v = 0; v < offsetv; ++v )
9664 {
9665 consdataChgWeight(consdata, v, consdata->capacity);
9666 }
9667
9668 *nchgcoefs += offsetv;
9669 }
9670
9671 if( newweight == 0 )
9672 {
9673 /* delete redundant coefficient */
9674 SCIP_CALL( delCoefPos(scip, cons, candpos) );
9675 assert(consdata->nvars == nvars - 1);
9676 --nvars;
9677 }
9678 else
9679 {
9680 /* replace old with new coefficient */
9682 }
9683 ++(*nchgcoefs);
9684
9685 assert(consdata->vars == vars);
9686 assert(consdata->nvars == nvars);
9687 assert(consdata->weights == weights);
9688
9689 CONTINUE:
9690 /* now constraint can be normalized, dividing it by the gcd */
9691 for( v = nvars - 1; v >= 0; --v )
9692 {
9693 consdataChgWeight(consdata, v, weights[v]/gcd);
9694 }
9695 (*nchgcoefs) += nvars;
9696
9697 consdata->capacity /= gcd;
9698 ++(*nchgsides);
9699
9701
9702 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));
9703 }
9704 while( nvars >= 2 );
9705
9706 return SCIP_OKAY;
9707}
9708
9709
9710/** inserts an element into the list of binary zero implications */
9711static
9713 SCIP* scip, /**< SCIP data structure */
9714 int** liftcands, /**< array of the lifting candidates */
9715 int* nliftcands, /**< number of lifting candidates */
9716 int** firstidxs, /**< array of first zeroitems indices */
9717 SCIP_Longint** zeroweightsums, /**< array of sums of weights of the implied-to-zero items */
9718 int** zeroitems, /**< pointer to zero items array */
9719 int** nextidxs, /**< pointer to array of next zeroitems indeces */
9720 int* zeroitemssize, /**< pointer to size of zero items array */
9721 int* nzeroitems, /**< pointer to length of zero items array */
9722 int probindex, /**< problem index of variable y in implication y == v -> x == 0 */
9723 SCIP_Bool value, /**< value v of variable y in implication */
9724 int knapsackidx, /**< index of variable x in knapsack */
9725 SCIP_Longint knapsackweight, /**< weight of variable x in knapsack */
9726 SCIP_Bool* memlimitreached /**< pointer to store whether the memory limit was reached */
9727 )
9728{
9729 int nzeros;
9730
9731 assert(liftcands != NULL);
9732 assert(liftcands[value] != NULL);
9734 assert(firstidxs != NULL);
9735 assert(firstidxs[value] != NULL);
9737 assert(zeroweightsums[value] != NULL);
9738 assert(zeroitems != NULL);
9739 assert(nextidxs != NULL);
9743 assert(0 <= probindex && probindex < SCIPgetNVars(scip) - SCIPgetNContVars(scip));
9745
9746 nzeros = *nzeroitems;
9747
9748 /* allocate enough memory */
9749 if( nzeros == *zeroitemssize )
9750 {
9751 /* we explicitly construct the complete implication graph where the knapsack variables are involved;
9752 * this can be too huge - abort on memory limit
9753 */
9755 {
9756 SCIPdebugMsg(scip, "memory limit of %d bytes reached in knapsack preprocessing - abort collecting zero items\n",
9757 *zeroitemssize);
9759 return SCIP_OKAY;
9760 }
9761 *zeroitemssize *= 2;
9765 }
9767
9768 if( *memlimitreached )
9770
9771 /* insert element */
9772 (*zeroitems)[nzeros] = knapsackidx;
9773 (*nextidxs)[nzeros] = firstidxs[value][probindex];
9774 if( firstidxs[value][probindex] == 0 )
9775 {
9776 liftcands[value][nliftcands[value]] = probindex;
9777 ++nliftcands[value];
9778 }
9779 firstidxs[value][probindex] = nzeros;
9780 ++(*nzeroitems);
9781 zeroweightsums[value][probindex] += knapsackweight;
9782
9783 return SCIP_OKAY;
9784}
9785
9786#define MAX_CLIQUELENGTH 50
9787/** applies rule (3) of the weight tightening procedure, which can lift other variables into the knapsack:
9788 * (3) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
9789 * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
9790 * if cliqueweightsum(xi == v) < capacity:
9791 * - fixing variable xi to v would make the knapsack constraint redundant
9792 * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
9793 * redundancy effect:
9794 * wi' := capacity - cliqueweightsum(xi == v)
9795 * this rule can also be applied to binary variables not in the knapsack!
9796 */
9797static
9799 SCIP* scip, /**< SCIP data structure */
9800 SCIP_CONS* cons, /**< knapsack constraint */
9801 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9802 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9803 )
9804{
9805 SCIP_CONSDATA* consdata;
9806 SCIP_VAR** binvars;
9807 int nbinvars;
9808 int* liftcands[2]; /* binary variables that have at least one entry in zeroitems */
9809 int* firstidxs[2]; /* first index in zeroitems for each binary variable/value pair, or zero for empty list */
9810 SCIP_Longint* zeroweightsums[2]; /* sums of weights of the implied-to-zero items */
9811 int* zeroitems; /* item number in knapsack that is implied to zero */
9812 int* nextidxs; /* next index in zeroitems for the same binary variable, or zero for end of list */
9813 int zeroitemssize;
9814 int nzeroitems;
9815 SCIP_Bool* zeroiteminserted[2];
9816 SCIP_Bool memlimitreached;
9817 int nliftcands[2];
9818 SCIP_Bool* cliqueused;
9819 SCIP_Bool* itemremoved;
9820 SCIP_Longint maxcliqueweightsum;
9821 SCIP_VAR** addvars;
9822 SCIP_Longint* addweights;
9823 SCIP_Longint addweightsum;
9824 int nvars;
9825 int cliquenum;
9826 int naddvars;
9827 int val;
9828 int i;
9829
9830 int* tmpindices;
9831 SCIP_Bool* tmpboolindices;
9832 int* tmpindices2;
9833 SCIP_Bool* tmpboolindices2;
9834 int* tmpindices3;
9835 SCIP_Bool* tmpboolindices3;
9836 int tmp;
9837 int tmp2;
9838 int tmp3;
9839 SCIP_CONSHDLR* conshdlr;
9840 SCIP_CONSHDLRDATA* conshdlrdata;
9841
9842 assert(nchgcoefs != NULL);
9844
9845 consdata = SCIPconsGetData(cons);
9846 assert(consdata != NULL);
9847 assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
9848 assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
9849 assert(consdata->nvars > 0);
9850 assert(consdata->merged);
9851
9852 nvars = consdata->nvars;
9853
9854 /* check if the knapsack has too many items/cliques for applying this costly method */
9855 if( (!consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE) || consdata->ncliques > MAX_USECLIQUES_SIZE )
9856 return SCIP_OKAY;
9857
9858 /* sort items, s.t. the heaviest one is in the first position */
9859 sortItems(consdata);
9860
9861 if( !consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE )
9862 return SCIP_OKAY;
9863
9864 /* we have to consider all integral variables since even integer and implicit integer variables can have binary bounds */
9866 assert(nbinvars > 0);
9867 binvars = SCIPgetVars(scip);
9868
9869 /* get conshdlrdata to use cleared memory */
9870 conshdlr = SCIPconsGetHdlr(cons);
9871 assert(conshdlr != NULL);
9872 conshdlrdata = SCIPconshdlrGetData(conshdlr);
9873 assert(conshdlrdata != NULL);
9874
9875 /* allocate temporary memory for the list of implied to zero variables */
9876 zeroitemssize = MIN(nbinvars, MAX_ZEROITEMS_SIZE); /* initial size of zeroitems buffer */
9879
9880 assert(conshdlrdata->ints1size > 0);
9881 assert(conshdlrdata->ints2size > 0);
9882 assert(conshdlrdata->longints1size > 0);
9883 assert(conshdlrdata->longints2size > 0);
9884
9885 /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9886 * than binary + integer variables existed at the presolving initialization method, but for example if you would
9887 * transform all integers into their binary representation then it maybe happens
9888 */
9889 if( conshdlrdata->ints1size < nbinvars )
9890 {
9891 int oldsize = conshdlrdata->ints1size;
9892
9893 conshdlrdata->ints1size = nbinvars;
9894 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints1, oldsize, conshdlrdata->ints1size) );
9895 BMSclearMemoryArray(&(conshdlrdata->ints1[oldsize]), conshdlrdata->ints1size - oldsize); /*lint !e866*/
9896 }
9897 if( conshdlrdata->ints2size < nbinvars )
9898 {
9899 int oldsize = conshdlrdata->ints2size;
9900
9901 conshdlrdata->ints2size = nbinvars;
9902 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints2, oldsize, conshdlrdata->ints2size) );
9903 BMSclearMemoryArray(&(conshdlrdata->ints2[oldsize]), conshdlrdata->ints2size - oldsize); /*lint !e866*/
9904 }
9905 if( conshdlrdata->longints1size < nbinvars )
9906 {
9907 int oldsize = conshdlrdata->longints1size;
9908
9909 conshdlrdata->longints1size = nbinvars;
9910 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints1, oldsize, conshdlrdata->longints1size) );
9911 BMSclearMemoryArray(&(conshdlrdata->longints1[oldsize]), conshdlrdata->longints1size - oldsize); /*lint !e866*/
9912 }
9913 if( conshdlrdata->longints2size < nbinvars )
9914 {
9915 int oldsize = conshdlrdata->longints2size;
9916
9917 conshdlrdata->longints2size = nbinvars;
9918 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints2, oldsize, conshdlrdata->longints2size) );
9919 BMSclearMemoryArray(&(conshdlrdata->longints2[oldsize]), conshdlrdata->longints2size - oldsize); /*lint !e866*/
9920 }
9921
9922 firstidxs[0] = conshdlrdata->ints1;
9923 firstidxs[1] = conshdlrdata->ints2;
9924 zeroweightsums[0] = conshdlrdata->longints1;
9925 zeroweightsums[1] = conshdlrdata->longints2;
9926
9927 /* check for cleared arrays, all entries are zero */
9928#ifndef NDEBUG
9929 for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9930 {
9931 assert(firstidxs[0][tmp] == 0);
9932 assert(firstidxs[1][tmp] == 0);
9933 assert(zeroweightsums[0][tmp] == 0);
9934 assert(zeroweightsums[1][tmp] == 0);
9935 }
9936#endif
9937
9940
9941 zeroitems[0] = -1; /* dummy element */
9942 nextidxs[0] = -1;
9943 nzeroitems = 1;
9944 nliftcands[0] = 0;
9945 nliftcands[1] = 0;
9946
9947 assert(conshdlrdata->bools1size > 0);
9948 assert(conshdlrdata->bools2size > 0);
9949
9950 /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9951 * than binary + integer variables existed at the presolving initialization method, but for example if you would
9952 * transform all integers into their binary representation then it maybe happens
9953 */
9954 if( conshdlrdata->bools1size < nbinvars )
9955 {
9956 int oldsize = conshdlrdata->bools1size;
9957
9958 conshdlrdata->bools1size = nbinvars;
9959 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools1, oldsize, conshdlrdata->bools1size) );
9960 BMSclearMemoryArray(&(conshdlrdata->bools1[oldsize]), conshdlrdata->bools1size - oldsize); /*lint !e866*/
9961 }
9962 if( conshdlrdata->bools2size < nbinvars )
9963 {
9964 int oldsize = conshdlrdata->bools2size;
9965
9966 conshdlrdata->bools2size = nbinvars;
9967 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools2, oldsize, conshdlrdata->bools2size) );
9968 BMSclearMemoryArray(&(conshdlrdata->bools2[oldsize]), conshdlrdata->bools2size - oldsize); /*lint !e866*/
9969 }
9970
9971 zeroiteminserted[0] = conshdlrdata->bools1;
9972 zeroiteminserted[1] = conshdlrdata->bools2;
9973
9974 /* check for cleared arrays, all entries are zero */
9975#ifndef NDEBUG
9976 for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9977 {
9978 assert(zeroiteminserted[0][tmp] == 0);
9979 assert(zeroiteminserted[1][tmp] == 0);
9980 }
9981#endif
9982
9983 SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices3, consdata->nvars) );
9985 SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices3, consdata->nvars) );
9989
9990 tmp2 = 0;
9991 tmp3 = 0;
9992
9994 for( i = 0; i < consdata->nvars && !memlimitreached; ++i )
9995 {
9996 SCIP_CLIQUE** cliques;
9997 SCIP_VAR* var;
9998 SCIP_Longint weight;
9999 SCIP_Bool value;
10000 int varprobindex;
10001 int ncliques;
10002 int j;
10003
10004 tmp = 0;
10005
10006 /* get corresponding active problem variable */
10007 var = consdata->vars[i];
10008 weight = consdata->weights[i];
10009 value = TRUE;
10013
10014 /* update the zeroweightsum */
10015 zeroweightsums[!value][varprobindex] += weight; /*lint !e514*/
10016 tmpboolindices3[tmp3] = !value;
10018 ++tmp3;
10019
10020 /* initialize the arrays of inserted zero items */
10021 /* first add the implications (~x == 1 -> x == 0) */
10022 {
10023 SCIP_Bool implvalue;
10024 int probindex;
10025
10026 probindex = SCIPvarGetProbindex(var);
10027 assert(0 <= probindex && probindex < nbinvars);
10028
10029 implvalue = !value;
10030
10031 /* insert the item into the list of the implied variable/value */
10032 assert( !zeroiteminserted[implvalue][probindex] );
10033
10034 if( firstidxs[implvalue][probindex] == 0 )
10035 {
10037 tmpindices2[tmp2] = probindex;
10038 ++tmp2;
10039 }
10041 &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
10042 &memlimitreached) );
10043 zeroiteminserted[implvalue][probindex] = TRUE;
10045 tmpindices[tmp] = probindex;
10046 ++tmp;
10047 }
10048
10049 /* get the cliques where the knapsack item is member of with value 1 */
10050 ncliques = SCIPvarGetNCliques(var, value);
10051 cliques = SCIPvarGetCliques(var, value);
10052 for( j = 0; j < ncliques && !memlimitreached; ++j )
10053 {
10055 SCIP_Bool* cliquevalues;
10056 int ncliquevars;
10057 int k;
10058
10059 ncliquevars = SCIPcliqueGetNVars(cliques[j]);
10060
10061 /* discard big cliques */
10063 continue;
10064
10065 cliquevars = SCIPcliqueGetVars(cliques[j]);
10067
10068 for( k = ncliquevars - 1; k >= 0; --k )
10069 {
10070 SCIP_Bool implvalue;
10071 int probindex;
10072
10073 if( var == cliquevars[k] )
10074 continue;
10075
10076 probindex = SCIPvarGetProbindex(cliquevars[k]);
10077 if( probindex == -1 )
10078 continue;
10079
10080 assert(0 <= probindex && probindex < nbinvars);
10082
10083 /* insert the item into the list of the clique variable/value */
10084 if( !zeroiteminserted[implvalue][probindex] )
10085 {
10086 if( firstidxs[implvalue][probindex] == 0 )
10087 {
10089 tmpindices2[tmp2] = probindex;
10090 ++tmp2;
10091 }
10092
10094 &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
10095 &memlimitreached) );
10096 zeroiteminserted[implvalue][probindex] = TRUE;
10098 tmpindices[tmp] = probindex;
10099 ++tmp;
10100
10101 if( memlimitreached )
10102 break;
10103 }
10104 }
10105 }
10106 /* clear zeroiteminserted */
10107 for( --tmp; tmp >= 0; --tmp)
10109 }
10111
10112 /* calculate the clique partition and the maximal sum of weights using the clique information */
10113 assert(consdata->sorted);
10114 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10115
10116 assert(conshdlrdata->bools3size > 0);
10117
10118 /* next if condition should normally not be true, because it means that presolving has created more binary variables
10119 * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10120 * method, but for example if you would transform all integers into their binary representation then it maybe happens
10121 */
10122 if( conshdlrdata->bools3size < consdata->nvars )
10123 {
10124 int oldsize = conshdlrdata->bools3size;
10125
10126 conshdlrdata->bools3size = consdata->nvars;;
10127 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools3, oldsize, conshdlrdata->bools3size) );
10128 BMSclearMemoryArray(&(conshdlrdata->bools3[oldsize]), conshdlrdata->bools3size - oldsize); /*lint !e866*/
10129 }
10130
10131 cliqueused = conshdlrdata->bools3;
10132
10133 /* check for cleared array, all entries are zero */
10134#ifndef NDEBUG
10135 for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10136 assert(cliqueused[tmp] == 0);
10137#endif
10138
10140 tmp = 0;
10141
10142 /* calculates maximal weight of cliques */
10143 for( i = 0; i < consdata->nvars; ++i )
10144 {
10145 cliquenum = consdata->cliquepartition[i];
10147
10148 if( !cliqueused[cliquenum] )
10149 {
10150 maxcliqueweightsum += consdata->weights[i];
10153 ++tmp;
10154 }
10155 }
10156 /* clear cliqueused */
10157 for( --tmp; tmp >= 0; --tmp)
10158 cliqueused[tmp] = FALSE;
10159
10160 assert(conshdlrdata->bools4size > 0);
10161
10162 /* next if condition should normally not be true, because it means that presolving has created more binary variables
10163 * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10164 * method, but for example if you would transform all integers into their binary representation then it maybe happens
10165 */
10166 if( conshdlrdata->bools4size < consdata->nvars )
10167 {
10168 int oldsize = conshdlrdata->bools4size;
10169
10170 conshdlrdata->bools4size = consdata->nvars;
10171 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools4, oldsize, conshdlrdata->bools4size) );
10172 BMSclearMemoryArray(&conshdlrdata->bools4[oldsize], conshdlrdata->bools4size - oldsize); /*lint !e866*/
10173 }
10174
10175 itemremoved = conshdlrdata->bools4;
10176
10177 /* check for cleared array, all entries are zero */
10178#ifndef NDEBUG
10179 for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10180 assert(itemremoved[tmp] == 0);
10181#endif
10182
10183 /* for each binary variable xi and each fixing v, calculate the cliqueweightsum and update the weight of the
10184 * variable in the knapsack (this is sequence-dependent because the new or modified weights have to be
10185 * included in subsequent cliqueweightsum calculations)
10186 */
10189 naddvars = 0;
10190 addweightsum = 0;
10191 for( val = 0; val < 2 && addweightsum < consdata->capacity; ++val )
10192 {
10193 for( i = 0; i < nliftcands[val] && addweightsum < consdata->capacity; ++i )
10194 {
10195 SCIP_Longint cliqueweightsum;
10196 int probindex;
10197 int idx;
10198 int j;
10199
10200 tmp = 0;
10201
10202 probindex = liftcands[val][i];
10203 assert(0 <= probindex && probindex < nbinvars);
10204
10205 /* ignore empty zero lists and variables that cannot be lifted anyways */
10206 if( firstidxs[val][probindex] == 0
10207 || maxcliqueweightsum - zeroweightsums[val][probindex] + addweightsum >= consdata->capacity )
10208 continue;
10209
10210 /* mark the items that are implied to zero by setting the current variable to the current value */
10211 for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10212 {
10213 assert(0 < idx && idx < nzeroitems);
10214 assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10215 itemremoved[zeroitems[idx]] = TRUE;
10216 }
10217
10218 /* calculate the residual cliqueweight sum */
10219 cliqueweightsum = addweightsum; /* the previously added items are single-element cliques */
10220 for( j = 0; j < consdata->nvars; ++j )
10221 {
10222 cliquenum = consdata->cliquepartition[j];
10224 if( !itemremoved[j] )
10225 {
10226 if( !cliqueused[cliquenum] )
10227 {
10228 cliqueweightsum += consdata->weights[j];
10231 ++tmp;
10232 }
10233
10234 if( cliqueweightsum >= consdata->capacity )
10235 break;
10236 }
10237 }
10238
10239 /* check if the weight of the variable/value can be increased */
10240 if( cliqueweightsum < consdata->capacity )
10241 {
10242 SCIP_VAR* var;
10243 SCIP_Longint weight;
10244
10245 /* insert the variable (with value TRUE) in the list of additional items */
10247 var = binvars[probindex];
10248 if( val == FALSE )
10249 {
10251 }
10252 weight = consdata->capacity - cliqueweightsum;
10253 addvars[naddvars] = var;
10254 addweights[naddvars] = weight;
10255 addweightsum += weight;
10256 naddvars++;
10257
10258 SCIPdebugMsg(scip, "knapsack constraint <%s>: adding lifted item %" SCIP_LONGINT_FORMAT "<%s>\n",
10259 SCIPconsGetName(cons), weight, SCIPvarGetName(var));
10260 }
10261
10262 /* clear itemremoved */
10263 for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10264 {
10265 assert(0 < idx && idx < nzeroitems);
10266 assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10267 itemremoved[zeroitems[idx]] = FALSE;
10268 }
10269 /* clear cliqueused */
10270 for( --tmp; tmp >= 0; --tmp)
10272 }
10273 }
10274
10275 /* clear part of zeroweightsums */
10276 for( --tmp3; tmp3 >= 0; --tmp3)
10278
10279 /* clear rest of zeroweightsums and firstidxs */
10280 for( --tmp2; tmp2 >= 0; --tmp2)
10281 {
10284 }
10285
10286 /* add all additional item weights */
10287 for( i = 0; i < naddvars; ++i )
10288 {
10289 SCIP_CALL( addCoef(scip, cons, addvars[i], addweights[i]) );
10290 }
10291 *nchgcoefs += naddvars;
10292
10293 if( naddvars > 0 )
10294 {
10295 /* if new items were added, multiple entries of the same variable are possible and we have to clean up the constraint */
10297 }
10298
10299 /* free temporary memory */
10311
10312 return SCIP_OKAY;
10313}
10314
10315/** tightens item weights and capacity in presolving:
10316 * given a knapsack sum(wi*xi) <= capacity
10317 * (1) let weightsum := sum(wi)
10318 * if weightsum - wi < capacity:
10319 * - not using item i would make the knapsack constraint redundant
10320 * - wi and capacity can be changed to have the same redundancy effect and the same results for
10321 * fixing xi to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10322 * - change coefficients:
10323 * wi' := weightsum - capacity
10324 * capacity' := capacity - (wi - wi')
10325 * (2) increase weights from front to back(sortation is necessary) if there is no space left for another weight
10326 * - determine the four(can be adjusted) minimal weightsums of the knapsack, i.e. in increasing order
10327 * weights[nvars - 1], weights[nvars - 2], MIN(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]),
10328 * MIN(MAX(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]), weights[nvars - 4]), note that there
10329 * can be multiple times the same weight, this can be improved
10330 * - check if summing up a minimal weightsum with a big weight exceeds the capacity, then we can increase the big
10331 * weight, to capacity - lastmininmalweightsum, e.g. :
10332 * 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19
10333 * -> minimal weightsums: 5, 5, 10, 10
10334 * -> 15 + 5 > 19 => increase 15 to 19 - 0 = 19
10335 * -> 10 + 10 > 19 => increase 10 to 19 - 5 = 14, resulting in
10336 * 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10337 * (3) let W(C) be the maximal weight of clique C,
10338 * cliqueweightsum := sum(W(C))
10339 * if cliqueweightsum - W(C) < capacity:
10340 * - not using any item of C would make the knapsack constraint redundant
10341 * - weights wi, i in C, and capacity can be changed to have the same redundancy effect and the same results for
10342 * fixing xi, i in C, to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10343 * - change coefficients:
10344 * delta := capacity - (cliqueweightsum - W(C))
10345 * wi' := max(wi - delta, 0)
10346 * capacity' := capacity - delta
10347 * This rule has to add the used cliques in order to ensure they are enforced - otherwise, the reduction might
10348 * introduce infeasible solutions.
10349 * (4) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
10350 * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
10351 * if cliqueweightsum(xi == v) < capacity:
10352 * - fixing variable xi to v would make the knapsack constraint redundant
10353 * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
10354 * redundancy effect:
10355 * wi' := capacity - cliqueweightsum(xi == v)
10356 * This rule can also be applied to binary variables not in the knapsack!
10357 * (5) if min{w} + wi > capacity:
10358 * - using item i would force to fix other items to zero
10359 * - wi can be increased to the capacity
10360 */
10361static
10363 SCIP* scip, /**< SCIP data structure */
10364 SCIP_CONS* cons, /**< knapsack constraint */
10365 SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
10366 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10367 int* nchgsides, /**< pointer to count number of side changes */
10368 int* naddconss, /**< pointer to count number of added constraints */
10369 int* ndelconss, /**< pointer to count number of deleted constraints */
10370 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
10371 )
10372{
10373 SCIP_CONSHDLRDATA* conshdlrdata;
10374 SCIP_CONSDATA* consdata;
10375 SCIP_Longint* weights;
10376 SCIP_Longint sumcoef;
10377 SCIP_Longint capacity;
10378 SCIP_Longint newweight;
10379 SCIP_Longint maxweight;
10380 SCIP_Longint minweight;
10381 SCIP_Bool sumcoefcase = FALSE;
10382 int startpos;
10383 int backpos;
10384 int nvars;
10385 int pos;
10386 int k;
10387 int i;
10388
10389 assert(nchgcoefs != NULL);
10390 assert(nchgsides != NULL);
10392
10393 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
10394 assert(conshdlrdata != NULL);
10395
10396 consdata = SCIPconsGetData(cons);
10397 assert(consdata != NULL);
10398 assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
10399 assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
10400 assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
10401 assert(consdata->nvars > 0);
10402
10404 if( *cutoff )
10405 return SCIP_OKAY;
10406
10407 /* apply rule (1) */
10408 if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10409 {
10410 do
10411 {
10412 assert(consdata->merged);
10413
10414 /* sort items, s.t. the heaviest one is in the first position */
10415 sortItems(consdata);
10416
10417 for( i = 0; i < consdata->nvars; ++i )
10418 {
10419 SCIP_Longint weight;
10420
10421 weight = consdata->weights[i];
10422 if( consdata->weightsum - weight < consdata->capacity )
10423 {
10424 newweight = consdata->weightsum - consdata->capacity;
10425 consdataChgWeight(consdata, i, newweight);
10426 consdata->capacity -= (weight - newweight);
10427 (*nchgcoefs)++;
10428 (*nchgsides)++;
10429 assert(!consdata->sorted);
10430 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",
10431 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, newweight,
10432 consdata->capacity + (weight-newweight), consdata->capacity);
10433 }
10434 else
10435 break;
10436 }
10437 }
10438 while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10439 }
10440
10441 /* check for redundancy */
10442 if( consdata->weightsum <= consdata->capacity )
10443 return SCIP_OKAY;
10444
10445 pos = 0;
10446 while( pos < consdata->nvars && consdata->weights[pos] == consdata->capacity )
10447 ++pos;
10448
10449 sumcoef = 0;
10450 weights = consdata->weights;
10451 nvars = consdata->nvars;
10452 capacity = consdata->capacity;
10453
10454 if( (presoltiming & (SCIP_PRESOLTIMING_FAST | SCIP_PRESOLTIMING_MEDIUM)) != 0 &&
10455 pos < nvars && weights[pos] + weights[pos + 1] > capacity )
10456 {
10457 /* further reductions using the next possible coefficient sum
10458 *
10459 * e.g. 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19 <=> 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10460 */
10461 /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
10462 for( k = 0; k < 4; ++k )
10463 {
10464 newweight = capacity - sumcoef;
10465
10466 /* determine next minimal coefficient sum */
10467 switch( k )
10468 {
10469 case 0:
10470 sumcoef = weights[nvars - 1];
10471 backpos = nvars - 1;
10472 break;
10473 case 1:
10474 sumcoef = weights[nvars - 2];
10475 backpos = nvars - 2;
10476 break;
10477 case 2:
10478 if( weights[nvars - 3] < weights[nvars - 1] + weights[nvars - 2] )
10479 {
10480 sumcoefcase = TRUE;
10481 sumcoef = weights[nvars - 3];
10482 backpos = nvars - 3;
10483 }
10484 else
10485 {
10487 sumcoef = weights[nvars - 1] + weights[nvars - 2];
10488 backpos = nvars - 2;
10489 }
10490 break;
10491 default:
10492 assert(k == 3);
10493 if( sumcoefcase )
10494 {
10495 if( weights[nvars - 4] < weights[nvars - 1] + weights[nvars - 2] )
10496 {
10497 sumcoef = weights[nvars - 4];
10498 backpos = nvars - 4;
10499 }
10500 else
10501 {
10502 sumcoef = weights[nvars - 1] + weights[nvars - 2];
10503 backpos = nvars - 2;
10504 }
10505 }
10506 else
10507 {
10508 sumcoef = weights[nvars - 3];
10509 backpos = nvars - 3;
10510 }
10511 break;
10512 }
10513
10514 if( backpos <= pos )
10515 break;
10516
10517 /* tighten next coefficients that, paired with the current small coefficient, exceed the capacity */
10518 maxweight = weights[pos];
10519 startpos = pos;
10520 while( 2 * maxweight > capacity && maxweight + sumcoef > capacity )
10521 {
10522 assert(newweight > weights[pos]);
10523
10524 SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10525 SCIPconsGetName(cons), maxweight, newweight);
10526
10527 consdataChgWeight(consdata, pos, newweight);
10528
10529 ++pos;
10530 assert(pos < nvars);
10531
10532 maxweight = weights[pos];
10533
10534 if( backpos <= pos )
10535 break;
10536 }
10537 (*nchgcoefs) += (pos - startpos);
10538
10539 /* skip unchangable weights */
10540 while( pos < nvars && weights[pos] + sumcoef == capacity )
10541 ++pos;
10542
10543 /* check special case were there is only one weight left to tighten
10544 *
10545 * e.g. 95x1 + 59x2 + 37x3 + 36x4 <= 95 (37 > 36)
10546 *
10547 * => 95x1 + 59x2 + 59x3 + 36x4 <= 95
10548 *
10549 * 197x1 + 120x2 + 77x3 + 10x4 <= 207 (here we cannot tighten the coefficient further)
10550 */
10551 if( pos + 1 == backpos && weights[pos] > sumcoef &&
10552 ((k == 0) || (k == 1 && weights[nvars - 1] + sumcoef + weights[pos] > capacity)) )
10553 {
10554 newweight = capacity - sumcoef;
10555 assert(newweight > weights[pos]);
10556
10557 SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10558 SCIPconsGetName(cons), maxweight, newweight);
10559
10560 consdataChgWeight(consdata, pos, newweight);
10561
10562 break;
10563 }
10564
10565 if( backpos <= pos )
10566 break;
10567 }
10568 }
10569
10570 /* apply rule (2) (don't apply, if the knapsack has too many items for applying this costly method) */
10571 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
10572 {
10573 if( conshdlrdata->disaggregation && consdata->nvars - pos <= MAX_USECLIQUES_SIZE && consdata->nvars >= 2 &&
10574 pos > 0 && (SCIP_Longint)consdata->nvars - pos <= consdata->capacity &&
10575 consdata->weights[pos - 1] == consdata->capacity && (pos == consdata->nvars || consdata->weights[pos] == 1) )
10576 {
10577 SCIP_VAR** clqvars;
10579 char name[SCIP_MAXSTRLEN];
10580 int* clqpart;
10581 int nclqvars;
10582 int nclq;
10583 int len;
10584 int c;
10585 int w;
10586
10587 assert(!SCIPconsIsDeleted(cons));
10588
10589 if( pos == consdata->nvars )
10590 {
10591 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
10592
10593 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, SCIPconsGetName(cons), pos, consdata->vars,
10597 SCIPconsIsStickingAtNode(cons)) );
10598
10601 ++(*naddconss);
10602
10603 /* delete old constraint */
10604 SCIP_CALL( SCIPdelCons(scip, cons) );
10605 ++(*ndelconss);
10606
10607 return SCIP_OKAY;
10608 }
10609
10610 len = consdata->nvars - pos;
10611
10612 /* allocate temporary memory */
10614
10615 /* calculate clique partition */
10616 SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[pos]), len, clqpart, &nclq) );
10617 assert(nclq <= len);
10618
10619#ifndef NDEBUG
10620 /* clique numbers must be at least as high as the index */
10621 for( w = 0; w < nclq; ++w )
10622 assert(clqpart[w] <= w);
10623#endif
10624
10625 SCIPdebugMsg(scip, "Disaggregating knapsack constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
10626
10627 /* allocate temporary memory */
10628 SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, pos + len - nclq + 1) );
10629
10630 /* copy corresponding variables with big coefficients */
10631 for( w = pos - 1; w >= 0; --w )
10632 clqvars[w] = consdata->vars[w];
10633
10634 /* create for each clique a set-packing constraint */
10635 for( c = 0; c < nclq; ++c )
10636 {
10637 nclqvars = pos;
10638
10639 for( w = c; w < len; ++w )
10640 {
10641 if( clqpart[w] == c )
10642 {
10643 assert(nclqvars < pos + len - nclq + 1);
10644 clqvars[nclqvars] = consdata->vars[w + pos];
10645 ++nclqvars;
10646 }
10647 }
10648
10649 assert(nclqvars > 1);
10650
10651 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, c);
10656 SCIPconsIsStickingAtNode(cons)) );
10657 SCIPdebugMsg(scip, " -> adding clique constraint: ");
10661 ++(*naddconss);
10662 }
10663
10664 /* delete old constraint */
10665 SCIP_CALL( SCIPdelCons(scip, cons) );
10666 ++(*ndelconss);
10667
10670
10671 return SCIP_OKAY;
10672 }
10673 else if( consdata->nvars <= MAX_USECLIQUES_SIZE || (consdata->cliquepartitioned && consdata->ncliques <= MAX_USECLIQUES_SIZE) )
10674 {
10675 SCIP_Longint* maxcliqueweights;
10676 SCIP_Longint* newweightvals;
10677 int* newweightidxs;
10678 SCIP_Longint cliqueweightsum;
10679
10680 SCIP_CALL( SCIPallocBufferArray(scip, &maxcliqueweights, consdata->nvars) );
10681 SCIP_CALL( SCIPallocBufferArray(scip, &newweightvals, consdata->nvars) );
10682 SCIP_CALL( SCIPallocBufferArray(scip, &newweightidxs, consdata->nvars) );
10683
10684 /* repeat as long as changes have been applied */
10685 do
10686 {
10687 int ncliques;
10688 int cliquenum;
10689 SCIP_Bool zeroweights;
10690
10691 assert(consdata->merged);
10692
10693 /* sort items, s.t. the heaviest one is in the first position */
10694 sortItems(consdata);
10695
10696 /* calculate a clique partition */
10697 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10698
10699 /* if there are only single element cliques, rule (2) is equivalent to rule (1) */
10700 if( consdata->cliquepartition[consdata->nvars - 1] == consdata->nvars - 1 )
10701 break;
10702
10703 /* calculate the maximal weight of the cliques and store the clique type */
10704 cliqueweightsum = 0;
10705 ncliques = 0;
10706
10707 for( i = 0; i < consdata->nvars; ++i )
10708 {
10709 SCIP_Longint weight;
10710
10711 cliquenum = consdata->cliquepartition[i];
10712 assert(0 <= cliquenum && cliquenum <= ncliques);
10713
10714 weight = consdata->weights[i];
10715 assert(weight > 0);
10716
10717 if( cliquenum == ncliques )
10718 {
10719 maxcliqueweights[ncliques] = weight;
10720 cliqueweightsum += weight;
10721 ++ncliques;
10722 }
10723
10724 assert(maxcliqueweights[cliquenum] >= weight);
10725 }
10726
10727 /* apply rule on every clique */
10729 for( i = 0; i < ncliques; ++i )
10730 {
10731 SCIP_Longint delta;
10732
10733 delta = consdata->capacity - (cliqueweightsum - maxcliqueweights[i]);
10734 if( delta > 0 )
10735 {
10736 SCIP_Longint newcapacity;
10737#ifndef NDEBUG
10738 SCIP_Longint newmincliqueweight;
10739#endif
10740 SCIP_Longint newminweightsuminclique;
10741 SCIP_Bool forceclique;
10742 int nnewweights;
10743 int j;
10744
10745 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",
10746 SCIPconsGetName(cons), i, maxcliqueweights[i], cliqueweightsum, consdata->capacity, delta);
10747 newcapacity = consdata->capacity - delta;
10749 nnewweights = 0;
10750#ifndef NDEBUG
10752 for( j = 0; j < i; ++j )
10753 assert(consdata->cliquepartition[j] < i); /* no element j < i can be in clique i */
10754#endif
10755 for( j = i; j < consdata->nvars; ++j )
10756 {
10757 if( consdata->cliquepartition[j] == i )
10758 {
10759 newweight = consdata->weights[j] - delta;
10760 newweight = MAX(newweight, 0);
10761
10762 /* cache the new weight */
10766 nnewweights++;
10767
10768#ifndef NDEBUG
10769 assert(newweight <= newmincliqueweight); /* items are sorted by non-increasing weight! */
10771#endif
10772 }
10773 }
10774
10775 /* check if our clique information results out of this knapsack constraint and if so check if we would loose the clique information */
10776 if( nnewweights > 1 )
10777 {
10778#ifndef NDEBUG
10780 assert(0 <= j && j < consdata->nvars);
10781 assert(consdata->cliquepartition[j] == i);
10783 assert(0 <= j && j < consdata->nvars);
10784 assert(consdata->cliquepartition[j] == i);
10785#endif
10786
10789
10790 /* check if these new two minimal weights both fit into the knapsack;
10791 * if this is true, we have to add a clique constraint in order to enforce the clique
10792 * (otherwise, the knapsack might have been one of the reasons for the clique, and the weight
10793 * reduction might be infeasible, i.e., allows additional solutions)
10794 */
10796 forceclique = TRUE;
10797 }
10798
10799 /* check if we really want to apply the change */
10800 if( conshdlrdata->disaggregation || !forceclique )
10801 {
10802 SCIPdebugMsg(scip, " -> change capacity from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT " (forceclique:%u)\n",
10803 consdata->capacity, newcapacity, forceclique);
10804 consdata->capacity = newcapacity;
10805 (*nchgsides)++;
10806
10807 for( k = 0; k < nnewweights; ++k )
10808 {
10809 j = newweightidxs[k];
10810 assert(0 <= j && j < consdata->nvars);
10811 assert(consdata->cliquepartition[j] == i);
10812
10813 /* apply the weight change */
10814 SCIPdebugMsg(scip, " -> change weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10815 SCIPvarGetName(consdata->vars[j]), consdata->weights[j], newweightvals[k]);
10816 consdataChgWeight(consdata, j, newweightvals[k]);
10817 (*nchgcoefs)++;
10818 assert(!consdata->sorted);
10820 }
10821 /* if before the weight update at least one pair of weights did not fit into the knapsack and now fits,
10822 * we have to make sure, the clique is enforced - the clique might have been constructed partially from
10823 * this constraint, and by reducing the weights, this clique information is not contained anymore in the
10824 * knapsack constraint
10825 */
10826 if( forceclique )
10827 {
10829 char name[SCIP_MAXSTRLEN];
10831
10833 for( k = 0; k < nnewweights; ++k )
10834 cliquevars[k] = consdata->vars[newweightidxs[k]];
10835
10836 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, i);
10841 SCIPconsIsStickingAtNode(cons)) );
10842 SCIPdebugMsg(scip, " -> adding clique constraint: ");
10847 (*naddconss)++;
10848 }
10849 }
10850 }
10851 }
10852 if( zeroweights )
10853 {
10855 }
10856 }
10857 while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10858
10859 /* free temporary memory */
10863
10864 /* check for redundancy */
10865 if( consdata->weightsum <= consdata->capacity )
10866 return SCIP_OKAY;
10867 }
10868 }
10869
10870 /* apply rule (3) */
10871 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
10872 {
10873 SCIP_CALL( tightenWeightsLift(scip, cons, nchgcoefs, cutoff) );
10874 }
10875
10876 /* check for redundancy */
10877 if( consdata->weightsum <= consdata->capacity )
10878 return SCIP_OKAY;
10879
10880 if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10881 {
10882 /* apply rule (4) (all but smallest weight) */
10883 assert(consdata->merged);
10884 sortItems(consdata);
10885 minweight = consdata->weights[consdata->nvars-1];
10886 for( i = 0; i < consdata->nvars-1; ++i )
10887 {
10888 SCIP_Longint weight;
10889
10890 weight = consdata->weights[i];
10891 assert(weight >= minweight);
10892 if( minweight + weight > consdata->capacity )
10893 {
10894 if( weight < consdata->capacity )
10895 {
10896 SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10897 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, consdata->capacity);
10898 assert(consdata->sorted);
10899 consdataChgWeight(consdata, i, consdata->capacity); /* this does not destroy the weight order! */
10900 assert(i == 0 || consdata->weights[i-1] >= consdata->weights[i]);
10901 consdata->sorted = TRUE;
10902 (*nchgcoefs)++;
10903 }
10904 }
10905 else
10906 break;
10907 }
10908
10909 /* apply rule (5) (smallest weight) */
10910 if( consdata->nvars >= 2 )
10911 {
10912 SCIP_Longint weight;
10913
10914 minweight = consdata->weights[consdata->nvars-2];
10915 weight = consdata->weights[consdata->nvars-1];
10916 assert(minweight >= weight);
10917 if( minweight + weight > consdata->capacity && weight < consdata->capacity )
10918 {
10919 SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10920 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[consdata->nvars-1]), weight, consdata->capacity);
10921 assert(consdata->sorted);
10922 consdataChgWeight(consdata, consdata->nvars-1, consdata->capacity); /* this does not destroy the weight order! */
10923 assert(minweight >= consdata->weights[consdata->nvars-1]);
10924 consdata->sorted = TRUE;
10925 (*nchgcoefs)++;
10926 }
10927 }
10928 }
10929
10930 return SCIP_OKAY;
10931}
10932
10933
10934#ifdef SCIP_DEBUG
10935static
10936void printClique(
10938 int ncliquevars
10939 )
10940{
10941 int b;
10942 SCIPdebugMessage("adding new Clique: ");
10943 for( b = 0; b < ncliquevars; ++b )
10945 SCIPdebugPrintf("\n");
10946}
10947#endif
10948
10949/** adds negated cliques of the knapsack constraint to the global clique table */
10950static
10952 SCIP*const scip, /**< SCIP data structure */
10953 SCIP_CONS*const cons, /**< knapsack constraint */
10954 SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
10955 int*const nbdchgs /**< pointer to count the number of performed bound changes */
10956 )
10957{
10958 SCIP_CONSDATA* consdata;
10959 SCIP_CONSHDLRDATA* conshdlrdata;
10962 SCIP_Longint* maxweights;
10963 SCIP_Longint* gainweights;
10965 SCIP_Bool* cliqueused;
10966 SCIP_Longint minactduetonegcliques;
10967 SCIP_Longint freecapacity;
10968 SCIP_Longint lastweight;
10969 SCIP_Longint beforelastweight;
10970 int nposcliquevars;
10971 int ncliquevars;
10972 int nvars;
10973 int nnegcliques;
10974 int lastcliqueused;
10975 int thisnbdchgs;
10976 int v;
10977 int w;
10978
10979 assert(scip != NULL);
10980 assert(cons != NULL);
10981 assert(cutoff != NULL);
10982 assert(nbdchgs != NULL);
10983
10984 *cutoff = FALSE;
10985
10986 consdata = SCIPconsGetData(cons);
10987 assert(consdata != NULL);
10988
10989 nvars = consdata->nvars;
10990
10991 /* check whether the cliques have already been added */
10992 if( consdata->cliquesadded || nvars == 0 )
10993 return SCIP_OKAY;
10994
10995 /* make sure, the items are merged */
10997 if( *cutoff )
10998 return SCIP_OKAY;
10999
11000 /* make sure, items are sorted by non-increasing weight */
11001 sortItems(consdata);
11002
11003 assert(consdata->merged);
11004
11005 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11006 assert(conshdlrdata != NULL);
11007
11008 /* calculate a clique partition */
11009 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
11010 nnegcliques = consdata->nnegcliques;
11011
11012 /* if we have no negated cliques, stop */
11013 if( nnegcliques == nvars )
11014 return SCIP_OKAY;
11015
11016 /* get temporary memory */
11021 SCIP_CALL( SCIPallocBufferArray(scip, &maxweights, nnegcliques) );
11023
11024 nnegcliques = 0;
11026
11027 /* determine maximal weights for all negated cliques and calculate minimal weightsum due to negated cliques */
11028 for( v = 0; v < nvars; ++v )
11029 {
11030 assert(0 <= consdata->negcliquepartition[v] && consdata->negcliquepartition[v] <= nnegcliques);
11031 assert(consdata->weights[v] > 0);
11032
11033 if( consdata->negcliquepartition[v] == nnegcliques )
11034 {
11035 nnegcliques++;
11036 maxweights[consdata->negcliquepartition[v]] = consdata->weights[v];
11037 }
11038 else
11039 minactduetonegcliques += consdata->weights[v];
11040 }
11041
11042 nposcliquevars = 0;
11043
11044 /* add cliques, using negated cliques information */
11045 if( minactduetonegcliques > 0 )
11046 {
11047 /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11048 freecapacity = consdata->capacity - minactduetonegcliques;
11049
11051 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",
11052 SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11053
11054 /* calculate possible gain by switching chosen items in negated cliques */
11055 for( v = 0; v < nvars; ++v )
11056 {
11057 if( !cliqueused[consdata->negcliquepartition[v]] )
11058 {
11059 cliqueused[consdata->negcliquepartition[v]] = TRUE;
11060 for( w = v + 1; w < nvars; ++w )
11061 {
11062 /* if we would take the biggest weight instead of another what would we gain, take weight[v] instead of
11063 * weight[w] (which are both in a negated clique) */
11064 if( consdata->negcliquepartition[v] == consdata->negcliquepartition[w]
11065 && consdata->weights[v] > consdata->weights[w] )
11066 {
11067 poscliquevars[nposcliquevars] = consdata->vars[w];
11068 gainweights[nposcliquevars] = maxweights[consdata->negcliquepartition[v]] - consdata->weights[w];
11069 gaincliquepartition[nposcliquevars] = consdata->negcliquepartition[v];
11071 }
11072 }
11073 }
11074 }
11075
11076 /* try to create negated cliques */
11077 if( nposcliquevars > 0 )
11078 {
11079 /* sort possible gain per substitution of the clique members */
11081
11082 for( v = 0; v < nposcliquevars; ++v )
11083 {
11085 ncliquevars = 1;
11087 beforelastweight = -1;
11089 /* clear cliqueused to get an unused array */
11090 BMSclearMemoryArray(cliqueused, nnegcliques);
11092
11093 /* taking bigger weights make the knapsack redundant so we will create cliques, only take items which are not
11094 * in the same negated clique and by taking two of them would exceed the free capacity */
11096 {
11102 ++ncliquevars;
11103 }
11104
11105 if( ncliquevars > 1 )
11106 {
11109 /* add the clique to the clique table */
11110 /* this really happens, e.g., on enigma.mps from the short test set */
11112 if( *cutoff )
11113 goto TERMINATE;
11114 *nbdchgs += thisnbdchgs;
11115
11116 /* reset last used clique to get slightly different cliques */
11118
11119 /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11121 {
11125 if( *cutoff )
11126 goto TERMINATE;
11127 *nbdchgs += thisnbdchgs;
11128 }
11129 }
11130 }
11131 }
11132 }
11133
11134 TERMINATE:
11135 /* free temporary memory */
11142
11143 return SCIP_OKAY;
11144}
11145
11146/** greedy clique detection by considering weights and capacity
11147 *
11148 * greedily detects cliques by first sorting the items by decreasing weights (optional) and then collecting greedily
11149 * 1) neighboring items which exceed the capacity together => one clique
11150 * 2) looping through the remaining items and finding the largest set of preceding items to build a clique => possibly many more cliques
11151 */
11152static
11154 SCIP*const scip, /**< SCIP data structure */
11155 SCIP_VAR** items, /**< array of variable items */
11156 SCIP_Longint* weights, /**< weights of the items */
11157 int nitems, /**< the number of items */
11158 SCIP_Longint capacity, /**< maximum free capacity of the knapsack */
11159 SCIP_Bool sorteditems, /**< are the items sorted by their weights nonincreasing? */
11160 SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11161 SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11162 int*const nbdchgs /**< pointer to count the number of performed bound changes */
11163 )
11164{
11165 SCIP_Longint lastweight;
11166 int ncliquevars;
11167 int i;
11168 int thisnbdchgs;
11169
11170 if( nitems <= 1 )
11171 return SCIP_OKAY;
11172
11173 /* sort possible gain per substitution of the clique members */
11174 if( ! sorteditems )
11175 SCIPsortDownLongPtr(weights,(void**) items, nitems);
11176
11177 ncliquevars = 1;
11178 lastweight = weights[0];
11179
11180 /* taking these two weights together violates the knapsack => include into clique */
11181 for( i = 1; i < nitems && weights[i] + lastweight > capacity; ++i )
11182 {
11183 lastweight = weights[i];
11184 ++ncliquevars;
11185 }
11186
11187 if( ncliquevars > 1 )
11188 {
11189 SCIP_Longint compareweight;
11191 int compareweightidx;
11192 int minclqsize;
11193 int nnzadded;
11194
11195 /* add the clique to the clique table */
11198
11199 if( *cutoff )
11200 return SCIP_OKAY;
11201
11202 *nbdchgs += thisnbdchgs;
11204
11205 /* 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)*/
11206 if( ncliquevars == nitems )
11207 return SCIP_OKAY;
11208
11209 /* copy items in order into buffer array and deduce more cliques */
11211
11212 /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11213 /* loop over remaining, smaller items and compare each item backwards against larger weights, starting with the second smallest weight */
11215 assert(i == nitems || weights[i] + weights[ncliquevars - 1] <= capacity);
11216
11217 /* determine minimum clique size for the following loop */
11218 minclqsize = (int)(cliqueextractfactor * ncliquevars);
11220
11221 /* loop over the remaining variables and the larger items of the first clique until we
11222 * find another clique or reach the size limit */
11223 while( compareweightidx >= 0 && i < nitems && ! (*cutoff)
11224 && ncliquevars >= minclqsize /* stop at a given minimum clique size */
11225 && nnzadded <= 2 * nitems /* stop if enough nonzeros were added to the cliquetable */
11226 )
11227 {
11229 assert(compareweight > 0);
11230
11231 /* include this item together with all items that have a weight at least as large as the compare weight in a clique */
11232 if( compareweight + weights[i] > capacity )
11233 {
11235 cliquevars[ncliquevars - 1] = items[i];
11238
11240
11241 /* stop when there is a cutoff */
11242 if( ! (*cutoff) )
11243 *nbdchgs += thisnbdchgs;
11244
11245 /* go to next smaller item */
11246 ++i;
11247 }
11248 else
11249 {
11250 /* choose a preceding, larger weight to compare small items against. Clique size is reduced by 1 simultaneously */
11252 ncliquevars --;
11253 }
11254 }
11255
11257 }
11258
11259 return SCIP_OKAY;
11260}
11261
11262/** adds cliques of the knapsack constraint to the global clique table */
11263static
11265 SCIP*const scip, /**< SCIP data structure */
11266 SCIP_CONS*const cons, /**< knapsack constraint */
11267 SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11268 SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11269 int*const nbdchgs /**< pointer to count the number of performed bound changes */
11270 )
11271{
11272 SCIP_CONSDATA* consdata;
11273 SCIP_CONSHDLRDATA* conshdlrdata;
11274 int i;
11275 SCIP_Longint minactduetonegcliques;
11276 SCIP_Longint freecapacity;
11277 int nnegcliques;
11278 int cliquenum;
11280 SCIP_Longint* gainweights;
11281 int nposcliquevars;
11282 SCIP_Longint* secondmaxweights;
11283 int nvars;
11284
11285 assert(scip != NULL);
11286 assert(cons != NULL);
11287 assert(cutoff != NULL);
11288 assert(nbdchgs != NULL);
11289
11290 *cutoff = FALSE;
11291
11292 consdata = SCIPconsGetData(cons);
11293 assert(consdata != NULL);
11294
11295 nvars = consdata->nvars;
11296
11297 /* check whether the cliques have already been added */
11298 if( consdata->cliquesadded || nvars == 0 )
11299 return SCIP_OKAY;
11300
11301 /* make sure, the items are merged */
11303 if( *cutoff )
11304 return SCIP_OKAY;
11305
11306 /* make sure, the items are sorted by non-increasing weight */
11307 sortItems(consdata);
11308
11309 assert(consdata->merged);
11310
11311 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11312 assert(conshdlrdata != NULL);
11313
11314 /* calculate a clique partition */
11315 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
11316 nnegcliques = consdata->nnegcliques;
11317 assert(nnegcliques <= nvars);
11318
11319 /* get temporary memory */
11325
11327
11328 /* calculate minimal activity due to negated cliques, and determine second maximal weight in each clique */
11329 if( nnegcliques < nvars )
11330 {
11331 nnegcliques = 0;
11332
11333 for( i = 0; i < nvars; ++i )
11334 {
11335 SCIP_Longint weight;
11336
11337 cliquenum = consdata->negcliquepartition[i];
11338 assert(0 <= cliquenum && cliquenum <= nnegcliques);
11339
11340 weight = consdata->weights[i];
11341 assert(weight > 0);
11342
11343 if( cliquenum == nnegcliques )
11344 nnegcliques++;
11345 else
11346 {
11347 minactduetonegcliques += weight;
11348 if( secondmaxweights[cliquenum] == 0 )
11349 secondmaxweights[cliquenum] = weight;
11350 }
11351 }
11352 }
11353
11354 /* add cliques, using negated cliques information */
11355 if( minactduetonegcliques > 0 )
11356 {
11357 /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11358 freecapacity = consdata->capacity - minactduetonegcliques;
11359
11361 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",
11362 SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11363
11364 /* create negated cliques out of negated cliques, if we do not take the smallest weight of a cliques ... */
11365 SCIP_CALL( addNegatedCliques(scip, cons, cutoff, nbdchgs ) );
11366
11367 if( *cutoff )
11368 goto TERMINATE;
11369
11370 nposcliquevars = 0;
11371
11372 for( i = nvars - 1; i >= 0; --i )
11373 {
11374 /* if we would take the biggest weight instead of the second biggest */
11375 cliquenum = consdata->negcliquepartition[i];
11376 if( consdata->weights[i] > secondmaxweights[cliquenum] )
11377 {
11378 poscliquevars[nposcliquevars] = consdata->vars[i];
11379 gainweights[nposcliquevars] = consdata->weights[i] - secondmaxweights[cliquenum];
11381 }
11382 }
11383
11384 /* use the gain weights and free capacity to derive greedily cliques */
11385 if( nposcliquevars > 1 )
11386 {
11388
11389 if( *cutoff )
11390 goto TERMINATE;
11391 }
11392 }
11393
11394 /* build cliques by using the items with the maximal weights */
11395 SCIP_CALL( greedyCliqueAlgorithm(scip, consdata->vars, consdata->weights, nvars, consdata->capacity, TRUE, cliqueextractfactor, cutoff, nbdchgs) );
11396
11397 TERMINATE:
11398 /* free temporary memory and mark the constraint */
11402 consdata->cliquesadded = TRUE;
11403
11404 return SCIP_OKAY;
11405}
11406
11407
11408/** gets the key of the given element */
11409static
11411{ /*lint --e{715}*/
11412 /* the key is the element itself */
11413 return elem;
11414}
11415
11416/** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables and the
11417 * same coefficients
11418 */
11419static
11421{
11422#ifndef NDEBUG
11423 SCIP* scip;
11424#endif
11427 int i;
11428
11431 assert(consdata1->sorted);
11432 assert(consdata2->sorted);
11433#ifndef NDEBUG
11434 scip = (SCIP*)userptr;
11435 assert(scip != NULL);
11436#endif
11437
11438 /* checks trivial case */
11439 if( consdata1->nvars != consdata2->nvars )
11440 return FALSE;
11441
11442 for( i = consdata1->nvars - 1; i >= 0; --i )
11443 {
11444 /* tests if variables are equal */
11445 if( consdata1->vars[i] != consdata2->vars[i] )
11446 {
11447 assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 ||
11448 SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1);
11449 return FALSE;
11450 }
11451 assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 0);
11452
11453 /* tests if weights are equal too */
11454 if( consdata1->weights[i] != consdata2->weights[i] )
11455 return FALSE;
11456 }
11457
11458 return TRUE;
11459}
11460
11461/** returns the hash value of the key */
11462static
11464{
11465#ifndef NDEBUG
11466 SCIP* scip;
11467#endif
11468 SCIP_CONSDATA* consdata;
11469 uint64_t firstweight;
11470 int minidx;
11471 int mididx;
11472 int maxidx;
11473
11474 consdata = SCIPconsGetData((SCIP_CONS*)key);
11475 assert(consdata != NULL);
11476 assert(consdata->nvars > 0);
11477
11478#ifndef NDEBUG
11479 scip = (SCIP*)userptr;
11480 assert(scip != NULL);
11481#endif
11482
11483 /* sorts the constraints */
11484 sortItems(consdata);
11485
11486 minidx = SCIPvarGetIndex(consdata->vars[0]);
11487 mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]);
11488 maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]);
11489 assert(minidx >= 0 && mididx >= 0 && maxidx >= 0);
11490
11491 /* hash value depends on vectors of variable indices */
11492 firstweight = (uint64_t)consdata->weights[0];
11493 return SCIPhashSix(consdata->nvars, minidx, mididx, maxidx, firstweight>>32, firstweight);
11494}
11495
11496/** compares each constraint with all other constraints for possible redundancy and removes or changes constraint
11497 * accordingly; in contrast to preprocessConstraintPairs(), it uses a hash table
11498 */
11499static
11501 SCIP* scip, /**< SCIP data structure */
11502 BMS_BLKMEM* blkmem, /**< block memory */
11503 SCIP_CONS** conss, /**< constraint set */
11504 int nconss, /**< number of constraints in constraint set */
11505 SCIP_Bool* cutoff, /**< pointer to store whether the problem is infeasible */
11506 int* ndelconss /**< pointer to count number of deleted constraints */
11507 )
11508{
11509 SCIP_HASHTABLE* hashtable;
11510 int hashtablesize;
11511 int c;
11512
11513 assert(scip != NULL);
11514 assert(blkmem != NULL);
11515 assert(conss != NULL);
11516 assert(ndelconss != NULL);
11517
11518 /* create a hash table for the constraint set */
11519 hashtablesize = nconss;
11520 hashtablesize = MAX(hashtablesize, HASHSIZE_KNAPSACKCONS);
11521 SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize,
11523
11524 /* check all constraints in the given set for redundancy */
11525 for( c = nconss - 1; c >= 0; --c )
11526 {
11530
11531 cons0 = conss[c];
11532
11534 continue;
11535
11537 assert(consdata0 != NULL);
11538 if( consdata0->nvars == 0 )
11539 {
11540 if( consdata0->capacity < 0 )
11541 {
11542 *cutoff = TRUE;
11543 goto TERMINATE;
11544 }
11545 else
11546 {
11548 ++(*ndelconss);
11549 continue;
11550 }
11551 }
11552
11553 /* get constraint from current hash table with same variables and same weights as cons0 */
11554 cons1 = (SCIP_CONS*)(SCIPhashtableRetrieve(hashtable, (void*)cons0));
11555
11556 if( cons1 != NULL )
11557 {
11561
11564
11565 /* constraint found: create a new constraint with same coefficients and best left and right hand side;
11566 * delete old constraints afterwards
11567 */
11569
11570 assert(consdata1 != NULL);
11571 assert(consdata0->nvars > 0 && consdata0->nvars == consdata1->nvars);
11572
11573 assert(consdata0->sorted && consdata1->sorted);
11574 assert(consdata0->vars[0] == consdata1->vars[0]);
11575 assert(consdata0->weights[0] == consdata1->weights[0]);
11576
11577 SCIPdebugMsg(scip, "knapsack constraints <%s> and <%s> with equal coefficients\n",
11579
11580 /* check which constraint has to stay; */
11581 if( consdata0->capacity < consdata1->capacity )
11582 {
11583 consstay = cons0;
11584 consdel = cons1;
11585
11586 /* exchange consdel with consstay in hashtable */
11587 SCIP_CALL( SCIPhashtableRemove(hashtable, (void*) consdel) );
11588 SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) consstay) );
11589 }
11590 else
11591 {
11592 consstay = cons1;
11593 consdel = cons0;
11594 }
11595
11596 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11598
11599 /* delete consdel */
11601 ++(*ndelconss);
11602
11604 }
11605 else
11606 {
11607 /* no such constraint in current hash table: insert cons0 into hash table */
11608 SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) cons0) );
11609 }
11610 }
11611
11612 TERMINATE:
11613 /* free hash table */
11614 SCIPhashtableFree(&hashtable);
11615
11616 return SCIP_OKAY;
11617}
11618
11619
11620/** compares constraint with all prior constraints for possible redundancy or aggregation,
11621 * and removes or changes constraint accordingly
11622 */
11623static
11625 SCIP* scip, /**< SCIP data structure */
11626 SCIP_CONS** conss, /**< constraint set */
11627 int firstchange, /**< first constraint that changed since last pair preprocessing round */
11628 int chkind, /**< index of constraint to check against all prior indices upto startind */
11629 int* ndelconss /**< pointer to count number of deleted constraints */
11630 )
11631{
11634 int c;
11635
11636 assert(scip != NULL);
11637 assert(conss != NULL);
11639 assert(ndelconss != NULL);
11640
11641 /* get the constraint to be checked against all prior constraints */
11642 cons0 = conss[chkind];
11643 assert(cons0 != NULL);
11646
11648 assert(consdata0 != NULL);
11649 assert(consdata0->nvars >= 1);
11650 assert(consdata0->merged);
11651
11652 /* sort the constraint */
11654
11655 /* see #2970 */
11656 if( consdata0->capacity == 0 )
11657 return SCIP_OKAY;
11658
11659 /* check constraint against all prior constraints */
11660 for( c = (consdata0->presolvedtiming == SCIP_PRESOLTIMING_EXHAUSTIVE ? firstchange : 0); c < chkind; ++c )
11661 {
11664 SCIP_Bool iscons0incons1contained;
11665 SCIP_Bool iscons1incons0contained;
11666 SCIP_Real quotient;
11667 int v;
11668 int v0;
11669 int v1;
11670
11671 cons1 = conss[c];
11672 assert(cons1 != NULL);
11674 continue;
11675
11677 assert(consdata1 != NULL);
11678
11679 /* if both constraints didn't change since last pair processing, we can ignore the pair */
11680 if( consdata0->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE && consdata1->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE ) /*lint !e574*/
11681 continue;
11682
11683 assert(consdata1->nvars >= 1);
11684 assert(consdata1->merged);
11685
11686 /* sort the constraint */
11688
11689 /* see #2970 */
11690 if( consdata1->capacity == 0 )
11691 continue;
11692
11693 quotient = ((SCIP_Real) consdata0->capacity) / ((SCIP_Real) consdata1->capacity);
11694
11695 if( consdata0->nvars > consdata1->nvars )
11696 {
11699 v = consdata1->nvars - 1;
11700 }
11701 else if( consdata0->nvars < consdata1->nvars )
11702 {
11705 v = consdata0->nvars - 1;
11706 }
11707 else
11708 {
11711 v = consdata0->nvars - 1;
11712 }
11713
11714 SCIPdebugMsg(scip, "preprocess knapsack constraint pair <%s> and <%s>\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11715
11716 /* check consdata0 against consdata1:
11717 * 1. if all variables var_i of cons1 are in cons0 and for each of these variables
11718 * (consdata0->weights[i] / quotient) >= consdata1->weights[i] cons1 is redundant
11719 * 2. if all variables var_i of cons0 are in cons1 and for each of these variables
11720 * (consdata0->weights[i] / quotient) <= consdata1->weights[i] cons0 is redundant
11721 */
11722 v0 = consdata0->nvars - 1;
11723 v1 = consdata1->nvars - 1;
11724
11725 while( v >= 0 )
11726 {
11728
11729 /* now there are more variables in cons1 left */
11730 if( v1 > v0 )
11731 {
11734 break;
11735 }
11736 /* now there are more variables in cons0 left */
11737 else if( v1 < v0 )
11738 {
11741 break;
11742 }
11743
11744 assert(v == v0 || v == v1);
11745 assert(v0 >= 0);
11746 assert(v1 >= 0);
11747
11748 /* both variables are the same */
11749 if( consdata0->vars[v0] == consdata1->vars[v1] )
11750 {
11751 /* if cons1 is possible contained in cons0 (consdata0->weights[v0] / quotient) must be greater equals consdata1->weights[v1] */
11752 if( iscons1incons0contained && SCIPisLT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11753 {
11756 break;
11757 }
11758 /* if cons0 is possible contained in cons1 (consdata0->weight[v0] / quotient) must be less equals consdata1->weight[v1] */
11759 else if( iscons0incons1contained && SCIPisGT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11760 {
11763 break;
11764 }
11765 --v0;
11766 --v1;
11767 --v;
11768 }
11769 else
11770 {
11771 /* both constraints have a variables which is not part of the other constraint, so stop */
11773 {
11776 break;
11777 }
11780 /* continue to the next variable */
11782 --v1;
11783 else
11784 --v0;
11785 }
11786 }
11787 /* neither one constraint was contained in another or we checked all variables of one constraint against the
11788 * other
11789 */
11791
11793 {
11794 SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons1));
11796
11797 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11799
11801 ++(*ndelconss);
11802 }
11803 else if( iscons0incons1contained )
11804 {
11805 SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons0));
11807
11808 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11810
11812 ++(*ndelconss);
11813 break;
11814 }
11815 }
11816
11817 return SCIP_OKAY;
11818}
11819
11820/** helper function to enforce constraints */
11821static
11823 SCIP* scip, /**< SCIP data structure */
11824 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11825 SCIP_CONS** conss, /**< constraints to process */
11826 int nconss, /**< number of constraints */
11827 int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
11828 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
11829 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
11830 )
11831{
11832 SCIP_CONSHDLRDATA* conshdlrdata;
11833 SCIP_Bool violated;
11834 SCIP_Bool cutoff = FALSE;
11835 int maxncuts;
11836 int ncuts = 0;
11837 int i;
11838
11840
11841 SCIPdebugMsg(scip, "knapsack enforcement of %d/%d constraints for %s solution\n", nusefulconss, nconss,
11842 sol == NULL ? "LP" : "relaxation");
11843
11844 /* get maximal number of cuts per round */
11845 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11846 assert(conshdlrdata != NULL);
11847 maxncuts = (SCIPgetDepth(scip) == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
11848
11849 /* search for violated useful knapsack constraints */
11850 for( i = 0; i < nusefulconss && ncuts < maxncuts && ! cutoff; i++ )
11851 {
11852 SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11853 if( violated )
11854 {
11855 /* add knapsack constraint as LP row to the relaxation */
11856 SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11857 ncuts++;
11858 }
11859 }
11860
11861 /* as long as no violations were found, search for violated obsolete knapsack constraints */
11862 for( i = nusefulconss; i < nconss && ncuts == 0 && ! cutoff; i++ )
11863 {
11864 SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11865 if( violated )
11866 {
11867 /* add knapsack constraint as LP row to the relaxation */
11868 SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11869 ncuts++;
11870 }
11871 }
11872
11873 /* adjust the result code */
11874 if ( cutoff )
11876 else if ( ncuts > 0 )
11878
11879 return SCIP_OKAY;
11880}
11881
11882/*
11883 * Linear constraint upgrading
11884 */
11885
11886/** creates and captures a knapsack constraint out of a linear inequality */
11887static
11889 SCIP* scip, /**< SCIP data structure */
11890 SCIP_CONS** cons, /**< pointer to hold the created constraint */
11891 const char* name, /**< name of constraint */
11892 int nvars, /**< number of variables in the constraint */
11893 SCIP_VAR** vars, /**< array with variables of constraint entries */
11894 SCIP_Real* vals, /**< array with inequality coefficients */
11895 SCIP_Real lhs, /**< left hand side of inequality */
11896 SCIP_Real rhs, /**< right hand side of inequality */
11897 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11898 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11899 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11900 * Usually set to TRUE. */
11901 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11902 * TRUE for model constraints, FALSE for additional, redundant constraints. */
11903 SCIP_Bool check, /**< should the constraint be checked for feasibility?
11904 * TRUE for model constraints, FALSE for additional, redundant constraints. */
11905 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11906 * Usually set to TRUE. */
11907 SCIP_Bool local, /**< is constraint only valid locally?
11908 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11909 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11910 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11911 * adds coefficients to this constraint. */
11912 SCIP_Bool dynamic, /**< is constraint subject to aging?
11913 * Usually set to FALSE. Set to TRUE for own cuts which
11914 * are separated as constraints. */
11915 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
11916 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11917 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
11918 * if it may be moved to a more global node?
11919 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
11920 )
11921{
11923 SCIP_Longint* weights;
11924 SCIP_Longint capacity;
11925 SCIP_Longint weight;
11926 int mult;
11927 int v;
11928
11929 assert(nvars == 0 || vars != NULL);
11930 assert(nvars == 0 || vals != NULL);
11931 assert(SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11932
11933 /* get temporary memory */
11936
11937 /* if the right hand side is non-infinite, we have to negate all variables with negative coefficient;
11938 * otherwise, we have to negate all variables with positive coefficient and multiply the row with -1
11939 */
11940 if( SCIPisInfinity(scip, rhs) )
11941 {
11942 mult = -1;
11943 capacity = (SCIP_Longint)SCIPfeasFloor(scip, -lhs);
11944 }
11945 else
11946 {
11947 mult = +1;
11948 capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
11949 }
11950
11951 /* negate positive or negative variables */
11952 for( v = 0; v < nvars; ++v )
11953 {
11954 assert(SCIPisFeasIntegral(scip, vals[v]));
11955 weight = mult * (SCIP_Longint)SCIPfeasFloor(scip, vals[v]);
11956 if( weight > 0 )
11957 {
11958 transvars[v] = vars[v];
11959 weights[v] = weight;
11960 }
11961 else
11962 {
11964 weights[v] = -weight; /*lint !e2704*/
11965 capacity -= weight;
11966 }
11967 assert(transvars[v] != NULL);
11968 }
11969
11970 /* create the constraint */
11971 SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, transvars, weights, capacity,
11972 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
11973
11974 /* free temporary memory */
11975 SCIPfreeBufferArray(scip, &weights);
11977
11978 return SCIP_OKAY;
11979}
11980
11981/** tries to upgrade a linear constraint into a knapsack constraint */
11982static
11984{ /*lint --e{715}*/
11985 SCIP_Bool upgrade;
11986
11987 assert(upgdcons != NULL);
11988
11989 /* check, if linear constraint can be upgraded to a knapsack constraint
11990 * - all variables must be binary
11991 * - all coefficients must be integral
11992 * - exactly one of the sides must be infinite
11993 * note that this includes the case of negative capacity, which has been
11994 * observed to occur, e.g., when upgrading a conflict constraint
11995 */
11998 && (SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11999
12000 if( upgrade )
12001 {
12002 SCIPdebugMsg(scip, "upgrading constraint <%s> to knapsack constraint\n", SCIPconsGetName(cons));
12003
12004 /* create the knapsack constraint (an automatically upgraded constraint is always unmodifiable) */
12011 }
12012
12013 return SCIP_OKAY;
12014}
12015
12016
12017/*
12018 * Callback methods of constraint handler
12019 */
12020
12021/** copy method for constraint handler plugins (called when SCIP copies plugins) */
12022/**! [SnippetConsCopyKnapsack] */
12023static
12025{ /*lint --e{715}*/
12026 assert(scip != NULL);
12027 assert(conshdlr != NULL);
12029
12030 /* call inclusion method of constraint handler */
12032
12033 *valid = TRUE;
12034
12035 return SCIP_OKAY;
12036}
12037/**! [SnippetConsCopyKnapsack] */
12038
12039/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12040/**! [SnippetConsFreeKnapsack] */
12041static
12043{ /*lint --e{715}*/
12044 SCIP_CONSHDLRDATA* conshdlrdata;
12045
12046 /* free constraint handler data */
12047 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12048 assert(conshdlrdata != NULL);
12049
12050 SCIPfreeBlockMemory(scip, &conshdlrdata);
12051
12052 SCIPconshdlrSetData(conshdlr, NULL);
12053
12054 return SCIP_OKAY;
12055}
12056/**! [SnippetConsFreeKnapsack] */
12057
12058
12059/** initialization method of constraint handler (called after problem was transformed) */
12060static
12062{ /*lint --e{715}*/
12063 SCIP_CONSHDLRDATA* conshdlrdata;
12064 int nvars;
12065
12066 assert( scip != NULL );
12067 assert( conshdlr != NULL );
12068
12069 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12070 assert(conshdlrdata != NULL);
12071
12072 /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12074
12075 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->reals1, nvars) );
12076 conshdlrdata->reals1size = nvars;
12077
12078 return SCIP_OKAY;
12079}
12080
12081/** deinitialization method of constraint handler (called before transformed problem is freed) */
12082static
12084{ /*lint --e{715}*/
12085 SCIP_CONSHDLRDATA* conshdlrdata;
12086
12087 assert( scip != NULL );
12088 assert( conshdlr != NULL );
12089
12090 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12091 assert(conshdlrdata != NULL);
12092
12093 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->reals1, conshdlrdata->reals1size);
12094 conshdlrdata->reals1size = 0;
12095
12096 return SCIP_OKAY;
12097}
12098
12099
12100/** presolving initialization method of constraint handler (called when presolving is about to begin) */
12101static
12103{ /*lint --e{715}*/
12104 SCIP_CONSHDLRDATA* conshdlrdata;
12105 int nvars;
12106
12107 assert(scip != NULL);
12108 assert(conshdlr != NULL);
12109 assert(nconss == 0 || conss != NULL);
12110
12111 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12112 assert(conshdlrdata != NULL);
12113
12114 /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12116
12117 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints1, nvars) );
12118 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints2, nvars) );
12119 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints1, nvars) );
12120 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints2, nvars) );
12121 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools1, nvars) );
12122 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools2, nvars) );
12123 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools3, nvars) );
12124 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools4, nvars) );
12125
12126 conshdlrdata->ints1size = nvars;
12127 conshdlrdata->ints2size = nvars;
12128 conshdlrdata->longints1size = nvars;
12129 conshdlrdata->longints2size = nvars;
12130 conshdlrdata->bools1size = nvars;
12131 conshdlrdata->bools2size = nvars;
12132 conshdlrdata->bools3size = nvars;
12133 conshdlrdata->bools4size = nvars;
12134
12135#ifdef WITH_CARDINALITY_UPGRADE
12136 conshdlrdata->upgradedcard = FALSE;
12137#endif
12138
12139 return SCIP_OKAY;
12140}
12141
12142
12143/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12144static
12146{ /*lint --e{715}*/
12147 SCIP_CONSHDLRDATA* conshdlrdata;
12148 int c;
12149
12150 assert(scip != NULL);
12151 assert(conshdlr != NULL);
12152
12153 for( c = 0; c < nconss; ++c )
12154 {
12155 if( !SCIPconsIsDeleted(conss[c]) )
12156 {
12157 /* since we are not allowed to detect infeasibility in the exitpre stage, we dont give an infeasible pointer */
12158 SCIP_CALL( applyFixings(scip, conss[c], NULL) );
12159 }
12160 }
12161
12162 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12163 assert(conshdlrdata != NULL);
12164
12165 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints1, conshdlrdata->ints1size);
12166 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints2, conshdlrdata->ints2size);
12167 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints1, conshdlrdata->longints1size);
12168 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints2, conshdlrdata->longints2size);
12169 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools1, conshdlrdata->bools1size);
12170 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools2, conshdlrdata->bools2size);
12171 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools3, conshdlrdata->bools3size);
12172 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools4, conshdlrdata->bools4size);
12173
12174 conshdlrdata->ints1size = 0;
12175 conshdlrdata->ints2size = 0;
12176 conshdlrdata->longints1size = 0;
12177 conshdlrdata->longints2size = 0;
12178 conshdlrdata->bools1size = 0;
12179 conshdlrdata->bools2size = 0;
12180 conshdlrdata->bools3size = 0;
12181 conshdlrdata->bools4size = 0;
12182
12183 return SCIP_OKAY;
12184}
12185
12186/** solving process initialization method of constraint handler */
12187static
12189{ /*lint --e{715}*/
12190 /* add nlrow representation to NLP, if NLP had been constructed */
12192 {
12193 int c;
12194 for( c = 0; c < nconss; ++c )
12195 {
12196 SCIP_CALL( addNlrow(scip, conss[c]) );
12197 }
12198 }
12199
12200 return SCIP_OKAY;
12201}
12202
12203/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12204static
12206{ /*lint --e{715}*/
12207 SCIP_CONSDATA* consdata;
12208 int c;
12209
12210 assert( scip != NULL );
12211
12212 /* release the rows and nlrows of all constraints */
12213 for( c = 0; c < nconss; ++c )
12214 {
12215 consdata = SCIPconsGetData(conss[c]);
12216 assert(consdata != NULL);
12217
12218 if( consdata->row != NULL )
12219 {
12220 SCIP_CALL( SCIPreleaseRow(scip, &consdata->row) );
12221 }
12222
12223 if( consdata->nlrow != NULL )
12224 {
12225 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
12226 }
12227 }
12228
12229 return SCIP_OKAY;
12230}
12231
12232/** frees specific constraint data */
12233static
12235{ /*lint --e{715}*/
12236 SCIP_CONSHDLRDATA* conshdlrdata;
12237
12238 assert(conshdlr != NULL);
12240
12241 /* get event handler */
12242 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12243 assert(conshdlrdata != NULL);
12244 assert(conshdlrdata->eventhdlr != NULL);
12245
12246 /* free knapsack constraint */
12247 SCIP_CALL( consdataFree(scip, consdata, conshdlrdata->eventhdlr) );
12248
12249 return SCIP_OKAY;
12250}
12251
12252/** transforms constraint data into data belonging to the transformed problem */
12253/**! [SnippetConsTransKnapsack]*/
12254static
12256{ /*lint --e{715}*/
12257 SCIP_CONSHDLRDATA* conshdlrdata;
12260
12261 assert(conshdlr != NULL);
12266
12269 assert(sourcedata->row == NULL); /* in original problem, there cannot be LP rows */
12270
12271 /* get event handler */
12272 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12273 assert(conshdlrdata != NULL);
12274 assert(conshdlrdata->eventhdlr != NULL);
12275
12276 /* create target constraint data */
12278 sourcedata->nvars, sourcedata->vars, sourcedata->weights, sourcedata->capacity) );
12279
12280 /* create target constraint */
12286
12287 /* catch events for variables */
12288 SCIP_CALL( catchEvents(scip, *targetcons, targetdata, conshdlrdata->eventhdlr) );
12289
12290 return SCIP_OKAY;
12291}
12292/**! [SnippetConsTransKnapsack]*/
12293
12294/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
12295static
12297{ /*lint --e{715}*/
12298 int i;
12299
12300 *infeasible = FALSE;
12301
12302 for( i = 0; i < nconss && !(*infeasible); i++ )
12303 {
12304 assert(SCIPconsIsInitial(conss[i]));
12305 SCIP_CALL( addRelaxation(scip, conss[i], infeasible) );
12306 }
12307
12308 return SCIP_OKAY;
12309}
12310
12311/** separation method of constraint handler for LP solutions */
12312static
12314{ /*lint --e{715}*/
12315 SCIP_CONSHDLRDATA* conshdlrdata;
12316 SCIP_Bool sepacardinality;
12317 SCIP_Bool cutoff;
12318
12319 SCIP_Real loclowerbound;
12320 SCIP_Real glblowerbound;
12321 SCIP_Real cutoffbound;
12322 SCIP_Real maxbound;
12323
12324 int depth;
12325 int nrounds;
12326 int sepafreq;
12327 int sepacardfreq;
12328 int ncuts;
12329 int maxsepacuts;
12330 int i;
12331
12333
12334 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12335 assert(conshdlrdata != NULL);
12336
12339
12340 SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12341 nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12342
12343 /* only call the separator a given number of times at each node */
12344 if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12345 || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12346 return SCIP_OKAY;
12347
12348 /* check, if we should additionally separate knapsack cuts */
12349 sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12350 sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12351 sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12352 && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12353
12354 /* check dual bound to see if we want to produce knapsack cuts at this node */
12357 cutoffbound = SCIPgetCutoffbound(scip);
12358 maxbound = glblowerbound + conshdlrdata->maxcardbounddist * (cutoffbound - glblowerbound);
12361
12362 /* get the maximal number of cuts allowed in a separation round */
12363 maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12364
12366 ncuts = 0;
12367 cutoff = FALSE;
12368
12369 /* separate useful constraints */
12370 for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12371 {
12372 SCIP_CALL( separateCons(scip, conss[i], NULL, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12373 }
12374
12375 /* adjust return value */
12376 if ( cutoff )
12378 else if ( ncuts > 0 )
12380
12381 return SCIP_OKAY;
12382}
12383
12384
12385/** separation method of constraint handler for arbitrary primal solutions */
12386static
12388{ /*lint --e{715}*/
12389 SCIP_CONSHDLRDATA* conshdlrdata;
12390 SCIP_Bool sepacardinality;
12391 SCIP_Bool cutoff;
12392
12393 int depth;
12394 int nrounds;
12395 int sepafreq;
12396 int sepacardfreq;
12397 int ncuts;
12398 int maxsepacuts;
12399 int i;
12400
12402
12403 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12404 assert(conshdlrdata != NULL);
12405
12408
12409 SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12410 nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12411
12412 /* only call the separator a given number of times at each node */
12413 if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12414 || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12415 return SCIP_OKAY;
12416
12417 /* check, if we should additionally separate knapsack cuts */
12418 sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12419 sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12420 sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12421 && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12422
12423 /* get the maximal number of cuts allowed in a separation round */
12424 maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12425
12427 ncuts = 0;
12428 cutoff = FALSE;
12429
12430 /* separate useful constraints */
12431 for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12432 {
12433 SCIP_CALL( separateCons(scip, conss[i], sol, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12434 }
12435
12436 /* adjust return value */
12437 if ( cutoff )
12439 else if( ncuts > 0 )
12441
12442 return SCIP_OKAY;
12443}
12444
12445/** constraint enforcing method of constraint handler for LP solutions */
12446static
12448{ /*lint --e{715}*/
12449 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, result) );
12450
12451 return SCIP_OKAY;
12452}
12453
12454/** constraint enforcing method of constraint handler for relaxation solutions */
12455static
12457{ /*lint --e{715}*/
12458 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, result) );
12459
12460 return SCIP_OKAY;
12461}
12462
12463/** constraint enforcing method of constraint handler for pseudo solutions */
12464static
12466{ /*lint --e{715}*/
12467 SCIP_Bool violated;
12468 int i;
12469
12470 for( i = 0; i < nconss; i++ )
12471 {
12472 SCIP_CALL( checkCons(scip, conss[i], NULL, TRUE, FALSE, &violated) );
12473 if( violated )
12474 {
12476 return SCIP_OKAY;
12477 }
12478 }
12480
12481 return SCIP_OKAY;
12482}
12483
12484/** feasibility check method of constraint handler for integral solutions */
12485static
12487{ /*lint --e{715}*/
12488 SCIP_Bool violated;
12489 int i;
12490
12492
12493 for( i = 0; i < nconss && (*result == SCIP_FEASIBLE || completely); i++ )
12494 {
12495 SCIP_CALL( checkCons(scip, conss[i], sol, checklprows, printreason, &violated) );
12496 if( violated )
12498 }
12499
12500 return SCIP_OKAY;
12501}
12502
12503/** domain propagation method of constraint handler */
12504static
12506{ /*lint --e{715}*/
12507 SCIP_CONSHDLRDATA* conshdlrdata;
12508 SCIP_Bool cutoff;
12509 SCIP_Bool redundant;
12510 SCIP_Bool inpresolve;
12511 int nfixedvars;
12512 int i;
12513
12514 cutoff = FALSE;
12515 nfixedvars = 0;
12516
12517 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12518 assert(conshdlrdata != NULL);
12519
12522
12523 /* process useful constraints */
12524 for( i = 0; i < nmarkedconss && !cutoff; i++ )
12525 {
12526 /* do not propagate constraints with multi-aggregated variables, which should only happen in probing mode,
12527 * otherwise the multi-aggregation should be resolved
12528 */
12529 if( inpresolve && SCIPconsGetData(conss[i])->existmultaggr )
12530 continue;
12531#ifndef NDEBUG
12532 else
12533 assert(!(SCIPconsGetData(conss[i])->existmultaggr));
12534#endif
12535
12536 SCIP_CALL( propagateCons(scip, conss[i], &cutoff, &redundant, &nfixedvars, conshdlrdata->negatedclique) );
12537
12538 /* unmark the constraint to be propagated */
12540 }
12541
12542 /* adjust result code */
12543 if( cutoff )
12545 else if( nfixedvars > 0 )
12547 else
12549
12550 return SCIP_OKAY; /*lint !e438*/
12551}
12552
12553/** presolving method of constraint handler */
12554static
12556{ /*lint --e{574,715}*/
12557 SCIP_CONSHDLRDATA* conshdlrdata;
12558 SCIP_CONSDATA* consdata;
12559 SCIP_CONS* cons;
12560 SCIP_Bool cutoff;
12561 SCIP_Bool redundant;
12562 SCIP_Bool success;
12563 int oldnfixedvars;
12564 int oldnchgbds;
12565 int oldndelconss;
12566 int oldnaddconss;
12567 int oldnchgcoefs;
12568 int oldnchgsides;
12569 int firstchange;
12570 int c;
12571 SCIP_Bool newchanges;
12572
12573 /* remember old preprocessing counters */
12574 cutoff = FALSE;
12575 oldnfixedvars = *nfixedvars;
12576 oldnchgbds = *nchgbds;
12577 oldndelconss = *ndelconss;
12578 oldnaddconss = *naddconss;
12579 oldnchgcoefs = *nchgcoefs;
12580 oldnchgsides = *nchgsides;
12582
12583 newchanges = (nrounds == 0 || nnewfixedvars > 0 || nnewaggrvars > 0 || nnewchgbds > 0 || nnewupgdconss > 0);
12584
12585 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12586 assert(conshdlrdata != NULL);
12587
12588 for( c = 0; c < nconss && !SCIPisStopped(scip); c++ )
12589 {
12590 int thisnfixedvars;
12591 int thisnchgbds;
12592
12593 cons = conss[c];
12594 consdata = SCIPconsGetData(cons);
12595 assert(consdata != NULL);
12596
12597 /* update data structures */
12598 /* todo if UBTIGHTENED events were caught, we could move this block after the continue */
12599 if( newchanges || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12600 {
12601 SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12602 if( cutoff )
12603 break;
12604 }
12605
12606 /* force presolving the constraint in the initial round */
12607 if( nrounds == 0 )
12608 consdata->presolvedtiming = 0;
12609 else if( consdata->presolvedtiming >= presoltiming )
12610 continue;
12611
12612 SCIPdebugMsg(scip, "presolving knapsack constraint <%s>\n", SCIPconsGetName(cons));
12614 consdata->presolvedtiming = presoltiming;
12615
12616 thisnfixedvars = *nfixedvars;
12617 thisnchgbds = *nchgbds;
12618
12619 /* merge constraint, so propagation works better */
12620 SCIP_CALL( mergeMultiples(scip, cons, &cutoff) );
12621 if( cutoff )
12622 break;
12623
12624 /* add cliques in the knapsack to the clique table */
12625 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12626 {
12627 SCIP_CALL( addCliques(scip, cons, conshdlrdata->cliqueextractfactor, &cutoff, nchgbds) );
12628 if( cutoff )
12629 break;
12630 }
12631
12632 /* propagate constraint */
12633 if( presoltiming < SCIP_PRESOLTIMING_EXHAUSTIVE )
12634 {
12635 SCIP_CALL( propagateCons(scip, cons, &cutoff, &redundant, nfixedvars, (presoltiming & SCIP_PRESOLTIMING_MEDIUM)) );
12636
12637 if( cutoff )
12638 break;
12639 if( redundant )
12640 {
12641 (*ndelconss)++;
12642 continue;
12643 }
12644 }
12645
12646 /* remove again all fixed variables, if further fixings were found */
12647 if( *nfixedvars > thisnfixedvars || *nchgbds > thisnchgbds )
12648 {
12649 SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12650 if( cutoff )
12651 break;
12652
12653 thisnfixedvars = *nfixedvars;
12654 }
12655
12656 if( !SCIPconsIsModifiable(cons) )
12657 {
12658 /* check again for redundancy (applyFixings() might have decreased weightsum due to fixed-to-zero vars) */
12659 if( consdata->weightsum <= consdata->capacity )
12660 {
12661 SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
12662 SCIPconsGetName(cons), consdata->weightsum, consdata->capacity);
12664 continue;
12665 }
12666
12667 /* divide weights by their greatest common divisor */
12668 normalizeWeights(cons, nchgcoefs, nchgsides);
12669
12670 /* try to simplify inequalities */
12671 if( conshdlrdata->simplifyinequalities && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
12672 {
12673 SCIP_CALL( simplifyInequalities(scip, cons, nfixedvars, ndelconss, nchgcoefs, nchgsides, naddconss, &cutoff) );
12674 if( cutoff )
12675 break;
12676
12677 if( SCIPconsIsDeleted(cons) )
12678 continue;
12679
12680 /* remove again all fixed variables, if further fixings were found */
12681 if( *nfixedvars > thisnfixedvars )
12682 {
12684 if( cutoff )
12685 break;
12686 }
12687 }
12688
12689 /* tighten capacity and weights */
12690 SCIP_CALL( tightenWeights(scip, cons, presoltiming, nchgcoefs, nchgsides, naddconss, ndelconss, &cutoff) );
12691 if( cutoff )
12692 break;
12693
12694 if( SCIPconsIsActive(cons) )
12695 {
12696 if( conshdlrdata->dualpresolving && SCIPallowStrongDualReds(scip) && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12697 {
12698 /* in case the knapsack constraints is independent of everything else, solve the knapsack and apply the
12699 * dual reduction
12700 */
12701 SCIP_CALL( dualPresolving(scip, cons, nchgbds, ndelconss, &redundant) );
12702 if( redundant )
12703 continue;
12704 }
12705
12706 /* check if knapsack constraint is parallel to objective function */
12707 SCIP_CALL( checkParallelObjective(scip, cons, conshdlrdata) );
12708 }
12709 }
12710 /* remember the first changed constraint to begin the next aggregation round with */
12711 if( firstchange == INT_MAX && consdata->presolvedtiming != SCIP_PRESOLTIMING_EXHAUSTIVE )
12712 firstchange = c;
12713 }
12714
12715 /* preprocess pairs of knapsack constraints */
12716 if( !cutoff && conshdlrdata->presolusehashing && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12717 {
12718 /* detect redundant constraints; fast version with hash table instead of pairwise comparison */
12719 SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &cutoff, ndelconss) );
12720 }
12721
12722 if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) || (*naddconss != oldnaddconss) )
12723 success = TRUE;
12724 else
12725 success = FALSE;
12726
12727 if( !cutoff && firstchange < nconss && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
12728 {
12729 SCIP_Longint npaircomparisons;
12730
12731 npaircomparisons = 0;
12732 oldndelconss = *ndelconss;
12733 oldnchgsides = *nchgsides;
12734 oldnchgcoefs = *nchgcoefs;
12735
12736 for( c = firstchange; c < nconss && !cutoff && !SCIPisStopped(scip); ++c )
12737 {
12738 cons = conss[c];
12739 if( !SCIPconsIsActive(cons) || SCIPconsIsModifiable(cons) )
12740 continue;
12741
12742 npaircomparisons += ((SCIPconsGetData(cons)->presolvedtiming < SCIP_PRESOLTIMING_EXHAUSTIVE) ? (SCIP_Longint) c : ((SCIP_Longint) c - (SCIP_Longint) firstchange));
12743
12744 SCIP_CALL( preprocessConstraintPairs(scip, conss, firstchange, c, ndelconss) );
12745
12747 {
12748 if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) )
12749 success = TRUE;
12750 if( ((SCIP_Real) (*ndelconss - oldndelconss) + ((SCIP_Real) (*nchgsides - oldnchgsides))/2.0 +
12751 ((SCIP_Real) (*nchgcoefs - oldnchgcoefs))/10.0) / ((SCIP_Real) npaircomparisons) < MINGAINPERNMINCOMPARISONS )
12752 break;
12753 oldndelconss = *ndelconss;
12754 oldnchgsides = *nchgsides;
12755 oldnchgcoefs = *nchgcoefs;
12756 npaircomparisons = 0;
12757 }
12758 }
12759 }
12760#ifdef WITH_CARDINALITY_UPGRADE
12761 /* @todo upgrade to cardinality constraints: the code below relies on disabling the checking of the knapsack
12762 * constraint in the original problem, because the upgrade ensures that at most the given number of continuous
12763 * variables has a nonzero value, but not that the binary variables corresponding to the continuous variables with
12764 * value zero are set to zero as well. This can cause problems if the user accesses the values of the binary
12765 * variables (as the MIPLIB solution checker does), or the transformed problem is freed and the original problem
12766 * (possibly with some user modifications) is re-optimized. Until there is a way to force the binary variables to 0
12767 * as well, we better keep this code disabled. */
12768 /* upgrade to cardinality constraints - only try to upgrade towards the end of presolving, since the process below is quite expensive */
12769 if ( ! cutoff && conshdlrdata->upgdcardinality && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 && SCIPisPresolveFinished(scip) && ! conshdlrdata->upgradedcard )
12770 {
12771 SCIP_HASHMAP* varhash;
12773 SCIP_Real* cardweights;
12774 int noldupgdconss;
12775 int nscipvars;
12776 int makeupgrade;
12777
12778 noldupgdconss = *nupgdconss;
12782
12783 /* set up hash map */
12785
12786 /* We loop through all cardinality constraints twice:
12787 * - First, determine for each binary variable the number of cardinality constraints that can be upgraded to a
12788 * knapsack constraint and contain this variable; this number has to coincide with the number of variable up
12789 * locks; otherwise it would be infeasible to delete the knapsack constraints after the constraint update.
12790 * - Second, upgrade knapsack constraints to cardinality constraints. */
12791 for (makeupgrade = 0; makeupgrade < 2; ++makeupgrade)
12792 {
12793 for (c = nconss-1; c >= 0 && ! SCIPisStopped(scip); --c)
12794 {
12796 SCIP_VAR** vars;
12797 SCIP_Longint* weights;
12798 int nvars;
12799 int v;
12800
12801 cons = conss[c];
12802 assert( cons != NULL );
12803 consdata = SCIPconsGetData(cons);
12804 assert( consdata != NULL );
12805
12806 nvars = consdata->nvars;
12807 vars = consdata->vars;
12808 weights = consdata->weights;
12809
12810 /* Check, whether linear knapsack can be upgraded to a cardinality constraint:
12811 * - all variables must be binary (always true)
12812 * - all coefficients must be 1.0
12813 * - the right hand side must be smaller than nvars
12814 */
12815 if ( consdata->capacity >= nvars )
12816 continue;
12817
12818 /* the weights are sorted: check first and last weight */
12819 assert( consdata->sorted );
12820 if ( weights[0] != 1 || weights[nvars-1] != 1 )
12821 continue;
12822
12823 /* check whether all variables are of the form 0 <= x_v <= u_v y_v for y_v \in \{0,1\} and zero objective */
12824 for (v = 0; v < nvars; ++v)
12825 {
12827 SCIP_Real* implbounds;
12829 SCIP_VAR* var;
12830 int nimpls;
12831 int j;
12832
12833 var = consdata->vars[v];
12834 assert( var != NULL );
12836
12837 /* ignore non-active variables */
12838 if ( ! SCIPvarIsActive(var) )
12839 break;
12840
12841 /* be sure that implication variable has zero objective */
12842 if ( ! SCIPisZero(scip, SCIPvarGetObj(var)) )
12843 break;
12844
12845 nimpls = SCIPvarGetNImpls(var, FALSE);
12849
12850 for (j = 0; j < nimpls; ++j)
12851 {
12852 /* be sure that continuous variable is fixed to 0 */
12854 continue;
12855
12856 /* cannot currently deal with nonzero fixings */
12857 if ( ! SCIPisZero(scip, implbounds[j]) )
12858 continue;
12859
12860 /* number of down locks should be one */
12862 continue;
12863
12864 cardvars[v] = implvars[j];
12865 cardweights[v] = (SCIP_Real) v;
12866
12867 break;
12868 }
12869
12870 /* found no variable upper bound candidate -> exit */
12871 if ( j >= nimpls )
12872 break;
12873 }
12874
12875 /* did not find fitting variable upper bound for some variable -> exit */
12876 if ( v < nvars )
12877 break;
12878
12879 /* save number of knapsack constraints that can be upgraded to a cardinality constraint,
12880 * in which the binary variable is involved in */
12881 if ( makeupgrade == 0 )
12882 {
12883 for (v = 0; v < nvars; ++v)
12884 {
12885 if ( SCIPhashmapExists(varhash, vars[v]) )
12886 {
12887 int image;
12888
12889 image = SCIPhashmapGetImageInt(varhash, vars[v]);
12890 SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image + 1) );
12891 assert( image + 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12892 }
12893 else
12894 {
12895 SCIP_CALL( SCIPhashmapInsertInt(varhash, vars[v], 1) );
12896 assert( 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12897 assert( SCIPhashmapExists(varhash, vars[v]) );
12898 }
12899 }
12900 }
12901 else
12902 {
12903 SCIP_CONS* origcons;
12904
12905 /* for each variable: check whether the number of cardinality constraints that can be upgraded to a
12906 * knapsack constraint coincides with the number of variable up locks */
12907 for (v = 0; v < nvars; ++v)
12908 {
12909 assert( SCIPhashmapExists(varhash, vars[v]) );
12911 break;
12912 }
12913 if ( v < nvars )
12914 break;
12915
12916 /* store that we have upgraded */
12917 conshdlrdata->upgradedcard = TRUE;
12918
12919 /* at this point we found suitable variable upper bounds */
12920 SCIPdebugMessage("Upgrading knapsack constraint <%s> to cardinality constraint ...\n", SCIPconsGetName(cons));
12921
12922 /* create cardinality constraint */
12923 assert( ! SCIPconsIsModifiable(cons) );
12928#ifdef SCIP_DEBUG
12929 SCIPprintCons(scip, cons, NULL);
12930 SCIPinfoMessage(scip, NULL, "\n");
12932 SCIPinfoMessage(scip, NULL, "\n");
12933#endif
12936 ++(*nupgdconss);
12937
12938 /* delete oknapsack constraint */
12939 SCIP_CALL( SCIPdelCons(scip, cons) );
12940 ++(*ndelconss);
12941
12942 /* We need to disable the original knapsack constraint, since it might happen that the binary variables
12943 * are 1 although the continuous variables are 0. Thus, the knapsack constraint might be violated,
12944 * although the cardinality constraint is satisfied. */
12945 origcons = SCIPfindOrigCons(scip, SCIPconsGetName(cons));
12946 assert( origcons != NULL );
12947 SCIP_CALL( SCIPsetConsChecked(scip, origcons, FALSE) );
12948
12949 for (v = 0; v < nvars; ++v)
12950 {
12951 int image;
12952
12953 assert ( SCIPhashmapExists(varhash, vars[v]) );
12954 image = SCIPhashmapGetImageInt(varhash, vars[v]);
12955 SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image - 1) );
12956 assert( image - 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12957 }
12958 }
12959 }
12960 }
12961 SCIPhashmapFree(&varhash);
12964
12965 if ( *nupgdconss > noldupgdconss )
12966 success = TRUE;
12967 }
12968#endif
12969
12970 if( cutoff )
12972 else if( success || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12974 else
12976
12977 return SCIP_OKAY;
12978}
12979
12980/** propagation conflict resolving method of constraint handler */
12981static
12983{ /*lint --e{715}*/
12984 SCIP_CONSDATA* consdata;
12985 SCIP_Longint capsum;
12986 int i;
12987
12988 assert(result != NULL);
12989
12990 consdata = SCIPconsGetData(cons);
12991 assert(consdata != NULL);
12992
12993 /* check if we fixed a binary variable to one (due to negated clique) */
12994 if( inferinfo >= 0 && SCIPvarGetLbLocal(infervar) > 0.5 )
12995 {
12996 for( i = 0; i < consdata->nvars; ++i )
12997 {
12998 if( SCIPvarGetIndex(consdata->vars[i]) == inferinfo )
12999 {
13000 assert( SCIPgetVarUbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) < 0.5 );
13001 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
13002 break;
13003 }
13004 }
13006 }
13007 else
13008 {
13009 /* according to negated cliques the minweightsum and all variables which are fixed to one which led to a fixing of
13010 * another negated clique variable to one, the inferinfo was chosen to be the negative of the position in the
13011 * knapsack constraint, see one above call of SCIPinferBinvarCons
13012 */
13013 if( inferinfo < 0 )
13014 capsum = 0;
13015 else
13016 {
13017 /* locate the inference variable and calculate the capacity that has to be used up to conclude infervar == 0;
13018 * inferinfo stores the position of the inference variable (but maybe the variables were resorted)
13019 */
13020 if( inferinfo < consdata->nvars && consdata->vars[inferinfo] == infervar )
13021 capsum = consdata->weights[inferinfo];
13022 else
13023 {
13024 for( i = 0; i < consdata->nvars && consdata->vars[i] != infervar; ++i )
13025 {}
13027 capsum = consdata->weights[i];
13028 }
13029 }
13030
13031 /* add fixed-to-one variables up to the point, that their weight plus the weight of the conflict variable exceeds
13032 * the capacity
13033 */
13034 if( capsum <= consdata->capacity )
13035 {
13036 for( i = 0; i < consdata->nvars; i++ )
13037 {
13038 if( SCIPgetVarLbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) > 0.5 )
13039 {
13040 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
13041 capsum += consdata->weights[i];
13042 if( capsum > consdata->capacity )
13043 break;
13044 }
13045 }
13046 }
13047 }
13048
13049 /* NOTE: It might be the case that capsum < consdata->capacity. This is due the fact that the fixing of the variable
13050 * to zero can included negated clique information. A negated clique means, that at most one of the clique
13051 * variables can be zero. These information can be used to compute a minimum activity of the constraint and
13052 * used to fix variables to zero.
13053 *
13054 * Even if capsum < consdata->capacity we still reported a complete reason since the minimum activity is based
13055 * on global variable bounds. It might even be the case that we reported to many variables which are fixed to
13056 * one.
13057 */
13059
13060 return SCIP_OKAY;
13061}
13062
13063/** variable rounding lock method of constraint handler */
13064/**! [SnippetConsLockKnapsack] */
13065static
13067{ /*lint --e{715}*/
13068 SCIP_CONSDATA* consdata;
13069 int i;
13070
13071 consdata = SCIPconsGetData(cons);
13072 assert(consdata != NULL);
13073
13074 for( i = 0; i < consdata->nvars; i++)
13075 {
13076 SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlocksneg, nlockspos) );
13077 }
13078
13079 return SCIP_OKAY;
13080}
13081/**! [SnippetConsLockKnapsack] */
13082
13083/** constraint activation notification method of constraint handler */
13084static
13086{ /*lint --e{715}*/
13088 {
13089 SCIP_CALL( addNlrow(scip, cons) );
13090 }
13091
13092 return SCIP_OKAY;
13093}
13094
13095/** constraint deactivation notification method of constraint handler */
13096static
13098{ /*lint --e{715}*/
13099 SCIP_CONSDATA* consdata;
13100
13101 assert(cons != NULL);
13102
13103 consdata = SCIPconsGetData(cons);
13104 assert(consdata != NULL);
13105
13106 /* remove row from NLP, if still in solving
13107 * if we are in exitsolve, the whole NLP will be freed anyway
13108 */
13109 if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && consdata->nlrow != NULL )
13110 {
13111 SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
13112 }
13113
13114 return SCIP_OKAY;
13115}
13116
13117/** variable deletion method of constraint handler */
13118static
13120{
13121 assert(scip != NULL);
13122 assert(conshdlr != NULL);
13123 assert(conss != NULL || nconss == 0);
13124
13125 if( nconss > 0 )
13126 {
13127 SCIP_CALL( performVarDeletions(scip, conshdlr, conss, nconss) );
13128 }
13129
13130 return SCIP_OKAY;
13131}
13132
13133/** constraint display method of constraint handler */
13134static
13136{ /*lint --e{715}*/
13137 SCIP_CONSDATA* consdata;
13138 int i;
13139
13140 assert( scip != NULL );
13141 assert( conshdlr != NULL );
13142 assert( cons != NULL );
13143
13144 consdata = SCIPconsGetData(cons);
13145 assert(consdata != NULL);
13146
13147 for( i = 0; i < consdata->nvars; ++i )
13148 {
13149 if( i > 0 )
13150 SCIPinfoMessage(scip, file, " ");
13151 SCIPinfoMessage(scip, file, "%+" SCIP_LONGINT_FORMAT, consdata->weights[i]);
13152 SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[i], TRUE) );
13153 }
13154 SCIPinfoMessage(scip, file, " <= %" SCIP_LONGINT_FORMAT "", consdata->capacity);
13155
13156 return SCIP_OKAY;
13157}
13158
13159/** constraint copying method of constraint handler */
13160static
13162{ /*lint --e{715}*/
13164 SCIP_Longint* weights;
13165 SCIP_Real* coefs;
13166 const char* consname;
13167 int nvars;
13168 int v;
13169
13170 /* get variables and coefficients of the source constraint */
13172 nvars = SCIPgetNVarsKnapsack(sourcescip, sourcecons);
13173 weights = SCIPgetWeightsKnapsack(sourcescip, sourcecons);
13174
13176 for( v = 0; v < nvars; ++v )
13177 coefs[v] = (SCIP_Real) weights[v];
13178
13179 if( name != NULL )
13180 consname = name;
13181 else
13182 consname = SCIPconsGetName(sourcecons);
13183
13184 /* copy the logic using the linear constraint copy method */
13185 SCIP_CALL( SCIPcopyConsLinear(scip, cons, sourcescip, consname, nvars, sourcevars, coefs,
13186 -SCIPinfinity(scip), (SCIP_Real) SCIPgetCapacityKnapsack(sourcescip, sourcecons), varmap, consmap,
13187 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, global, valid) );
13188 assert(cons != NULL);
13189
13190 SCIPfreeBufferArray(scip, &coefs);
13191
13192 return SCIP_OKAY;
13193}
13194
13195/** constraint parsing method of constraint handler */
13196static
13198{ /*lint --e{715}*/
13199 SCIP_VAR* var;
13200 SCIP_Longint weight;
13201 SCIP_VAR** vars;
13202 SCIP_Longint* weights;
13203 SCIP_Longint capacity;
13204 char* endptr;
13205 int nread;
13206 int nvars;
13207 int varssize;
13208
13209 assert(scip != NULL);
13210 assert(success != NULL);
13211 assert(str != NULL);
13212 assert(name != NULL);
13213 assert(cons != NULL);
13214
13215 *success = TRUE;
13216
13217 nvars = 0;
13218 varssize = 5;
13219 SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13220 SCIP_CALL( SCIPallocBufferArray(scip, &weights, varssize) );
13221
13222 while( *str != '\0' )
13223 {
13224 /* try to parse coefficient, and use 1 if not successful */
13225 weight = 1;
13226 nread = 0;
13227 sscanf(str, "%" SCIP_LONGINT_FORMAT "%n", &weight, &nread);
13228 str += nread;
13229
13230 /* parse variable name */
13232
13233 if( var == NULL )
13234 {
13235 endptr = strchr(endptr, '<');
13236
13237 if( endptr == NULL )
13238 {
13239 SCIPerrorMessage("no capacity found\n");
13240 *success = FALSE;
13241 }
13242 else
13243 str = endptr;
13244
13245 break;
13246 }
13247
13248 str = endptr;
13249
13250 /* store weight and variable */
13251 if( varssize <= nvars )
13252 {
13253 varssize = SCIPcalcMemGrowSize(scip, varssize+1);
13254 SCIP_CALL( SCIPreallocBufferArray(scip, &vars, varssize) );
13255 SCIP_CALL( SCIPreallocBufferArray(scip, &weights, varssize) );
13256 }
13257
13258 vars[nvars] = var;
13259 weights[nvars] = weight;
13260 ++nvars;
13261
13262 /* skip whitespace */
13263 SCIP_CALL( SCIPskipSpace((char**)&str) );
13264 }
13265
13266 if( *success )
13267 {
13268 if( strncmp(str, "<=", 2) != 0 )
13269 {
13270 SCIPerrorMessage("expected '<=' at begin of '%s'\n", str);
13271 *success = FALSE;
13272 }
13273 else
13274 {
13275 str += 2;
13276 }
13277 }
13278
13279 if( *success )
13280 {
13281 /* skip whitespace */
13282 SCIP_CALL( SCIPskipSpace((char**)&str) );
13283
13284 /* coverity[secure_coding] */
13285 if( sscanf(str, "%" SCIP_LONGINT_FORMAT, &capacity) != 1 )
13286 {
13287 SCIPerrorMessage("error parsing capacity from '%s'\n", str);
13288 *success = FALSE;
13289 }
13290 else
13291 {
13292 SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13293 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13294 }
13295 }
13296
13298 SCIPfreeBufferArray(scip, &weights);
13299
13300 return SCIP_OKAY;
13301}
13302
13303/** constraint method of constraint handler which returns the variables (if possible) */
13304static
13306{ /*lint --e{715}*/
13307 SCIP_CONSDATA* consdata;
13308
13309 consdata = SCIPconsGetData(cons);
13310 assert(consdata != NULL);
13311
13313 (*success) = FALSE;
13314 else
13315 {
13316 assert(vars != NULL);
13317
13318 BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13319 (*success) = TRUE;
13320 }
13321
13322 return SCIP_OKAY;
13323}
13324
13325/** constraint method of constraint handler which returns the number of variables (if possible) */
13326static
13328{ /*lint --e{715}*/
13329 SCIP_CONSDATA* consdata;
13330
13331 consdata = SCIPconsGetData(cons);
13332 assert(consdata != NULL);
13333
13334 (*nvars) = consdata->nvars;
13335 (*success) = TRUE;
13336
13337 return SCIP_OKAY;
13338}
13339
13340/*
13341 * Event handler
13342 */
13343
13344/** execution method of bound change event handler */
13345static
13347{ /*lint --e{715}*/
13348 SCIP_CONSDATA* consdata;
13349
13350 assert(eventdata != NULL);
13351 assert(eventdata->cons != NULL);
13352
13353 consdata = SCIPconsGetData(eventdata->cons);
13354 assert(consdata != NULL);
13355
13356 switch( SCIPeventGetType(event) )
13357 {
13359 consdata->onesweightsum += eventdata->weight;
13360 consdata->presolvedtiming = 0;
13361 SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13362 break;
13364 consdata->onesweightsum -= eventdata->weight;
13365 break;
13367 consdata->presolvedtiming = 0;
13368 SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13369 break;
13370 case SCIP_EVENTTYPE_VARFIXED: /* the variable should be removed from the constraint in presolving */
13371 if( !consdata->existmultaggr )
13372 {
13373 SCIP_VAR* var;
13375 assert(var != NULL);
13376
13377 /* if the variable was aggregated or multiaggregated, we must signal to propagation that we are no longer merged */
13379 {
13380 consdata->existmultaggr = TRUE;
13381 consdata->merged = FALSE;
13382 }
13385 consdata->merged = FALSE;
13386 }
13387 /*lint -fallthrough*/
13388 case SCIP_EVENTTYPE_IMPLADDED: /* further preprocessing might be possible due to additional implications */
13389 consdata->presolvedtiming = 0;
13390 break;
13392 consdata->varsdeleted = TRUE;
13393 break;
13394 default:
13395 SCIPerrorMessage("invalid event type %" SCIP_EVENTTYPE_FORMAT "\n", SCIPeventGetType(event));
13396 return SCIP_INVALIDDATA;
13397 }
13398
13399 return SCIP_OKAY;
13400}
13401
13402
13403/*
13404 * constraint specific interface methods
13405 */
13406
13407/** creates the handler for knapsack constraints and includes it in SCIP */
13409 SCIP* scip /**< SCIP data structure */
13410 )
13411{
13412 SCIP_EVENTHDLRDATA* eventhdlrdata;
13413 SCIP_CONSHDLRDATA* conshdlrdata;
13414 SCIP_CONSHDLR* conshdlr;
13415
13416 /* create knapsack constraint handler data */
13417 SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
13418
13419 /* include event handler for bound change events */
13420 eventhdlrdata = NULL;
13421 conshdlrdata->eventhdlr = NULL;
13423 eventExecKnapsack, eventhdlrdata) );
13424
13425 /* get event handler for bound change events */
13426 if( conshdlrdata->eventhdlr == NULL )
13427 {
13428 SCIPerrorMessage("event handler for knapsack constraints not found\n");
13429 return SCIP_PLUGINNOTFOUND;
13430 }
13431
13432 /* include constraint handler */
13436 conshdlrdata) );
13437
13438 assert(conshdlr != NULL);
13439
13440 /* set non-fundamental callbacks via specific setter functions */
13466
13467 if( SCIPfindConshdlr(scip,"linear") != NULL )
13468 {
13469 /* include the linear constraint to knapsack constraint upgrade in the linear constraint handler */
13471 }
13472
13473 /* add knapsack constraint handler parameters */
13475 "constraints/" CONSHDLR_NAME "/sepacardfreq",
13476 "multiplier on separation frequency, how often knapsack cuts are separated (-1: never, 0: only at root)",
13477 &conshdlrdata->sepacardfreq, TRUE, DEFAULT_SEPACARDFREQ, -1, SCIP_MAXTREEDEPTH, NULL, NULL) );
13479 "constraints/" CONSHDLR_NAME "/maxcardbounddist",
13480 "maximal relative distance from current node's dual bound to primal bound compared to best node's dual bound for separating knapsack cuts",
13481 &conshdlrdata->maxcardbounddist, TRUE, DEFAULT_MAXCARDBOUNDDIST, 0.0, 1.0, NULL, NULL) );
13483 "constraints/" CONSHDLR_NAME "/cliqueextractfactor",
13484 "lower clique size limit for greedy clique extraction algorithm (relative to largest clique)",
13485 &conshdlrdata->cliqueextractfactor, TRUE, DEFAULT_CLIQUEEXTRACTFACTOR, 0.0, 1.0, NULL, NULL) );
13487 "constraints/" CONSHDLR_NAME "/maxrounds",
13488 "maximal number of separation rounds per node (-1: unlimited)",
13489 &conshdlrdata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
13491 "constraints/" CONSHDLR_NAME "/maxroundsroot",
13492 "maximal number of separation rounds per node in the root node (-1: unlimited)",
13493 &conshdlrdata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
13495 "constraints/" CONSHDLR_NAME "/maxsepacuts",
13496 "maximal number of cuts separated per separation round",
13497 &conshdlrdata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
13499 "constraints/" CONSHDLR_NAME "/maxsepacutsroot",
13500 "maximal number of cuts separated per separation round in the root node",
13501 &conshdlrdata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
13503 "constraints/" CONSHDLR_NAME "/disaggregation",
13504 "should disaggregation of knapsack constraints be allowed in preprocessing?",
13505 &conshdlrdata->disaggregation, TRUE, DEFAULT_DISAGGREGATION, NULL, NULL) );
13507 "constraints/" CONSHDLR_NAME "/simplifyinequalities",
13508 "should presolving try to simplify knapsacks",
13509 &conshdlrdata->simplifyinequalities, TRUE, DEFAULT_SIMPLIFYINEQUALITIES, NULL, NULL) );
13511 "constraints/" CONSHDLR_NAME "/negatedclique",
13512 "should negated clique information be used in solving process",
13513 &conshdlrdata->negatedclique, TRUE, DEFAULT_NEGATEDCLIQUE, NULL, NULL) );
13515 "constraints/" CONSHDLR_NAME "/presolpairwise",
13516 "should pairwise constraint comparison be performed in presolving?",
13517 &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13519 "constraints/" CONSHDLR_NAME "/presolusehashing",
13520 "should hash table be used for detecting redundant constraints in advance",
13521 &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) );
13523 "constraints/" CONSHDLR_NAME "/dualpresolving",
13524 "should dual presolving steps be performed?",
13525 &conshdlrdata->dualpresolving, TRUE, DEFAULT_DUALPRESOLVING, NULL, NULL) );
13527 "constraints/" CONSHDLR_NAME "/usegubs",
13528 "should GUB information be used for separation?",
13529 &conshdlrdata->usegubs, TRUE, DEFAULT_USEGUBS, NULL, NULL) );
13531 "constraints/" CONSHDLR_NAME "/detectcutoffbound",
13532 "should presolving try to detect constraints parallel to the objective function defining an upper bound and prevent these constraints from entering the LP?",
13533 &conshdlrdata->detectcutoffbound, TRUE, DEFAULT_DETECTCUTOFFBOUND, NULL, NULL) );
13535 "constraints/" CONSHDLR_NAME "/detectlowerbound",
13536 "should presolving try to detect constraints parallel to the objective function defining a lower bound and prevent these constraints from entering the LP?",
13537 &conshdlrdata->detectlowerbound, TRUE, DEFAULT_DETECTLOWERBOUND, NULL, NULL) );
13539 "constraints/" CONSHDLR_NAME "/updatecliquepartitions",
13540 "should clique partition information be updated when old partition seems outdated?",
13541 &conshdlrdata->updatecliquepartitions, TRUE, DEFAULT_UPDATECLIQUEPARTITIONS, NULL, NULL) );
13543 "constraints/" CONSHDLR_NAME "/clqpartupdatefac",
13544 "factor on the growth of global cliques to decide when to update a previous "
13545 "(negated) clique partition (used only if updatecliquepartitions is set to TRUE)",
13546 &conshdlrdata->clqpartupdatefac, TRUE, DEFAULT_CLQPARTUPDATEFAC, 1.0, 10.0, NULL, NULL) );
13547#ifdef WITH_CARDINALITY_UPGRADE
13549 "constraints/" CONSHDLR_NAME "/upgdcardinality",
13550 "if TRUE then try to update knapsack constraints to cardinality constraints",
13551 &conshdlrdata->upgdcardinality, TRUE, DEFAULT_UPGDCARDINALITY, NULL, NULL) );
13552#endif
13553 return SCIP_OKAY;
13554}
13555
13556/** creates and captures a knapsack constraint
13557 *
13558 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13559 */
13560/**! [SnippetConsCreationKnapsack] */
13562 SCIP* scip, /**< SCIP data structure */
13563 SCIP_CONS** cons, /**< pointer to hold the created constraint */
13564 const char* name, /**< name of constraint */
13565 int nvars, /**< number of items in the knapsack */
13566 SCIP_VAR** vars, /**< array with item variables */
13567 SCIP_Longint* weights, /**< array with item weights */
13568 SCIP_Longint capacity, /**< capacity of knapsack (right hand side of inequality) */
13569 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13570 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13571 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13572 * Usually set to TRUE. */
13573 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13574 * TRUE for model constraints, FALSE for additional, redundant constraints. */
13575 SCIP_Bool check, /**< should the constraint be checked for feasibility?
13576 * TRUE for model constraints, FALSE for additional, redundant constraints. */
13577 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13578 * Usually set to TRUE. */
13579 SCIP_Bool local, /**< is constraint only valid locally?
13580 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13581 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13582 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13583 * adds coefficients to this constraint. */
13584 SCIP_Bool dynamic, /**< is constraint subject to aging?
13585 * Usually set to FALSE. Set to TRUE for own cuts which
13586 * are separated as constraints. */
13587 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13588 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13589 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13590 * if it may be moved to a more global node?
13591 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13592 )
13593{
13594 SCIP_CONSHDLRDATA* conshdlrdata;
13595 SCIP_CONSHDLR* conshdlr;
13596 SCIP_CONSDATA* consdata;
13597
13598 /* find the knapsack constraint handler */
13599 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13600 if( conshdlr == NULL )
13601 {
13602 SCIPerrorMessage("knapsack constraint handler not found\n");
13603 return SCIP_PLUGINNOTFOUND;
13604 }
13605
13606 /* get event handler */
13607 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13608 assert(conshdlrdata != NULL);
13609 assert(conshdlrdata->eventhdlr != NULL);
13610
13611 /* create constraint data */
13612 SCIP_CALL( consdataCreate(scip, &consdata, nvars, vars, weights, capacity) );
13613
13614 /* create constraint */
13615 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
13616 local, modifiable, dynamic, removable, stickingatnode) );
13617
13618 /* catch events for variables */
13619 if( SCIPisTransformed(scip) )
13620 {
13621 SCIP_CALL( catchEvents(scip, *cons, consdata, conshdlrdata->eventhdlr) );
13622 }
13623
13624 return SCIP_OKAY;
13625}
13626/**! [SnippetConsCreationKnapsack] */
13627
13628/** creates and captures a knapsack constraint
13629 * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13630 * method SCIPcreateConsKnapsack(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13631 *
13632 * @see SCIPcreateConsKnapsack() for information about the basic constraint flag configuration
13633 *
13634 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13635 */
13637 SCIP* scip, /**< SCIP data structure */
13638 SCIP_CONS** cons, /**< pointer to hold the created constraint */
13639 const char* name, /**< name of constraint */
13640 int nvars, /**< number of items in the knapsack */
13641 SCIP_VAR** vars, /**< array with item variables */
13642 SCIP_Longint* weights, /**< array with item weights */
13643 SCIP_Longint capacity /**< capacity of knapsack */
13644 )
13645{
13646 assert(scip != NULL);
13647
13648 SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13650
13651 return SCIP_OKAY;
13652}
13653
13654/** adds new item to knapsack constraint */
13656 SCIP* scip, /**< SCIP data structure */
13657 SCIP_CONS* cons, /**< constraint data */
13658 SCIP_VAR* var, /**< item variable */
13659 SCIP_Longint weight /**< item weight */
13660 )
13661{
13662 assert(var != NULL);
13663 assert(scip != NULL);
13664
13666 {
13667 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13668 return SCIP_INVALIDDATA;
13669 }
13670
13671 SCIP_CALL( addCoef(scip, cons, var, weight) );
13672
13673 return SCIP_OKAY;
13674}
13675
13676/** gets the capacity of the knapsack constraint */
13678 SCIP* scip, /**< SCIP data structure */
13679 SCIP_CONS* cons /**< constraint data */
13680 )
13681{
13682 SCIP_CONSDATA* consdata;
13683
13684 assert(scip != NULL);
13685
13687 {
13688 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13689 SCIPABORT();
13690 return 0; /*lint !e527*/
13691 }
13692
13693 consdata = SCIPconsGetData(cons);
13694 assert(consdata != NULL);
13695
13696 return consdata->capacity;
13697}
13698
13699/** changes capacity of the knapsack constraint
13700 *
13701 * @note This method can only be called during problem creation stage (SCIP_STAGE_PROBLEM)
13702 */
13704 SCIP* scip, /**< SCIP data structure */
13705 SCIP_CONS* cons, /**< constraint data */
13706 SCIP_Longint capacity /**< new capacity of knapsack */
13707 )
13708{
13709 SCIP_CONSDATA* consdata;
13710
13711 assert(scip != NULL);
13712
13714 {
13715 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13716 return SCIP_INVALIDDATA;
13717 }
13718
13720 {
13721 SCIPerrorMessage("method can only be called during problem creation stage\n");
13722 return SCIP_INVALIDDATA;
13723 }
13724
13725 consdata = SCIPconsGetData(cons);
13726 assert(consdata != NULL);
13727
13728 consdata->capacity = capacity;
13729
13730 return SCIP_OKAY;
13731}
13732
13733/** gets the number of items in the knapsack constraint */
13735 SCIP* scip, /**< SCIP data structure */
13736 SCIP_CONS* cons /**< constraint data */
13737 )
13738{
13739 SCIP_CONSDATA* consdata;
13740
13741 assert(scip != NULL);
13742
13744 {
13745 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13746 SCIPABORT();
13747 return -1; /*lint !e527*/
13748 }
13749
13750 consdata = SCIPconsGetData(cons);
13751 assert(consdata != NULL);
13752
13753 return consdata->nvars;
13754}
13755
13756/** gets the array of variables in the knapsack constraint; the user must not modify this array! */
13758 SCIP* scip, /**< SCIP data structure */
13759 SCIP_CONS* cons /**< constraint data */
13760 )
13761{
13762 SCIP_CONSDATA* consdata;
13763
13764 assert(scip != NULL);
13765
13767 {
13768 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13769 SCIPABORT();
13770 return NULL; /*lint !e527*/
13771 }
13772
13773 consdata = SCIPconsGetData(cons);
13774 assert(consdata != NULL);
13775
13776 return consdata->vars;
13777}
13778
13779/** gets the array of weights in the knapsack constraint; the user must not modify this array! */
13781 SCIP* scip, /**< SCIP data structure */
13782 SCIP_CONS* cons /**< constraint data */
13783 )
13784{
13785 SCIP_CONSDATA* consdata;
13786
13787 assert(scip != NULL);
13788
13790 {
13791 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13792 SCIPABORT();
13793 return NULL; /*lint !e527*/
13794 }
13795
13796 consdata = SCIPconsGetData(cons);
13797 assert(consdata != NULL);
13798
13799 return consdata->weights;
13800}
13801
13802/** gets the dual solution of the knapsack constraint in the current LP */
13804 SCIP* scip, /**< SCIP data structure */
13805 SCIP_CONS* cons /**< constraint data */
13806 )
13807{
13808 SCIP_CONSDATA* consdata;
13809
13810 assert(scip != NULL);
13811
13813 {
13814 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13815 SCIPABORT();
13816 return SCIP_INVALID; /*lint !e527*/
13817 }
13818
13819 consdata = SCIPconsGetData(cons);
13820 assert(consdata != NULL);
13821
13822 if( consdata->row != NULL )
13823 return SCIProwGetDualsol(consdata->row);
13824 else
13825 return 0.0;
13826}
13827
13828/** gets the dual Farkas value of the knapsack constraint in the current infeasible LP */
13830 SCIP* scip, /**< SCIP data structure */
13831 SCIP_CONS* cons /**< constraint data */
13832 )
13833{
13834 SCIP_CONSDATA* consdata;
13835
13836 assert(scip != NULL);
13837
13839 {
13840 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13841 SCIPABORT();
13842 return SCIP_INVALID; /*lint !e527*/
13843 }
13844
13845 consdata = SCIPconsGetData(cons);
13846 assert(consdata != NULL);
13847
13848 if( consdata->row != NULL )
13849 return SCIProwGetDualfarkas(consdata->row);
13850 else
13851 return 0.0;
13852}
13853
13854/** returns the linear relaxation of the given knapsack constraint; may return NULL if no LP row was yet created;
13855 * the user must not modify the row!
13856 */
13858 SCIP* scip, /**< SCIP data structure */
13859 SCIP_CONS* cons /**< constraint data */
13860 )
13861{
13862 SCIP_CONSDATA* consdata;
13863
13864 assert(scip != NULL);
13865
13867 {
13868 SCIPerrorMessage("constraint is not a knapsack\n");
13869 SCIPABORT();
13870 return NULL; /*lint !e527*/
13871 }
13872
13873 consdata = SCIPconsGetData(cons);
13874 assert(consdata != NULL);
13875
13876 return consdata->row;
13877}
13878
13879/** cleans up (multi-)aggregations and fixings from knapsack constraints */
13881 SCIP* scip, /**< SCIP data structure */
13882 SCIP_Bool onlychecked, /**< should only checked constraints be cleaned up? */
13883 SCIP_Bool* infeasible /**< pointer to return whether the problem was detected to be infeasible */
13884 )
13885{
13886 SCIP_CONSHDLR* conshdlr;
13887 SCIP_CONS** conss;
13888 int nconss;
13889 int i;
13890
13891 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13892 if( conshdlr == NULL )
13893 return SCIP_OKAY;
13894
13895 assert(infeasible != NULL);
13896 *infeasible = FALSE;
13897
13899 conss = onlychecked ? SCIPconshdlrGetCheckConss(conshdlr) : SCIPconshdlrGetConss(conshdlr);
13900
13901 for( i = 0; i < nconss; ++i )
13902 {
13903 SCIP_CALL( applyFixings(scip, conss[i], infeasible) );
13904
13905 if( *infeasible )
13906 break;
13907 }
13908
13909 return SCIP_OKAY;
13910}
SCIP_VAR * h
SCIP_VAR * w
SCIP_VAR ** b
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_RETCODE consdataCreate(SCIP *scip, SCIP_CONSDATA **consdata, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
static SCIP_RETCODE getLiftingSequenceGUB(SCIP *scip, SCIP_GUBSET *gubset, SCIP_Real *solvals, SCIP_Longint *weights, int *varsC1, int *varsC2, int *varsF, int *varsR, int nvarsC1, int nvarsC2, int nvarsF, int nvarsR, int *gubconsGC1, int *gubconsGC2, int *gubconsGFC1, int *gubconsGR, int *ngubconsGC1, int *ngubconsGC2, int *ngubconsGFC1, int *ngubconsGR, int *ngubconscapexceed, int *maxgubvarssize)
GUBConsstatus
@ GUBCONSSTATUS_BELONGSTOSET_GF
@ GUBCONSSTATUS_UNINITIAL
@ GUBCONSSTATUS_BELONGSTOSET_GR
@ GUBCONSSTATUS_BELONGSTOSET_GOC1
@ GUBCONSSTATUS_BELONGSTOSET_GNC1
@ GUBCONSSTATUS_BELONGSTOSET_GC2
#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
#define DEFAULT_SEPACARDFREQ
#define CONSHDLR_SEPAFREQ
static SCIP_RETCODE insertZerolist(SCIP *scip, int **liftcands, int *nliftcands, int **firstidxs, SCIP_Longint **zeroweightsums, int **zeroitems, int **nextidxs, int *zeroitemssize, int *nzeroitems, int probindex, SCIP_Bool value, int knapsackidx, SCIP_Longint knapsackweight, SCIP_Bool *memlimitreached)
static SCIP_RETCODE addRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff)
#define KNAPSACKRELAX_MAXDELTA
static SCIP_RETCODE eventdataCreate(SCIP *scip, SCIP_EVENTDATA **eventdata, SCIP_CONS *cons, SCIP_Longint weight)
static SCIP_RETCODE prepareCons(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *ndelconss, int *nchgcoefs)
#define DEFAULT_USEGUBS
#define CONSHDLR_CHECKPRIORITY
static SCIP_RETCODE enlargeMinweights(SCIP *scip, SCIP_Longint **minweightsptr, int *minweightslen, int *minweightssize, int newlen)
#define CONSHDLR_DESC
static SCIP_RETCODE separateSequLiftedExtendedWeightInequality(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *feassetvars, int *nonfeassetvars, int nfeassetvars, int nnonfeassetvars, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
static SCIP_RETCODE GUBconsCreate(SCIP *scip, SCIP_GUBCONS **gubcons)
#define KNAPSACKRELAX_MAXSCALE
static void normalizeWeights(SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
static SCIP_RETCODE separateSupLiftedMinimalCoverInequality(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *mincovervars, int *nonmincovervars, int nmincovervars, int nnonmincovervars, SCIP_Longint mincoverweight, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
#define DEFAULT_DETECTCUTOFFBOUND
static SCIP_RETCODE addCliques(SCIP *const scip, SCIP_CONS *const cons, SCIP_Real cliqueextractfactor, SCIP_Bool *const cutoff, int *const nbdchgs)
static SCIP_RETCODE upgradeCons(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *naddconss)
static SCIP_RETCODE createRelaxation(SCIP *scip, SCIP_CONS *cons)
static void updateWeightSums(SCIP_CONSDATA *consdata, SCIP_VAR *var, SCIP_Longint weightdelta)
static void GUBconsFree(SCIP *scip, SCIP_GUBCONS **gubcons)
#define CONSHDLR_PROP_TIMING
static void getPartitionCovervars(SCIP *scip, SCIP_Real *solvals, int *covervars, int ncovervars, int *varsC1, int *varsC2, int *nvarsC1, int *nvarsC2)
static void GUBsetSwapVars(SCIP *scip, SCIP_GUBSET *gubset, int var1, int var2)
static SCIP_RETCODE unlockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
static SCIP_RETCODE getCover(SCIP *scip, SCIP_VAR **vars, int nvars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int *ncovervars, int *nnoncovervars, SCIP_Longint *coverweight, SCIP_Bool *found, SCIP_Bool modtransused, int *ntightened, SCIP_Bool *fractional)
static SCIP_RETCODE consdataEnsureVarsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num, SCIP_Bool transformed)
static void GUBsetFree(SCIP *scip, SCIP_GUBSET **gubset)
static SCIP_RETCODE createNormalizedKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
#define CONSHDLR_MAXPREROUNDS
static SCIP_RETCODE calcCliquepartition(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONSDATA *consdata, SCIP_Bool normalclique, SCIP_Bool negatedclique)
#define DEFAULT_PRESOLPAIRWISE
static SCIP_RETCODE performVarDeletions(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
#define CONSHDLR_SEPAPRIORITY
#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
#define MAXCOVERSIZEITERLEWI
static SCIP_RETCODE mergeMultiples(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff)
static SCIP_RETCODE GUBsetCheck(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars)
static SCIP_RETCODE GUBsetMoveVar(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, int var, int oldgubcons, int newgubcons)
static void sortItems(SCIP_CONSDATA *consdata)
static SCIP_RETCODE addNegatedCliques(SCIP *const scip, SCIP_CONS *const cons, SCIP_Bool *const cutoff, int *const nbdchgs)
static SCIP_RETCODE detectRedundantVars(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *nchgcoefs, int *nchgsides, int *naddconss)
static SCIP_RETCODE GUBsetGetCliquePartition(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, SCIP_Real *solvals)
static SCIP_RETCODE applyFixings(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff)
static SCIP_RETCODE lockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
static void computeMinweightsGUB(SCIP_Longint *minweights, SCIP_Longint *finished, SCIP_Longint *unfinished, int minweightslen)
static SCIP_RETCODE sequentialUpAndDownLiftingGUB(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, int ngubconscapexceed, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *gubconsGC1, int *gubconsGC2, int *gubconsGFC1, int *gubconsGR, int ngubconsGC1, int ngubconsGC2, int ngubconsGFC1, int ngubconsGR, int alpha0, int *liftcoefs, SCIP_Real *cutact, int *liftrhs, int maxgubvarssize)
#define HASHSIZE_KNAPSACKCONS
static SCIP_RETCODE GUBsetCalcCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques, SCIP_Real *solvals)
#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_RETCODE dualWeightsTightening(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *nchgcoefs, int *nchgsides, int *naddconss)
#define DEFAULT_PRESOLUSEHASHING
#define MAX_CLIQUELENGTH
#define DEFAULT_CLQPARTUPDATEFAC
static SCIP_RETCODE addCoef(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
static SCIP_RETCODE dropEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata, SCIP_EVENTHDLR *eventhdlr)
#define IDX(j, d)
static SCIP_Bool checkMinweightidx(SCIP_Longint *weights, SCIP_Longint capacity, int *covervars, int ncovervars, SCIP_Longint coverweight, int minweightidx, int j)
static SCIP_RETCODE sequentialUpAndDownLifting(SCIP *scip, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *varsM1, int *varsM2, int *varsF, int *varsR, int nvarsM1, int nvarsM2, int nvarsF, int nvarsR, int alpha0, int *liftcoefs, SCIP_Real *cutact, int *liftrhs)
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
#define MAXNCLIQUEVARSCOMP
static SCIP_RETCODE tightenWeightsLift(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, SCIP_Bool *cutoff)
static SCIP_RETCODE getFeasibleSet(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int *ncovervars, int *nnoncovervars, SCIP_Longint *coverweight, SCIP_Bool modtransused, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
#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
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_RETCODE addNlrow(SCIP *scip, SCIP_CONS *cons)
static void getPartitionNoncovervars(SCIP *scip, SCIP_Real *solvals, int *noncovervars, int nnoncovervars, int *varsF, int *varsR, int *nvarsF, int *nvarsR)
static SCIP_RETCODE stableSort(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR **vars, SCIP_Longint *weights, int *cliquestartposs, SCIP_Bool usenegatedclique)
static SCIP_RETCODE tightenWeights(SCIP *scip, SCIP_CONS *cons, SCIP_PRESOLTIMING presoltiming, int *nchgcoefs, int *nchgsides, int *naddconss, int *ndelconss, SCIP_Bool *cutoff)
#define CONSHDLR_EAGERFREQ
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
#define KNAPSACKRELAX_MAXDNOM
#define USESUPADDLIFT
#define DEFAULT_MAXROUNDS
#define CONSHDLR_ENFOPRIORITY
#define MAXABSVBCOEF
#define LINCONSUPGD_PRIORITY
#define CONSHDLR_DELAYSEPA
#define MAX_USECLIQUES_SIZE
#define DEFAULT_UPDATECLIQUEPARTITIONS
GUBVarstatus
@ GUBVARSTATUS_BELONGSTOSET_F
@ GUBVARSTATUS_BELONGSTOSET_C1
@ GUBVARSTATUS_BELONGSTOSET_R
@ GUBVARSTATUS_BELONGSTOSET_C2
@ GUBVARSTATUS_CAPACITYEXCEEDED
@ GUBVARSTATUS_UNINITIAL
#define CONSHDLR_NAME
#define EVENTHDLR_NAME
static SCIP_RETCODE checkParallelObjective(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata)
static SCIP_RETCODE GUBconsAddVar(SCIP *scip, SCIP_GUBCONS *gubcons, int var)
static SCIP_RETCODE changePartitionFeasiblesetvars(SCIP *scip, SCIP_Longint *weights, int *varsC1, int *varsC2, int *nvarsC1, int *nvarsC2)
#define DEFAULT_DISAGGREGATION
static SCIP_RETCODE preprocessConstraintPairs(SCIP *scip, SCIP_CONS **conss, int firstchange, int chkind, int *ndelconss)
static SCIP_RETCODE GUBconsDelVar(SCIP *scip, SCIP_GUBCONS *gubcons, int var, int gubvarsidx)
#define DEFAULT_DETECTLOWERBOUND
static SCIP_RETCODE dualPresolving(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *ndelconss, SCIP_Bool *deleted)
#define CONSHDLR_DELAYPROP
#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 SCIP_MAXSTRLEN
Definition def.h:302
#define SCIP_Longint
Definition def.h:171
#define SCIP_MAXTREEDEPTH
Definition def.h:330
#define SCIP_INVALID
Definition def.h:206
#define SCIP_Real
Definition def.h:186
#define TRUE
Definition def.h:95
#define FALSE
Definition def.h:96
#define SCIPABORT()
Definition def.h:360
#define REALABS(x)
Definition def.h:210
#define SCIP_LONGINT_MAX
Definition def.h:172
#define SCIP_CALL(x)
Definition def.h:388
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)
SCIP_RETCODE SCIPcreateConsBasicKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
SCIP_RETCODE SCIPchgCapacityKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_Longint capacity)
SCIP_RETCODE SCIPseparateRelaxedKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, int nknapvars, SCIP_VAR **knapvars, SCIP_Real *knapvals, SCIP_Real valscale, SCIP_Real rhs, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
SCIP_RETCODE SCIPsolveKnapsackExactly(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval, SCIP_Bool *success)
#define SCIP_DECL_LINCONSUPGD(x)
SCIP_RETCODE SCIPcreateConsKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPcopyConsLinear(SCIP *scip, SCIP_CONS **cons, SCIP *sourcescip, const char *name, int nvars, SCIP_VAR **sourcevars, SCIP_Real *sourcecoefs, SCIP_Real lhs, SCIP_Real rhs, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode, SCIP_Bool global, SCIP_Bool *valid)
SCIP_Longint * SCIPgetWeightsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_Longint SCIPgetCapacityKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_VAR ** SCIPgetVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcreateConsLogicor(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_Real SCIPgetDualfarkasKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_ROW * SCIPgetRowKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPgetDualsolKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPincludeConshdlrKnapsack(SCIP *scip)
SCIP_Bool SCIPisConsCompressionEnabled(SCIP *scip)
Definition scip_copy.c:660
SCIP_Bool SCIPisTransformed(SCIP *scip)
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
SCIP_Bool SCIPisStopped(SCIP *scip)
SCIP_STAGE SCIPgetStage(SCIP *scip)
int SCIPgetNObjVars(SCIP *scip)
Definition scip_prob.c: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:3058
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3231
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition misc.c:3024
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3373
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition misc.c:3142
SCIP_RETCODE SCIPhashmapSetImageInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition misc.c:3307
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition misc.c:2296
#define SCIPhashSix(a, b, c, d, e, f)
Definition pub_misc.h:531
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:2246
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition misc.c:2558
SCIP_RETCODE SCIPhashtableRemove(SCIP_HASHTABLE *hashtable, void *element)
Definition misc.c:2627
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition misc.c:2497
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,...)
#define SCIPdebugMsgPrint
#define SCIPdebugMsg
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition misc.c:9032
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:9468
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition misc.c:11096
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:83
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:139
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:57
int SCIPgetNLPBranchCands(SCIP *scip)
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
SCIP_RETCODE SCIPaddConflictBinvar(SCIP *scip, SCIP_VAR *var)
SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
int SCIPconshdlrGetNCheckConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4615
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition cons.c:4210
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:366
SCIP_RETCODE SCIPsetConshdlrActive(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:664
SCIP_CONS ** SCIPconshdlrGetCheckConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4572
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition scip_cons.c:534
SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:486
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:229
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition scip_cons.c:275
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:317
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:175
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:802
SCIP_Longint SCIPconshdlrGetNCutsFound(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4859
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:825
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:779
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4180
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)),)
Definition scip_cons.c:341
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition scip_cons.c:886
SCIP_RETCODE SCIPsetConshdlrInit(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:390
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:572
SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:438
SCIP_RETCODE SCIPsetConshdlrDeactive(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:687
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4200
int SCIPconshdlrGetNActiveConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4629
int SCIPconshdlrGetSepaFreq(SCIP_CONSHDLR *conshdlr)
Definition cons.c:5089
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:595
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:641
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:510
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:462
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4552
SCIP_RETCODE SCIPsetConshdlrDelvars(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:756
SCIP_RETCODE SCIPsetConshdlrExit(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:414
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:618
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:848
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition cons.c:8118
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition cons.c:8347
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition cons.c:8108
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition cons.c:8257
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition scip_cons.c:2482
SCIP_RETCODE SCIPsetConsSeparated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool separate)
Definition scip_cons.c:1242
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition cons.c:8287
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition cons.c:8217
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition cons.c:8397
SCIP_RETCODE SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial)
Definition scip_cons.c:1217
SCIP_RETCODE SCIPsetConsEnforced(SCIP *scip, SCIP_CONS *cons, SCIP_Bool enforce)
Definition scip_cons.c:1267
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition cons.c:8277
SCIP_RETCODE SCIPunmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition scip_cons.c:1988
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition cons.c:8149
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:943
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition cons.c:8307
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition cons.c:8327
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition cons.c:8088
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition scip_cons.c:1758
SCIP_RETCODE SCIPmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition scip_cons.c:1960
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition cons.c:8337
SCIP_RETCODE SCIPupdateConsFlags(SCIP *scip, SCIP_CONS *cons0, SCIP_CONS *cons1)
Definition scip_cons.c:1470
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition cons.c:8367
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition scip_cons.c:1119
SCIP_RETCODE SCIPsetConsPropagated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool propagate)
Definition scip_cons.c:1317
SCIP_RETCODE SCIPsetConsChecked(SCIP *scip, SCIP_CONS *cons, SCIP_Bool check)
Definition scip_cons.c:1292
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition cons.c:8267
SCIP_RETCODE SCIPincConsAge(SCIP *scip, SCIP_CONS *cons)
Definition scip_cons.c:1730
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition cons.c:8357
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:391
SCIP_RETCODE SCIPaddNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition scip_nlp.c:363
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition scip_nlp.c:110
SCIP_RETCODE SCIPreleaseNlRow(SCIP *scip, SCIP_NLROW **nlrow)
Definition scip_nlp.c:1025
SCIP_Bool SCIPnlrowIsInNLP(SCIP_NLROW *nlrow)
Definition nlp.c:1872
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:921
SCIP_Bool SCIPinProbing(SCIP *scip)
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:1398
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition scip_sol.c:1361
void SCIPupdateSolLPConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition scip_sol.c:285
SCIP_RETCODE SCIPupdateCutoffbound(SCIP *scip, SCIP_Real cutoffbound)
int SCIPgetNSepaRounds(SCIP *scip)
SCIP_Real SCIPgetLowerbound(SCIP *scip)
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPcutoffbounddelta(SCIP *scip)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPepsilon(SCIP *scip)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition scip_tree.c:146
int SCIPgetDepth(SCIP *scip)
Definition scip_tree.c: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:18092
SCIP_Bool SCIPvarIsDeleted(SCIP_VAR *var)
Definition var.c:17462
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:17704
SCIP_VAR * SCIPvarGetNegatedVar(SCIP_VAR *var)
Definition var.c:17716
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition var.c:18114
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition var.c:17570
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition var.c:17421
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:18178
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition var.c:17360
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:17966
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition var.c:17383
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition var.c:17748
SCIP_VAR * SCIPvarGetProbvar(SCIP_VAR *var)
Definition var.c:12207
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:17910
SCIP_VAR ** SCIPvarGetImplVars(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:18195
int SCIPvarGetIndex(SCIP_VAR *var)
Definition var.c:17580
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:17590
const char * SCIPvarGetName(SCIP_VAR *var)
Definition var.c:17241
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition scip_var.c:1248
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition var.c:18124
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition var.c:18134
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition var.c:17432
SCIP_Real * SCIPvarGetImplBounds(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:18224
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:17680
int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition var.c:17668
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:18252
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition var.c:17956
SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
Definition var.c:17396
int SCIPgetNCliques(SCIP *scip)
Definition scip_var.c:7575
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition var.c:18104
SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:18263
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition var.c:17900
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:11931
SCIP_RETCODE SCIPvarGetProbvarBinary(SCIP_VAR **var, SCIP_Bool *negated)
Definition var.c:12299
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:18166
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:18146
SCIP_Bool SCIPvarsHaveCommonClique(SCIP_VAR *var1, SCIP_Bool value1, SCIP_VAR *var2, SCIP_Bool value2, SCIP_Bool regardimplics)
Definition var.c:11464
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition var.c:18156
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:18210
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:12267
SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition var.c:17692
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:10788
SCIP_RETCODE SCIPskipSpace(char **s)
Definition misc.c:10777
return SCIP_OKAY
int c
int depth
SCIP_Bool cutoff
SCIP_Real objval
static SCIP_SOL * sol
assert(minobj< SCIPgetCutoffbound(scip))
int nvars
SCIP_VAR * var
static SCIP_Bool propagate
static SCIP_VAR ** vars
int nbinvars
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
#define NULL
Definition lpi_spx1.cpp:161
memory allocation routines
#define BMScopyMemoryArray(ptr, source, num)
Definition memory.h:136
#define BMSclearMemoryArray(ptr, num)
Definition memory.h:132
struct BMS_BlkMem BMS_BLKMEM
Definition memory.h:439
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)
#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
SCIP_GUBCONS ** gubconss
#define MAX(x, y)
Definition tclique_def.h:92
@ SCIP_CONFTYPE_PROPAGATION
#define SCIP_DECL_CONSENFOLP(x)
Definition type_cons.h:362
#define SCIP_DECL_CONSINITPRE(x)
Definition type_cons.h:155
#define SCIP_DECL_CONSDELETE(x)
Definition type_cons.h:228
#define SCIP_DECL_CONSEXIT(x)
Definition type_cons.h:135
#define SCIP_DECL_CONSGETVARS(x)
Definition type_cons.h:865
#define SCIP_DECL_CONSINITSOL(x)
Definition type_cons.h:200
#define SCIP_DECL_CONSPRINT(x)
Definition type_cons.h:767
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition type_cons.h:64
#define SCIP_DECL_CONSSEPALP(x)
Definition type_cons.h:287
#define SCIP_DECL_CONSENFORELAX(x)
Definition type_cons.h:387
#define SCIP_DECL_CONSPROP(x)
Definition type_cons.h:504
#define SCIP_DECL_CONSGETNVARS(x)
Definition type_cons.h:883
#define SCIP_DECL_CONSRESPROP(x)
Definition type_cons.h:610
#define SCIP_DECL_CONSACTIVE(x)
Definition type_cons.h:689
#define SCIP_DECL_CONSENFOPS(x)
Definition type_cons.h:430
#define SCIP_DECL_CONSPARSE(x)
Definition type_cons.h:843
#define SCIP_DECL_CONSTRANS(x)
Definition type_cons.h:238
#define SCIP_DECL_CONSDEACTIVE(x)
Definition type_cons.h:704
#define SCIP_DECL_CONSPRESOL(x)
Definition type_cons.h:559
#define SCIP_DECL_CONSINITLP(x)
Definition type_cons.h:258
#define SCIP_DECL_CONSEXITPRE(x)
Definition type_cons.h:179
#define SCIP_DECL_CONSLOCK(x)
Definition type_cons.h:674
#define SCIP_DECL_CONSCOPY(x)
Definition type_cons.h:808
#define SCIP_DECL_CONSINIT(x)
Definition type_cons.h:125
struct SCIP_ConsData SCIP_CONSDATA
Definition type_cons.h:65
#define SCIP_DECL_CONSCHECK(x)
Definition type_cons.h:473
#define SCIP_DECL_CONSHDLRCOPY(x)
Definition type_cons.h:107
#define SCIP_DECL_CONSEXITSOL(x)
Definition type_cons.h:215
#define SCIP_DECL_CONSFREE(x)
Definition type_cons.h:115
#define SCIP_DECL_CONSSEPASOL(x)
Definition type_cons.h:319
#define SCIP_DECL_CONSDELVARS(x)
Definition type_cons.h:751
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_DECL_EVENTEXEC(x)
Definition type_event.h:253
#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:62
@ SCIP_BOUNDTYPE_UPPER
Definition type_lp.h:57
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition type_lp.h:59
#define SCIP_DECL_SORTPTRCOMP(x)
Definition type_misc.h:188
#define SCIP_DECL_HASHKEYEQ(x)
Definition type_misc.h:194
#define SCIP_DECL_HASHGETKEY(x)
Definition type_misc.h:191
#define SCIP_DECL_HASHKEYVAL(x)
Definition type_misc.h:197
@ SCIP_DIDNOTRUN
Definition type_result.h:42
@ SCIP_CUTOFF
Definition type_result.h:48
@ SCIP_FEASIBLE
Definition type_result.h:45
@ SCIP_REDUCEDDOM
Definition type_result.h:51
@ SCIP_DIDNOTFIND
Definition type_result.h:44
@ SCIP_SEPARATED
Definition type_result.h:49
@ SCIP_SUCCESS
Definition type_result.h:58
@ SCIP_INFEASIBLE
Definition type_result.h:46
enum SCIP_Result SCIP_RESULT
Definition type_result.h:61
@ SCIP_INVALIDDATA
@ SCIP_PLUGINNOTFOUND
@ SCIP_NOMEMORY
@ SCIP_ERROR
enum SCIP_Retcode SCIP_RETCODE
@ 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
#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