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-2024 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file cons_knapsack.c
26 * @ingroup DEFPLUGINS_CONS
27 * @brief Constraint handler for knapsack constraints of the form \f$a^T x \le b\f$, x binary and \f$a \ge 0\f$.
28 * @author Tobias Achterberg
29 * @author Xin Liu
30 * @author Kati Wolter
31 * @author Michael Winkler
32 * @author Tobias Fischer
33 */
34
35/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
36
38#include "scip/cons_knapsack.h"
39#include "scip/cons_linear.h"
40#include "scip/cons_logicor.h"
41#include "scip/cons_setppc.h"
42#include "scip/pub_cons.h"
43#include "scip/pub_event.h"
44#include "scip/pub_implics.h"
45#include "scip/pub_lp.h"
46#include "scip/pub_message.h"
47#include "scip/pub_misc.h"
49#include "scip/pub_misc_sort.h"
50#include "scip/pub_sepa.h"
51#include "scip/pub_var.h"
52#include "scip/scip_branch.h"
53#include "scip/scip_conflict.h"
54#include "scip/scip_cons.h"
55#include "scip/scip_copy.h"
56#include "scip/scip_cut.h"
57#include "scip/scip_event.h"
58#include "scip/scip_general.h"
59#include "scip/scip_lp.h"
60#include "scip/scip_mem.h"
61#include "scip/scip_message.h"
62#include "scip/scip_nlp.h"
63#include "scip/scip_numerics.h"
64#include "scip/scip_param.h"
65#include "scip/scip_prob.h"
66#include "scip/scip_probing.h"
67#include "scip/scip_sol.h"
69#include "scip/scip_tree.h"
70#include "scip/scip_var.h"
71#include "scip/symmetry_graph.h"
73#include <ctype.h>
74#include <string.h>
75
76#ifdef WITH_CARDINALITY_UPGRADE
78#endif
79
80/* constraint handler properties */
81#define CONSHDLR_NAME "knapsack"
82#define CONSHDLR_DESC "knapsack constraint of the form a^T x <= b, x binary and a >= 0"
83#define CONSHDLR_SEPAPRIORITY +600000 /**< priority of the constraint handler for separation */
84#define CONSHDLR_ENFOPRIORITY -600000 /**< priority of the constraint handler for constraint enforcing */
85#define CONSHDLR_CHECKPRIORITY -600000 /**< priority of the constraint handler for checking feasibility */
86#define CONSHDLR_SEPAFREQ 0 /**< frequency for separating cuts; zero means to separate only in the root node */
87#define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
88#define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
89 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
90#define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
91#define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
92#define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
93#define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
94
95#define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
96#define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
97
98#define EVENTHDLR_NAME "knapsack"
99#define EVENTHDLR_DESC "bound change event handler for knapsack constraints"
100#define EVENTTYPE_KNAPSACK SCIP_EVENTTYPE_LBCHANGED \
101 | SCIP_EVENTTYPE_UBTIGHTENED \
102 | SCIP_EVENTTYPE_VARFIXED \
103 | SCIP_EVENTTYPE_VARDELETED \
104 | SCIP_EVENTTYPE_IMPLADDED /**< variable events that should be caught by the event handler */
105
106#define LINCONSUPGD_PRIORITY +100000 /**< priority of the constraint handler for upgrading of linear constraints */
107
108#define MAX_USECLIQUES_SIZE 1000 /**< maximal number of items in knapsack where clique information is used */
109#define MAX_ZEROITEMS_SIZE 10000 /**< maximal number of items to store in the zero list in preprocessing */
110
111#define KNAPSACKRELAX_MAXDELTA 0.1 /**< maximal allowed rounding distance for scaling in knapsack relaxation */
112#define KNAPSACKRELAX_MAXDNOM 1000LL /**< maximal allowed denominator in knapsack rational relaxation */
113#define KNAPSACKRELAX_MAXSCALE 1000.0 /**< maximal allowed scaling factor in knapsack rational relaxation */
114
115#define DEFAULT_SEPACARDFREQ 1 /**< multiplier on separation frequency, how often knapsack cuts are separated */
116#define DEFAULT_MAXROUNDS 5 /**< maximal number of separation rounds per node (-1: unlimited) */
117#define DEFAULT_MAXROUNDSROOT -1 /**< maximal number of separation rounds in the root node (-1: unlimited) */
118#define DEFAULT_MAXSEPACUTS 50 /**< maximal number of cuts separated per separation round */
119#define DEFAULT_MAXSEPACUTSROOT 200 /**< maximal number of cuts separated per separation round in the root node */
120#define DEFAULT_MAXCARDBOUNDDIST 0.0 /**< maximal relative distance from current node's dual bound to primal bound compared
121 * to best node's dual bound for separating knapsack cuts */
122#define DEFAULT_DISAGGREGATION TRUE /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
123#define DEFAULT_SIMPLIFYINEQUALITIES TRUE/**< should presolving try to simplify knapsacks */
124#define DEFAULT_NEGATEDCLIQUE TRUE /**< should negated clique information be used in solving process */
125
126#define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds used for knapsack relaxation */
127#define USESUPADDLIFT FALSE /**< should lifted minimal cover inequalities using superadditive up-lifting be separated in addition */
128
129#define DEFAULT_PRESOLUSEHASHING TRUE /**< should hash table be used for detecting redundant constraints in advance */
130#define HASHSIZE_KNAPSACKCONS 500 /**< minimal size of hash table in linear constraint tables */
131
132#define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
133#define NMINCOMPARISONS 200000 /**< number for minimal pairwise presolving comparisons */
134#define MINGAINPERNMINCOMPARISONS 1e-06 /**< minimal gain per minimal pairwise presolving comparisons to repeat pairwise
135 * comparison round */
136#define DEFAULT_DUALPRESOLVING TRUE /**< should dual presolving steps be performed? */
137#define DEFAULT_DETECTCUTOFFBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
138 * function defining an upper bound and prevent these constraints from
139 * entering the LP */
140#define DEFAULT_DETECTLOWERBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
141 * function defining a lower bound and prevent these constraints from
142 * entering the LP */
143#define DEFAULT_CLIQUEEXTRACTFACTOR 0.5 /**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
144#define MAXCOVERSIZEITERLEWI 1000 /**< maximal size for which LEWI are iteratively separated by reducing the feasible set */
145
146#define DEFAULT_USEGUBS FALSE /**< should GUB information be used for separation? */
147#define GUBCONSGROWVALUE 6 /**< memory growing value for GUB constraint array */
148#define GUBSPLITGNC1GUBS FALSE /**< should GNC1 GUB conss without F vars be split into GOC1 and GR GUB conss? */
149#define DEFAULT_CLQPARTUPDATEFAC 1.5 /**< factor on the growth of global cliques to decide when to update a previous
150 * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
151#define DEFAULT_UPDATECLIQUEPARTITIONS FALSE /**< should clique partition information be updated when old partition seems outdated? */
152#define MAXNCLIQUEVARSCOMP 1000000 /**< limit on number of pairwise comparisons in clique partitioning algorithm */
153#ifdef WITH_CARDINALITY_UPGRADE
154#define DEFAULT_UPGDCARDINALITY FALSE /**< if TRUE then try to update knapsack constraints to cardinality constraints */
155#endif
156
157/* @todo maybe use event SCIP_EVENTTYPE_VARUNLOCKED to decide for another dual-presolving run on a constraint */
158
159/*
160 * Data structures
161 */
162
163/** constraint handler data */
164struct SCIP_ConshdlrData
165{
166 int* ints1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
167 * you have to clear it at the end, exists only in presolving stage */
168 int* ints2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
169 * you have to clear it at the end, exists only in presolving stage */
170 SCIP_Longint* longints1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
171 * you have to clear it at the end, exists only in presolving stage */
172 SCIP_Longint* longints2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
173 * you have to clear it at the end, exists only in presolving stage */
174 SCIP_Bool* bools1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
175 * you have to clear it at the end, exists only in presolving stage */
176 SCIP_Bool* bools2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
177 * you have to clear it at the end, exists only in presolving stage */
178 SCIP_Bool* bools3; /**< cleared memory array, all entries are set to zero in initpre, if you use this
179 * you have to clear it at the end, exists only in presolving stage */
180 SCIP_Bool* bools4; /**< cleared memory array, all entries are set to zero in initpre, if you use this
181 * you have to clear it at the end, exists only in presolving stage */
182 SCIP_Real* reals1; /**< cleared memory array, all entries are set to zero in consinit, if you use this
183 * you have to clear it at the end */
184 int ints1size; /**< size of ints1 array */
185 int ints2size; /**< size of ints2 array */
186 int longints1size; /**< size of longints1 array */
187 int longints2size; /**< size of longints2 array */
188 int bools1size; /**< size of bools1 array */
189 int bools2size; /**< size of bools2 array */
190 int bools3size; /**< size of bools3 array */
191 int bools4size; /**< size of bools4 array */
192 int reals1size; /**< size of reals1 array */
193 SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
194 SCIP_Real maxcardbounddist; /**< maximal relative distance from current node's dual bound to primal bound compared
195 * to best node's dual bound for separating knapsack cuts */
196 int sepacardfreq; /**< multiplier on separation frequency, how often knapsack cuts are separated */
197 int maxrounds; /**< maximal number of separation rounds per node (-1: unlimited) */
198 int maxroundsroot; /**< maximal number of separation rounds in the root node (-1: unlimited) */
199 int maxsepacuts; /**< maximal number of cuts separated per separation round */
200 int maxsepacutsroot; /**< maximal number of cuts separated per separation round in the root node */
201 SCIP_Bool disaggregation; /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
202 SCIP_Bool simplifyinequalities;/**< should presolving try to cancel down or delete coefficients in inequalities */
203 SCIP_Bool negatedclique; /**< should negated clique information be used in solving process */
204 SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
205 SCIP_Bool presolusehashing; /**< should hash table be used for detecting redundant constraints in advance */
206 SCIP_Bool dualpresolving; /**< should dual presolving steps be performed? */
207 SCIP_Bool usegubs; /**< should GUB information be used for separation? */
208 SCIP_Bool detectcutoffbound; /**< should presolving try to detect constraints parallel to the objective
209 * function defining an upper bound and prevent these constraints from
210 * entering the LP */
211 SCIP_Bool detectlowerbound; /**< should presolving try to detect constraints parallel to the objective
212 * function defining a lower bound and prevent these constraints from
213 * entering the LP */
214 SCIP_Bool updatecliquepartitions; /**< should clique partition information be updated when old partition seems outdated? */
215 SCIP_Real cliqueextractfactor;/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
216 SCIP_Real clqpartupdatefac; /**< factor on the growth of global cliques to decide when to update a previous
217 * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
218#ifdef WITH_CARDINALITY_UPGRADE
219 SCIP_Bool upgdcardinality; /**< if TRUE then try to update knapsack constraints to cardinality constraints */
220 SCIP_Bool upgradedcard; /**< whether we have already upgraded knapsack constraints to cardinality constraints */
221#endif
222};
223
224
225/** constraint data for knapsack constraints */
226struct SCIP_ConsData
227{
228 SCIP_VAR** vars; /**< variables in knapsack constraint */
229 SCIP_Longint* weights; /**< weights of variables in knapsack constraint */
230 SCIP_EVENTDATA** eventdata; /**< event data for bound change events of the variables */
231 int* cliquepartition; /**< clique indices of the clique partition */
232 int* negcliquepartition; /**< clique indices of the negated clique partition */
233 SCIP_ROW* row; /**< corresponding LP row */
234 SCIP_NLROW* nlrow; /**< corresponding NLP row */
235 int nvars; /**< number of variables in knapsack constraint */
236 int varssize; /**< size of vars, weights, and eventdata arrays */
237 int ncliques; /**< number of cliques in the clique partition */
238 int nnegcliques; /**< number of cliques in the negated clique partition */
239 int ncliqueslastnegpart;/**< number of global cliques the last time a negated clique partition was computed */
240 int ncliqueslastpart; /**< number of global cliques the last time a clique partition was computed */
241 SCIP_Longint capacity; /**< capacity of knapsack */
242 SCIP_Longint weightsum; /**< sum of all weights */
243 SCIP_Longint onesweightsum; /**< sum of weights of variables fixed to one */
244 unsigned int presolvedtiming:5; /**< max level in which the knapsack constraint is already presolved */
245 unsigned int sorted:1; /**< are the knapsack items sorted by weight? */
246 unsigned int cliquepartitioned:1;/**< is the clique partition valid? */
247 unsigned int negcliquepartitioned:1;/**< is the negated clique partition valid? */
248 unsigned int merged:1; /**< are the constraint's equal variables already merged? */
249 unsigned int cliquesadded:1; /**< were the cliques of the knapsack already added to clique table? */
250 unsigned int varsdeleted:1; /**< were variables deleted after last cleanup? */
251 unsigned int existmultaggr:1; /**< does this constraint contain multi-aggregations */
252};
253
254/** event data for bound changes events */
255struct SCIP_EventData
256{
257 SCIP_CONS* cons; /**< knapsack constraint to process the bound change for */
258 SCIP_Longint weight; /**< weight of variable */
259 int filterpos; /**< position of event in variable's event filter */
260};
261
262
263/** data structure to combine two sorting key values */
264struct sortkeypair
265{
266 SCIP_Real key1; /**< first sort key value */
267 SCIP_Real key2; /**< second sort key value */
268};
269typedef struct sortkeypair SORTKEYPAIR;
270
271/** status of GUB constraint */
273{
274 GUBVARSTATUS_UNINITIAL = -1, /** unintitialized variable status */
275 GUBVARSTATUS_CAPACITYEXCEEDED = 0, /** variable with weight exceeding the knapsack capacity */
276 GUBVARSTATUS_BELONGSTOSET_R = 1, /** variable in noncovervars R */
277 GUBVARSTATUS_BELONGSTOSET_F = 2, /** variable in noncovervars F */
278 GUBVARSTATUS_BELONGSTOSET_C2 = 3, /** variable in covervars C2 */
279 GUBVARSTATUS_BELONGSTOSET_C1 = 4 /** variable in covervars C1 */
282
283/** status of variable in GUB constraint */
285{
286 GUBCONSSTATUS_UNINITIAL = -1, /** unintitialized GUB constraint status */
287 GUBCONSSTATUS_BELONGSTOSET_GR = 0, /** all GUB variables are in noncovervars R */
288 GUBCONSSTATUS_BELONGSTOSET_GF = 1, /** all GUB variables are in noncovervars F (and noncovervars R) */
289 GUBCONSSTATUS_BELONGSTOSET_GC2 = 2, /** all GUB variables are in covervars C2 */
290 GUBCONSSTATUS_BELONGSTOSET_GNC1 = 3, /** some GUB variables are in covervars C1, others in noncovervars R or F */
291 GUBCONSSTATUS_BELONGSTOSET_GOC1 = 4 /** all GUB variables are in covervars C1 */
294
295/** data structure of GUB constraints */
297{
298 int* gubvars; /**< indices of GUB variables in knapsack constraint */
299 GUBVARSTATUS* gubvarsstatus; /**< status of GUB variables */
300 int ngubvars; /**< number of GUB variables */
301 int gubvarssize; /**< size of gubvars array */
302};
304
305/** data structure of a set of GUB constraints */
307{
308 SCIP_GUBCONS** gubconss; /**< GUB constraints in GUB set */
309 GUBCONSSTATUS* gubconsstatus; /**< status of GUB constraints */
310 int ngubconss; /**< number of GUB constraints */
311 int nvars; /**< number of variables in knapsack constraint */
312 int* gubconssidx; /**< index of GUB constraint (in gubconss array) of each knapsack variable */
313 int* gubvarsidx; /**< index in GUB constraint (in gubvars array) of each knapsack variable */
314};
316
317/*
318 * Local methods
319 */
320
321/** comparison method for two sorting key pairs */
322static
324{
327
328 if( sortkeypair1->key1 < sortkeypair2->key1 )
329 return -1;
330 else if( sortkeypair1->key1 > sortkeypair2->key1 )
331 return +1;
332 else if( sortkeypair1->key2 < sortkeypair2->key2 )
333 return -1;
334 else if( sortkeypair1->key2 > sortkeypair2->key2 )
335 return +1;
336 else
337 return 0;
338}
339
340/** creates event data */
341static
343 SCIP* scip, /**< SCIP data structure */
344 SCIP_EVENTDATA** eventdata, /**< pointer to store event data */
345 SCIP_CONS* cons, /**< constraint */
346 SCIP_Longint weight /**< weight of variable */
347 )
348{
349 assert(eventdata != NULL);
350
351 SCIP_CALL( SCIPallocBlockMemory(scip, eventdata) );
352 (*eventdata)->cons = cons;
353 (*eventdata)->weight = weight;
354
355 return SCIP_OKAY;
356}
357
358/** frees event data */
359static
361 SCIP* scip, /**< SCIP data structure */
362 SCIP_EVENTDATA** eventdata /**< pointer to event data */
363 )
364{
365 assert(eventdata != NULL);
366
367 SCIPfreeBlockMemory(scip, eventdata);
368
369 return SCIP_OKAY;
370}
371
372/** sorts items in knapsack with nonincreasing weights */
373static
375 SCIP_CONSDATA* consdata /**< constraint data */
376 )
377{
378 assert(consdata != NULL);
379 assert(consdata->nvars == 0 || consdata->vars != NULL);
380 assert(consdata->nvars == 0 || consdata->weights != NULL);
381 assert(consdata->nvars == 0 || consdata->eventdata != NULL);
382 assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
383
384 if( !consdata->sorted )
385 {
386 int pos;
387 int lastcliquenum;
388 int v;
389
390 /* sort of five joint arrays of Long/pointer/pointer/ints/ints,
391 * sorted by first array in non-increasing order via sort template */
393 consdata->weights,
394 (void**)consdata->vars,
395 (void**)consdata->eventdata,
396 consdata->cliquepartition,
397 consdata->negcliquepartition,
398 consdata->nvars);
399
400 v = consdata->nvars - 1;
401 /* sort all items with same weight according to their variable index, used for hash value for fast pairwise comparison of all constraints */
402 while( v >= 0 )
403 {
404 int w = v - 1;
405
406 while( w >= 0 && consdata->weights[v] == consdata->weights[w] )
407 --w;
408
409 if( v - w > 1 )
410 {
411 /* sort all corresponding parts of arrays for which the weights are equal by using the variable index */
413 (void**)(&(consdata->vars[w+1])),
414 (void**)(&(consdata->eventdata[w+1])),
415 &(consdata->cliquepartition[w+1]),
416 &(consdata->negcliquepartition[w+1]),
418 v - w);
419 }
420 v = w;
421 }
422
423 /* we need to make sure that our clique numbers of our normal clique will be in increasing order without gaps */
424 if( consdata->cliquepartitioned )
425 {
426 lastcliquenum = 0;
427
428 for( pos = 0; pos < consdata->nvars; ++pos )
429 {
430 /* if the clique number in the normal clique at position pos is greater than the last found clique number the
431 * partition is invalid */
432 if( consdata->cliquepartition[pos] > lastcliquenum )
433 {
434 consdata->cliquepartitioned = FALSE;
435 break;
436 }
437 else if( consdata->cliquepartition[pos] == lastcliquenum )
439 }
440 }
441 /* we need to make sure that our clique numbers of our negated clique will be in increasing order without gaps */
442 if( consdata->negcliquepartitioned )
443 {
444 lastcliquenum = 0;
445
446 for( pos = 0; pos < consdata->nvars; ++pos )
447 {
448 /* if the clique number in the negated clique at position pos is greater than the last found clique number the
449 * partition is invalid */
450 if( consdata->negcliquepartition[pos] > lastcliquenum )
451 {
452 consdata->negcliquepartitioned = FALSE;
453 break;
454 }
455 else if( consdata->negcliquepartition[pos] == lastcliquenum )
457 }
458 }
459
460 consdata->sorted = TRUE;
461 }
462#ifndef NDEBUG
463 {
464 /* check if the weight array is sorted in a non-increasing way */
465 int i;
466 for( i = 0; i < consdata->nvars-1; ++i )
467 assert(consdata->weights[i] >= consdata->weights[i+1]);
468 }
469#endif
470}
471
472/** calculates a partition of the variables into cliques */
473static
475 SCIP* scip, /**< SCIP data structure */
476 SCIP_CONSHDLRDATA* conshdlrdata, /**< knapsack constraint handler data */
477 SCIP_CONSDATA* consdata, /**< constraint data */
478 SCIP_Bool normalclique, /**< Should normal cliquepartition be created? */
479 SCIP_Bool negatedclique /**< Should negated cliquepartition be created? */
480 )
481{
482 SCIP_Bool ispartitionoutdated;
483 SCIP_Bool isnegpartitionoutdated;
484 assert(consdata != NULL);
485 assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
486
487 /* rerun eventually if number of global cliques increased considerably since last partition */
488 ispartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->ncliques > 1
489 && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastpart));
490
491 if( normalclique && ( !consdata->cliquepartitioned || ispartitionoutdated ) )
492 {
493 SCIP_CALL( SCIPcalcCliquePartition(scip, consdata->vars, consdata->nvars, consdata->cliquepartition, &consdata->ncliques) );
494 consdata->cliquepartitioned = TRUE;
495 consdata->ncliqueslastpart = SCIPgetNCliques(scip);
496 }
497
498 /* rerun eventually if number of global cliques increased considerably since last negated partition */
499 isnegpartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->nnegcliques > 1
500 && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastnegpart));
501
502 if( negatedclique && (!consdata->negcliquepartitioned || isnegpartitionoutdated) )
503 {
504 SCIP_CALL( SCIPcalcNegatedCliquePartition(scip, consdata->vars, consdata->nvars, consdata->negcliquepartition, &consdata->nnegcliques) );
505 consdata->negcliquepartitioned = TRUE;
506 consdata->ncliqueslastnegpart = SCIPgetNCliques(scip);
507 }
508 assert(!consdata->cliquepartitioned || consdata->ncliques <= consdata->nvars);
509 assert(!consdata->negcliquepartitioned || consdata->nnegcliques <= consdata->nvars);
510
511 return SCIP_OKAY;
512}
513
514/** installs rounding locks for the given variable in the given knapsack constraint */
515static
517 SCIP* scip, /**< SCIP data structure */
518 SCIP_CONS* cons, /**< knapsack constraint */
519 SCIP_VAR* var /**< variable of constraint entry */
520 )
521{
523
524 return SCIP_OKAY;
525}
526
527/** removes rounding locks for the given variable in the given knapsack constraint */
528static
530 SCIP* scip, /**< SCIP data structure */
531 SCIP_CONS* cons, /**< knapsack constraint */
532 SCIP_VAR* var /**< variable of constraint entry */
533 )
534{
536
537 return SCIP_OKAY;
538}
539
540/** catches bound change events for variables in knapsack */
541static
543 SCIP* scip, /**< SCIP data structure */
544 SCIP_CONS* cons, /**< constraint */
545 SCIP_CONSDATA* consdata, /**< constraint data */
546 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
547 )
548{
549 int i;
550
551 assert(cons != NULL);
552 assert(consdata != NULL);
553 assert(consdata->nvars == 0 || consdata->vars != NULL);
554 assert(consdata->nvars == 0 || consdata->weights != NULL);
555 assert(consdata->nvars == 0 || consdata->eventdata != NULL);
556
557 for( i = 0; i < consdata->nvars; i++)
558 {
559 SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[i], cons, consdata->weights[i]) );
561 eventhdlr, consdata->eventdata[i], &consdata->eventdata[i]->filterpos) );
562 }
563
564 return SCIP_OKAY;
565}
566
567/** drops bound change events for variables in knapsack */
568static
570 SCIP* scip, /**< SCIP data structure */
571 SCIP_CONSDATA* consdata, /**< constraint data */
572 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
573 )
574{
575 int i;
576
577 assert(consdata != NULL);
578 assert(consdata->nvars == 0 || consdata->vars != NULL);
579 assert(consdata->nvars == 0 || consdata->weights != NULL);
580 assert(consdata->nvars == 0 || consdata->eventdata != NULL);
581
582 for( i = 0; i < consdata->nvars; i++)
583 {
585 eventhdlr, consdata->eventdata[i], consdata->eventdata[i]->filterpos) );
586 SCIP_CALL( eventdataFree(scip, &consdata->eventdata[i]) );
587 }
588
589 return SCIP_OKAY;
590}
591
592/** ensures, that vars and vals arrays can store at least num entries */
593static
595 SCIP* scip, /**< SCIP data structure */
596 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
597 int num, /**< minimum number of entries to store */
598 SCIP_Bool transformed /**< is constraint from transformed problem? */
599 )
600{
601 assert(consdata != NULL);
602 assert(consdata->nvars <= consdata->varssize);
603
604 if( num > consdata->varssize )
605 {
606 int newsize;
607
609 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) );
610 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->weights, consdata->varssize, newsize) );
611 if( transformed )
612 {
613 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->eventdata, consdata->varssize, newsize) );
614 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->cliquepartition, consdata->varssize, newsize) );
615 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->negcliquepartition, consdata->varssize, newsize) );
616 }
617 else
618 {
619 assert(consdata->eventdata == NULL);
620 assert(consdata->cliquepartition == NULL);
621 assert(consdata->negcliquepartition == NULL);
622 }
623 consdata->varssize = newsize;
624 }
625 assert(num <= consdata->varssize);
626
627 return SCIP_OKAY;
628}
629
630/** updates all weight sums for fixed and unfixed variables */
631static
633 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
634 SCIP_VAR* var, /**< variable for this weight */
635 SCIP_Longint weightdelta /**< difference between the old and the new weight of the variable */
636 )
637{
638 assert(consdata != NULL);
639 assert(var != NULL);
640
641 consdata->weightsum += weightdelta;
642
643 if( SCIPvarGetLbLocal(var) > 0.5 )
644 consdata->onesweightsum += weightdelta;
645
646 assert(consdata->weightsum >= 0);
647 assert(consdata->onesweightsum >= 0);
648}
649
650/** creates knapsack constraint data */
651static
653 SCIP* scip, /**< SCIP data structure */
654 SCIP_CONSDATA** consdata, /**< pointer to store constraint data */
655 int nvars, /**< number of variables in knapsack */
656 SCIP_VAR** vars, /**< variables of knapsack */
657 SCIP_Longint* weights, /**< weights of knapsack items */
658 SCIP_Longint capacity /**< capacity of knapsack */
659 )
660{
661 int v;
662 SCIP_Longint constant;
663
664 assert(consdata != NULL);
665
666 SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
667
668 constant = 0L;
669 (*consdata)->vars = NULL;
670 (*consdata)->weights = NULL;
671 (*consdata)->nvars = 0;
672 if( nvars > 0 )
673 {
675 SCIP_Longint* weightsbuffer;
676 int k;
677
680
681 k = 0;
682 for( v = 0; v < nvars; ++v )
683 {
684 assert(vars[v] != NULL);
686
687 /* all weight have to be non negative */
688 assert( weights[v] >= 0 );
689
690 if( weights[v] > 0 )
691 {
692 /* treat fixed variables as constants if problem compression is enabled */
694 {
695 /* only if the variable is fixed to 1, we add its weight to the constant */
696 if( SCIPvarGetUbGlobal(vars[v]) > 0.5 )
697 constant += weights[v];
698 }
699 else
700 {
701 varsbuffer[k] = vars[v];
702 weightsbuffer[k] = weights[v];
703 ++k;
704 }
705 }
706 }
707 assert(k >= 0);
708 assert(constant >= 0);
709
710 (*consdata)->nvars = k;
711
712 /* copy the active variables and weights into the constraint data structure */
713 if( k > 0 )
714 {
715 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, varsbuffer, k) );
716 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->weights, weightsbuffer, k) );
717 }
718
719 /* free buffer storage */
722 }
723
724 (*consdata)->varssize = (*consdata)->nvars;
725 (*consdata)->capacity = capacity - constant;
726 (*consdata)->eventdata = NULL;
727 (*consdata)->cliquepartition = NULL;
728 (*consdata)->negcliquepartition = NULL;
729 (*consdata)->row = NULL;
730 (*consdata)->nlrow = NULL;
731 (*consdata)->weightsum = 0;
732 (*consdata)->onesweightsum = 0;
733 (*consdata)->ncliques = 0;
734 (*consdata)->nnegcliques = 0;
735 (*consdata)->presolvedtiming = 0;
736 (*consdata)->sorted = FALSE;
737 (*consdata)->cliquepartitioned = FALSE;
738 (*consdata)->negcliquepartitioned = FALSE;
739 (*consdata)->ncliqueslastpart = -1;
740 (*consdata)->ncliqueslastnegpart = -1;
741 (*consdata)->merged = FALSE;
742 (*consdata)->cliquesadded = FALSE;
743 (*consdata)->varsdeleted = FALSE;
744 (*consdata)->existmultaggr = FALSE;
745
746 /* get transformed variables, if we are in the transformed problem */
748 {
749 SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
750
751 for( v = 0; v < (*consdata)->nvars; v++ )
752 {
753 SCIP_VAR* var = SCIPvarGetProbvar((*consdata)->vars[v]);
754 assert(var != NULL);
755 (*consdata)->existmultaggr = (*consdata)->existmultaggr || (SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
756 }
757
758 /* allocate memory for additional data structures */
759 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->nvars) );
760 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->nvars) );
761 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->nvars) );
762 }
763
764 /* calculate sum of weights and capture variables */
765 for( v = 0; v < (*consdata)->nvars; ++v )
766 {
767 /* calculate sum of weights */
768 updateWeightSums(*consdata, (*consdata)->vars[v], (*consdata)->weights[v]);
769
770 /* capture variables */
771 SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) );
772 }
773 return SCIP_OKAY;
774}
775
776/** frees knapsack constraint data */
777static
779 SCIP* scip, /**< SCIP data structure */
780 SCIP_CONSDATA** consdata, /**< pointer to the constraint data */
781 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
782 )
783{
784 assert(consdata != NULL);
785 assert(*consdata != NULL);
786
787 if( (*consdata)->row != NULL )
788 {
789 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->row) );
790 }
791 if( (*consdata)->nlrow != NULL )
792 {
793 SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
794 }
795 if( (*consdata)->eventdata != NULL )
796 {
797 SCIP_CALL( dropEvents(scip, *consdata, eventhdlr) );
798 SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->varssize);
799 }
800 if( (*consdata)->negcliquepartition != NULL )
801 {
802 SCIPfreeBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->varssize);
803 }
804 if( (*consdata)->cliquepartition != NULL )
805 {
806 SCIPfreeBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->varssize);
807 }
808 if( (*consdata)->vars != NULL )
809 {
810 int v;
811
812 /* release variables */
813 for( v = 0; v < (*consdata)->nvars; v++ )
814 {
815 assert((*consdata)->vars[v] != NULL);
816 SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->vars[v])) );
817 }
818
819 assert( (*consdata)->weights != NULL );
820 assert( (*consdata)->varssize > 0 );
821 SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->varssize);
822 SCIPfreeBlockMemoryArray(scip, &(*consdata)->weights, (*consdata)->varssize);
823 }
824
825 SCIPfreeBlockMemory(scip, consdata);
826
827 return SCIP_OKAY;
828}
829
830/** changes a single weight in knapsack constraint data */
831static
833 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
834 int item, /**< item number */
835 SCIP_Longint newweight /**< new weight of item */
836 )
837{
838 SCIP_Longint oldweight;
839 SCIP_Longint weightdiff;
840
841 assert(consdata != NULL);
843
844 oldweight = consdata->weights[item];
846 consdata->weights[item] = newweight;
847
848 /* update weight sums for all and fixed variables */
849 updateWeightSums(consdata, consdata->vars[item], weightdiff);
850
851 if( consdata->eventdata != NULL )
852 {
853 assert(consdata->eventdata[item] != NULL);
854 assert(consdata->eventdata[item]->weight == oldweight);
855 consdata->eventdata[item]->weight = newweight;
856 }
857
858 consdata->presolvedtiming = 0;
859 consdata->sorted = FALSE;
860
861 /* recalculate cliques extraction after a weight was increased */
862 if( oldweight < newweight )
863 {
864 consdata->cliquesadded = FALSE;
865 }
866}
867
868/** creates LP row corresponding to knapsack constraint */
869static
871 SCIP* scip, /**< SCIP data structure */
872 SCIP_CONS* cons /**< knapsack constraint */
873 )
874{
875 SCIP_CONSDATA* consdata;
876 int i;
877
878 consdata = SCIPconsGetData(cons);
879 assert(consdata != NULL);
880 assert(consdata->row == NULL);
881
882 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, cons, SCIPconsGetName(cons),
883 -SCIPinfinity(scip), (SCIP_Real)consdata->capacity,
885
886 SCIP_CALL( SCIPcacheRowExtensions(scip, consdata->row) );
887 for( i = 0; i < consdata->nvars; ++i )
888 {
889 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, consdata->vars[i], (SCIP_Real)consdata->weights[i]) );
890 }
891 SCIP_CALL( SCIPflushRowExtensions(scip, consdata->row) );
892
893 return SCIP_OKAY;
894}
895
896/** adds linear relaxation of knapsack constraint to the LP */
897static
899 SCIP* scip, /**< SCIP data structure */
900 SCIP_CONS* cons, /**< knapsack constraint */
901 SCIP_Bool* cutoff /**< whether a cutoff has been detected */
902 )
903{
904 SCIP_CONSDATA* consdata;
905
906 assert( cutoff != NULL );
907 *cutoff = FALSE;
908
909 consdata = SCIPconsGetData(cons);
910 assert(consdata != NULL);
911
912 if( consdata->row == NULL )
913 {
915 }
916 assert(consdata->row != NULL);
917
918 /* insert LP row as cut */
919 if( !SCIProwIsInLP(consdata->row) )
920 {
921 SCIPdebugMsg(scip, "adding relaxation of knapsack constraint <%s> (capacity %" SCIP_LONGINT_FORMAT "): ",
922 SCIPconsGetName(cons), consdata->capacity);
923 SCIPdebug( SCIP_CALL(SCIPprintRow(scip, consdata->row, NULL)) );
924 SCIP_CALL( SCIPaddRow(scip, consdata->row, FALSE, cutoff) );
925 }
926
927 return SCIP_OKAY;
928}
929
930/** adds knapsack constraint as row to the NLP, if not added yet */
931static
933 SCIP* scip, /**< SCIP data structure */
934 SCIP_CONS* cons /**< knapsack constraint */
935 )
936{
937 SCIP_CONSDATA* consdata;
938
940
941 /* skip deactivated, redundant, or local linear constraints (the NLP does not allow for local rows at the moment) */
942 if( !SCIPconsIsActive(cons) || !SCIPconsIsChecked(cons) || SCIPconsIsLocal(cons) )
943 return SCIP_OKAY;
944
945 consdata = SCIPconsGetData(cons);
946 assert(consdata != NULL);
947
948 if( consdata->nlrow == NULL )
949 {
950 SCIP_Real* coefs;
951 int i;
952
953 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, consdata->nvars) );
954 for( i = 0; i < consdata->nvars; ++i )
955 coefs[i] = (SCIP_Real)consdata->weights[i]; /*lint !e613*/
956
957 SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
958 consdata->nvars, consdata->vars, coefs, NULL,
959 -SCIPinfinity(scip), (SCIP_Real)consdata->capacity, SCIP_EXPRCURV_LINEAR) );
960
961 assert(consdata->nlrow != NULL);
962
963 SCIPfreeBufferArray(scip, &coefs);
964 }
965
966 if( !SCIPnlrowIsInNLP(consdata->nlrow) )
967 {
968 SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
969 }
970
971 return SCIP_OKAY;
972}
973
974/** checks knapsack constraint for feasibility of given solution: returns TRUE iff constraint is feasible */
975static
977 SCIP* scip, /**< SCIP data structure */
978 SCIP_CONS* cons, /**< constraint to check */
979 SCIP_SOL* sol, /**< solution to check, NULL for current solution */
980 SCIP_Bool checklprows, /**< Do constraints represented by rows in the current LP have to be checked? */
981 SCIP_Bool printreason, /**< Should the reason for the violation be printed? */
982 SCIP_Bool* violated /**< pointer to store whether the constraint is violated */
983 )
984{
985 SCIP_CONSDATA* consdata;
986
987 assert(violated != NULL);
988
989 consdata = SCIPconsGetData(cons);
990 assert(consdata != NULL);
991
992 SCIPdebugMsg(scip, "checking knapsack constraint <%s> for feasibility of solution %p (lprows=%u)\n",
993 SCIPconsGetName(cons), (void*)sol, checklprows);
994
995 *violated = FALSE;
996
997 if( checklprows || consdata->row == NULL || !SCIProwIsInLP(consdata->row) )
998 {
999 SCIP_Real sum;
1000 SCIP_Longint integralsum;
1001 SCIP_Bool ishuge;
1002 SCIP_Real absviol;
1003 SCIP_Real relviol;
1004 int v;
1005
1006 /* increase age of constraint; age is reset to zero, if a violation was found only in case we are in
1007 * enforcement
1008 */
1009 if( sol == NULL )
1010 {
1011 SCIP_CALL( SCIPincConsAge(scip, cons) );
1012 }
1013
1014 sum = 0.0;
1015 integralsum = 0;
1016 /* we perform a more exact comparison if the capacity does not exceed the huge value */
1017 if( SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
1018 {
1019 ishuge = TRUE;
1020
1021 /* sum over all weight times the corresponding solution value */
1022 for( v = consdata->nvars - 1; v >= 0; --v )
1023 {
1024 assert(SCIPvarIsBinary(consdata->vars[v]));
1025 sum += consdata->weights[v] * SCIPgetSolVal(scip, sol, consdata->vars[v]);
1026 }
1027 }
1028 else
1029 {
1030 ishuge = FALSE;
1031
1032 /* sum over all weight for which the variable has a solution value of 1 in feastol */
1033 for( v = consdata->nvars - 1; v >= 0; --v )
1034 {
1035 assert(SCIPvarIsBinary(consdata->vars[v]));
1036
1037 if( SCIPgetSolVal(scip, sol, consdata->vars[v]) > 0.5 )
1038 integralsum += consdata->weights[v];
1039 }
1040 }
1041
1042 /* calculate constraint violation and update it in solution */
1044 absviol -= consdata->capacity;
1045 relviol = SCIPrelDiff(absviol + consdata->capacity, (SCIP_Real)consdata->capacity);
1046 if( sol != NULL )
1048
1050 {
1051 *violated = TRUE;
1052
1053 /* only reset constraint age if we are in enforcement */
1054 if( sol == NULL )
1055 {
1057 }
1058
1059 if( printreason )
1060 {
1061 SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
1062
1063 SCIPinfoMessage(scip, NULL, ";\n");
1064 SCIPinfoMessage(scip, NULL, "violation: the capacity is violated by %.15g\n", absviol);
1065 }
1066 }
1067 }
1068
1069 return SCIP_OKAY;
1070}
1071
1072/* IDX computes the integer index for the optimal solution array */
1073#define IDX(j,d) ((j)*(intcap)+(d))
1074
1075/** solves knapsack problem in maximization form exactly using dynamic programming;
1076 * if needed, one can provide arrays to store all selected items and all not selected items
1077 *
1078 * @note in case you provide the solitems or nonsolitems array you also have to provide the counter part, as well
1079 *
1080 * @note the algorithm will first compute a greedy solution and terminate
1081 * if the greedy solution is proven to be optimal.
1082 * The dynamic programming algorithm runs with a time and space complexity
1083 * of O(nitems * capacity).
1084 *
1085 * @todo If only the objective is relevant, it is easy to change the code to use only one slice with O(capacity) space.
1086 * There are recursive methods (see the book by Kellerer et al.) that require O(capacity) space, but it remains
1087 * to be checked whether they are faster and whether they can reconstruct the solution.
1088 * Dembo and Hammer (see Kellerer et al. Section 5.1.3, page 126) found a method that relies on a fast probing method.
1089 * This fixes additional elements to 0 or 1 similar to a reduced cost fixing.
1090 * This could be implemented, however, it would be technically a bit cumbersome,
1091 * since one needs the greedy solution and the LP-value for this.
1092 * This is currently only available after the redundant items have already been sorted out.
1093 */
1095 SCIP* scip, /**< SCIP data structure */
1096 int nitems, /**< number of available items */
1097 SCIP_Longint* weights, /**< item weights */
1098 SCIP_Real* profits, /**< item profits */
1099 SCIP_Longint capacity, /**< capacity of knapsack */
1100 int* items, /**< item numbers */
1101 int* solitems, /**< array to store items in solution, or NULL */
1102 int* nonsolitems, /**< array to store items not in solution, or NULL */
1103 int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1104 int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1105 SCIP_Real* solval, /**< pointer to store optimal solution value, or NULL */
1106 SCIP_Bool* success /**< pointer to store if an error occured during solving
1107 * (normally a memory problem) */
1108 )
1109{
1110 SCIP_RETCODE retcode;
1111 SCIP_Real* tempsort;
1112 SCIP_Real* optvalues;
1113 int intcap;
1114 int d;
1115 int j;
1116 int greedymedianpos;
1117 SCIP_Longint weightsum;
1118 int* myitems;
1119 SCIP_Longint* myweights;
1120 SCIP_Real* realweights;
1121 int* allcurrminweight;
1122 SCIP_Real* myprofits;
1123 int nmyitems;
1124 SCIP_Longint gcd;
1125 SCIP_Longint minweight;
1126 SCIP_Longint maxweight;
1127 int currminweight;
1128 SCIP_Longint greedysolweight;
1129 SCIP_Real greedysolvalue;
1130 SCIP_Real greedyupperbound;
1131 SCIP_Bool eqweights;
1132 SCIP_Bool intprofits;
1133
1134 assert(weights != NULL);
1135 assert(profits != NULL);
1136 assert(capacity >= 0);
1137 assert(items != NULL);
1138 assert(nitems >= 0);
1139 assert(success != NULL);
1140
1141 *success = TRUE;
1142
1143#ifndef NDEBUG
1144 for( j = nitems - 1; j >= 0; --j )
1145 assert(weights[j] >= 0);
1146#endif
1147
1148 SCIPdebugMsg(scip, "Solving knapsack exactly.\n");
1149
1150 /* initializing solution value */
1151 if( solval != NULL )
1152 *solval = 0.0;
1153
1154 /* init solution information */
1155 if( solitems != NULL )
1156 {
1157 assert(items != NULL);
1158 assert(nsolitems != NULL);
1161
1162 *nnonsolitems = 0;
1163 *nsolitems = 0;
1164 }
1165
1166 /* allocate temporary memory */
1170 nmyitems = 0;
1171 weightsum = 0;
1172 minweight = SCIP_LONGINT_MAX;
1173 maxweight = 0;
1174
1175 /* remove unnecessary items */
1176 for( j = 0; j < nitems; ++j )
1177 {
1178 assert(0 <= weights[j] && weights[j] < SCIP_LONGINT_MAX);
1179
1180 /* item does not fit */
1181 if( weights[j] > capacity )
1182 {
1183 if( solitems != NULL )
1184 nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
1185 }
1186 /* item is not profitable */
1187 else if( profits[j] <= 0.0 )
1188 {
1189 if( solitems != NULL )
1190 nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
1191 }
1192 /* item always fits */
1193 else if( weights[j] == 0 )
1194 {
1195 if( solitems != NULL )
1196 solitems[(*nsolitems)++] = items[j]; /*lint !e413*/
1197
1198 if( solval != NULL )
1199 *solval += profits[j];
1200 }
1201 /* all important items */
1202 else
1203 {
1204 myweights[nmyitems] = weights[j];
1206 myitems[nmyitems] = items[j];
1207
1208 /* remember smallest item */
1209 if( myweights[nmyitems] < minweight )
1210 minweight = myweights[nmyitems];
1211
1212 /* remember bigest item */
1213 if( myweights[nmyitems] > maxweight )
1214 maxweight = myweights[nmyitems];
1215
1216 weightsum += myweights[nmyitems];
1217 ++nmyitems;
1218 }
1219 }
1220
1221 intprofits = TRUE;
1222 /* check if all profits are integer to strengthen the upper bound on the greedy solution */
1223 for( j = 0; j < nmyitems && intprofits; ++j )
1225
1226 /* if no item is left then goto end */
1227 if( nmyitems == 0 )
1228 {
1229 SCIPdebugMsg(scip, "After preprocessing no items are left.\n");
1230
1231 goto TERMINATE;
1232 }
1233
1234 /* if all items fit, we also do not need to do the expensive stuff later on */
1235 if( weightsum > 0 && weightsum <= capacity )
1236 {
1237 SCIPdebugMsg(scip, "After preprocessing all items fit into knapsack.\n");
1238
1239 for( j = nmyitems - 1; j >= 0; --j )
1240 {
1241 if( solitems != NULL )
1242 solitems[(*nsolitems)++] = myitems[j]; /*lint !e413*/
1243
1244 if( solval != NULL )
1245 *solval += myprofits[j];
1246 }
1247
1248 goto TERMINATE;
1249 }
1250
1251 assert(0 < minweight && minweight <= capacity );
1252 assert(0 < maxweight && maxweight <= capacity);
1253
1254 /* make weights relatively prime */
1255 eqweights = TRUE;
1256 if( maxweight > 1 )
1257 {
1258 /* determine greatest common divisor */
1259 gcd = myweights[nmyitems - 1];
1260 for( j = nmyitems - 2; j >= 0 && gcd >= 2; --j )
1262
1263 SCIPdebugMsg(scip, "Gcd is %" SCIP_LONGINT_FORMAT ".\n", gcd);
1264
1265 /* divide by greatest common divisor */
1266 if( gcd > 1 )
1267 {
1268 for( j = nmyitems - 1; j >= 0; --j )
1269 {
1270 myweights[j] /= gcd;
1271 eqweights = eqweights && (myweights[j] == 1);
1272 }
1273 capacity /= gcd;
1274 minweight /= gcd;
1275 }
1276 else
1277 eqweights = FALSE;
1278 }
1279 assert(minweight <= capacity);
1280
1281 /* if only one item fits, then take the best */
1282 if( minweight > capacity / 2 )
1283 {
1284 int p;
1285
1286 SCIPdebugMsg(scip, "Only one item fits into knapsack, so take the best.\n");
1287
1288 p = nmyitems - 1;
1289
1290 /* find best item */
1291 for( j = nmyitems - 2; j >= 0; --j )
1292 {
1293 if( myprofits[j] > myprofits[p] )
1294 p = j;
1295 }
1296
1297 /* update solution information */
1298 if( solitems != NULL )
1299 {
1301
1302 solitems[(*nsolitems)++] = myitems[p];
1303 for( j = nmyitems - 1; j >= 0; --j )
1304 {
1305 if( j != p )
1306 nonsolitems[(*nnonsolitems)++] = myitems[j];
1307 }
1308 }
1309 /* update solution value */
1310 if( solval != NULL )
1311 *solval += myprofits[p];
1312
1313 goto TERMINATE;
1314 }
1315
1316 /* if all items have the same weight, then take the best */
1317 if( eqweights )
1318 {
1319 SCIP_Real addval = 0.0;
1320
1321 SCIPdebugMsg(scip, "All weights are equal, so take the best.\n");
1322
1324
1325 /* update solution information */
1326 if( solitems != NULL || solval != NULL )
1327 {
1328 SCIP_Longint i;
1329
1330 /* if all items would fit we had handled this case before */
1331 assert((SCIP_Longint) nmyitems > capacity);
1333
1334 /* take the first best items into the solution */
1335 for( i = capacity - 1; i >= 0; --i )
1336 {
1337 if( solitems != NULL )
1338 solitems[(*nsolitems)++] = myitems[i];
1339 addval += myprofits[i];
1340 }
1341
1342 if( solitems != NULL )
1343 {
1344 /* the rest are not in the solution */
1345 for( i = nmyitems - 1; i >= capacity; --i )
1347 }
1348 }
1349 /* update solution value */
1350 if( solval != NULL )
1351 {
1352 assert(addval > 0.0);
1353 *solval += addval;
1354 }
1355
1356 goto TERMINATE;
1357 }
1358
1359 SCIPdebugMsg(scip, "Determine greedy solution.\n");
1360
1361 /* sort myitems (plus corresponding arrays myweights and myprofits) such that
1362 * p_1/w_1 >= p_2/w_2 >= ... >= p_n/w_n, this is only used for the greedy solution
1363 */
1366
1367 for( j = 0; j < nmyitems; ++j )
1368 {
1371 }
1372
1374 (SCIP_Real)capacity, nmyitems, &greedymedianpos);
1375
1378
1379 /* initialize values for greedy solution information */
1380 greedysolweight = 0;
1381 greedysolvalue = 0.0;
1382
1383 /* determine greedy solution */
1384 for( j = 0; j < greedymedianpos; ++j )
1385 {
1386 assert(myweights[j] <= capacity);
1387
1388 /* update greedy solution weight and value */
1391 }
1392
1393 assert(0 < greedysolweight && greedysolweight <= capacity);
1394 assert(greedysolvalue > 0.0);
1395
1396 /* If the greedy solution is optimal by comparing to the LP solution, we take this solution. This happens if:
1397 * - the greedy solution reaches the capacity, because then the LP solution is integral;
1398 * - the greedy solution has an objective that is at least the LP value rounded down in case that all profits are integer, too. */
1400 if( intprofits )
1403 {
1404 SCIPdebugMsg(scip, "Greedy solution is optimal.\n");
1405
1406 /* update solution information */
1407 if( solitems != NULL )
1408 {
1409 int l;
1410
1412
1413 /* collect items */
1414 for( l = 0; l < j; ++l )
1415 solitems[(*nsolitems)++] = myitems[l];
1416 for ( ; l < nmyitems; ++l )
1418 }
1419 /* update solution value */
1420 if( solval != NULL )
1421 {
1422 assert(greedysolvalue > 0.0);
1423 *solval += greedysolvalue;
1424 }
1425
1426 goto TERMINATE;
1427 }
1428
1429 /* in the following table we do not need the first minweight columns */
1430 capacity -= (minweight - 1);
1431
1432 /* we can only handle integers */
1433 if( capacity >= INT_MAX )
1434 {
1435 SCIPdebugMsg(scip, "Capacity is to big, so we cannot handle it here.\n");
1436
1437 *success = FALSE;
1438 goto TERMINATE;
1439 }
1440 assert(capacity < INT_MAX);
1441
1442 intcap = (int)capacity;
1443 assert(intcap >= 0);
1444 assert(nmyitems > 0);
1445 assert(sizeof(size_t) >= sizeof(int)); /*lint !e506*/ /* no following conversion should be messed up */
1446
1447 /* this condition checks whether we will try to allocate a correct number of bytes and do not have an overflow, while
1448 * computing the size for the allocation
1449 */
1450 if( intcap < 0 || (intcap > 0 && (((size_t)nmyitems) > (SIZE_MAX / (size_t)intcap / sizeof(*optvalues)) || ((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues) > ((size_t)INT_MAX) )) ) /*lint !e571*/
1451 {
1452 SCIPdebugMsg(scip, "Too much memory (%lu) would be consumed.\n", (unsigned long) (((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues))); /*lint !e571*/
1453
1454 *success = FALSE;
1455 goto TERMINATE;
1456 }
1457
1458 /* allocate temporary memory and check for memory exceedance */
1460 if( retcode == SCIP_NOMEMORY )
1461 {
1462 SCIPdebugMsg(scip, "Did not get enough memory.\n");
1463
1464 *success = FALSE;
1465 goto TERMINATE;
1466 }
1467 else
1468 {
1469 SCIP_CALL( retcode );
1470 }
1471
1472 SCIPdebugMsg(scip, "Start real exact algorithm.\n");
1473
1474 /* we memorize at each step the current minimal weight to later on know which value in our optvalues matrix is valid;
1475 * each value entries of the j-th row of optvalues is valid if the index is >= allcurrminweight[j], otherwise it is
1476 * invalid; a second possibility would be to clear the whole optvalues, which should be more expensive than storing
1477 * 'nmyitem' values
1478 */
1480 assert(myweights[0] - minweight < INT_MAX);
1481 currminweight = (int) (myweights[0] - minweight);
1483
1484 /* fills first row of dynamic programming table with optimal values */
1485 for( d = currminweight; d < intcap; ++d )
1486 optvalues[d] = myprofits[0];
1487
1488 /* fills dynamic programming table with optimal values */
1489 for( j = 1; j < nmyitems; ++j )
1490 {
1491 int intweight;
1492
1493 /* compute important part of weight, which will be represented in the table */
1494 intweight = (int)(myweights[j] - minweight);
1495 assert(0 <= intweight && intweight < intcap);
1496
1497 /* copy all nonzeros from row above */
1498 for( d = currminweight; d < intweight && d < intcap; ++d )
1499 optvalues[IDX(j,d)] = optvalues[IDX(j-1,d)];
1500
1501 /* update corresponding row */
1502 for( d = intweight; d < intcap; ++d )
1503 {
1504 /* if index d < current minweight then optvalues[IDX(j-1,d)] is not initialized, i.e. should be 0 */
1505 if( d < currminweight )
1506 optvalues[IDX(j,d)] = myprofits[j];
1507 else
1508 {
1509 SCIP_Real sumprofit;
1510
1511 if( d - myweights[j] < currminweight )
1513 else
1514 sumprofit = optvalues[IDX(j-1,(int)(d-myweights[j]))] + myprofits[j];
1515
1517 }
1518 }
1519
1520 /* update currminweight */
1521 if( intweight < currminweight )
1523
1525 }
1526
1527 /* update optimal solution by following the table */
1528 if( solitems != NULL )
1529 {
1531 d = intcap - 1;
1532
1533 SCIPdebugMsg(scip, "Fill the solution vector after solving exactly.\n");
1534
1535 /* insert all items in (non-) solution vector */
1536 for( j = nmyitems - 1; j > 0; --j )
1537 {
1538 /* if the following condition holds this means all remaining items does not fit anymore */
1539 if( d < allcurrminweight[j] )
1540 {
1541 /* we cannot have exceeded our capacity */
1542 assert((SCIP_Longint) d >= -minweight);
1543 break;
1544 }
1545
1546 /* collect solution items; the first condition means that no further item can fit anymore, but this does */
1547 if( d < allcurrminweight[j-1] || optvalues[IDX(j,d)] > optvalues[IDX(j-1,d)] )
1548 {
1549 solitems[(*nsolitems)++] = myitems[j];
1550
1551 /* check that we do not have an underflow */
1552 assert(myweights[j] <= (INT_MAX + (SCIP_Longint) d));
1553 d = (int)(d - myweights[j]);
1554 }
1555 /* collect non-solution items */
1556 else
1557 nonsolitems[(*nnonsolitems)++] = myitems[j];
1558 }
1559
1560 /* insert remaining items */
1561 if( d >= allcurrminweight[j] )
1562 {
1563 assert(j == 0);
1564 solitems[(*nsolitems)++] = myitems[j];
1565 }
1566 else
1567 {
1568 assert(j >= 0);
1570
1571 for( ; j >= 0; --j )
1573 }
1574
1575 assert(*nsolitems + *nnonsolitems == nitems);
1576 }
1577
1578 /* update solution value */
1579 if( solval != NULL )
1580 *solval += optvalues[IDX(nmyitems-1,intcap-1)];
1582
1583 /* free all temporary memory */
1585
1586 TERMINATE:
1590
1591 return SCIP_OKAY;
1592}
1593
1594/** solves knapsack problem in maximization form approximately by solving the LP-relaxation of the problem using Dantzig's
1595 * method and rounding down the solution; if needed, one can provide arrays to store all selected items and all not
1596 * selected items
1597 */
1599 SCIP* scip, /**< SCIP data structure */
1600 int nitems, /**< number of available items */
1601 SCIP_Longint* weights, /**< item weights */
1602 SCIP_Real* profits, /**< item profits */
1603 SCIP_Longint capacity, /**< capacity of knapsack */
1604 int* items, /**< item numbers */
1605 int* solitems, /**< array to store items in solution, or NULL */
1606 int* nonsolitems, /**< array to store items not in solution, or NULL */
1607 int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1608 int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1609 SCIP_Real* solval /**< pointer to store optimal solution value, or NULL */
1610 )
1611{
1612 SCIP_Real* tempsort;
1613 SCIP_Longint solitemsweight;
1614 SCIP_Real* realweights;
1615 int j;
1616 int criticalindex;
1617
1618 assert(weights != NULL);
1619 assert(profits != NULL);
1620 assert(capacity >= 0);
1621 assert(items != NULL);
1622 assert(nitems >= 0);
1623
1624 if( solitems != NULL )
1625 {
1626 *nsolitems = 0;
1627 *nnonsolitems = 0;
1628 }
1629 if( solval != NULL )
1630 *solval = 0.0;
1631
1632 /* initialize data for median search */
1635 for( j = nitems - 1; j >= 0; --j )
1636 {
1637 tempsort[j] = profits[j]/((SCIP_Real) weights[j]);
1638 realweights[j] = (SCIP_Real)weights[j];
1639 }
1640
1641 /* partially sort indices such that all elements that are larger than the break item appear first */
1642 SCIPselectWeightedDownRealLongRealInt(tempsort, weights, profits, items, realweights, (SCIP_Real)capacity, nitems, &criticalindex);
1643
1644 /* selects items as long as they fit into the knapsack */
1645 solitemsweight = 0;
1646 for( j = 0; j < nitems && solitemsweight + weights[j] <= capacity; ++j )
1647 {
1648 if( solitems != NULL )
1649 solitems[(*nsolitems)++] = items[j];
1650
1651 if( solval != NULL )
1652 (*solval) += profits[j];
1653 solitemsweight += weights[j];
1654 }
1655 if ( solitems != NULL )
1656 {
1657 for( ; j < nitems; j++ )
1659 }
1660
1663
1664 return SCIP_OKAY;
1665}
1666
1667#ifdef SCIP_DEBUG
1668/** prints all nontrivial GUB constraints and their LP solution values */
1669static
1670void GUBsetPrint(
1671 SCIP* scip, /**< SCIP data structure */
1672 SCIP_GUBSET* gubset, /**< GUB set data structure */
1673 SCIP_VAR** vars, /**< variables in knapsack constraint */
1674 SCIP_Real* solvals /**< solution values of variables in knapsack constraint; or NULL */
1675 )
1676{
1678 int c;
1679
1681
1682 SCIPdebugMsg(scip, " Nontrivial GUBs of current GUB set:\n");
1683
1684 /* print out all nontrivial GUB constraints, i.e., with more than one variable */
1685 for( c = 0; c < gubset->ngubconss; c++ )
1686 {
1687 SCIP_Real gubsolval;
1688
1689 assert(gubset->gubconss[c]->ngubvars >= 0);
1690
1691 /* nontrivial GUB */
1692 if( gubset->gubconss[c]->ngubvars > 1 )
1693 {
1694 int v;
1695
1696 gubsolval = 0.0;
1697 SCIPdebugMsg(scip, " GUB<%d>:\n", c);
1698
1699 /* print GUB var */
1700 for( v = 0; v < gubset->gubconss[c]->ngubvars; v++ )
1701 {
1702 int currentvar;
1703
1704 currentvar = gubset->gubconss[c]->gubvars[v];
1705 if( solvals != NULL )
1706 {
1707 gubsolval += solvals[currentvar];
1708 SCIPdebugMsg(scip, " +<%s>(%4.2f)\n", SCIPvarGetName(vars[currentvar]), solvals[currentvar]);
1709 }
1710 else
1711 {
1713 }
1714 }
1715
1716 /* check whether LP solution satisfies the GUB constraint */
1717 if( solvals != NULL )
1718 {
1719 SCIPdebugMsg(scip, " =%4.2f <= 1 %s\n", gubsolval,
1720 SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1721 }
1722 else
1723 {
1724 SCIPdebugMsg(scip, " <= 1 %s\n", SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1725 }
1727 }
1728 }
1729
1730 SCIPdebugMsg(scip, " --> %d/%d nontrivial GUBs\n", nnontrivialgubconss, gubset->ngubconss);
1731}
1732#endif
1733
1734/** creates an empty GUB constraint */
1735static
1737 SCIP* scip, /**< SCIP data structure */
1738 SCIP_GUBCONS** gubcons /**< pointer to store GUB constraint data */
1739 )
1740{
1741 assert(scip != NULL);
1742 assert(gubcons != NULL);
1743
1744 /* allocate memory for GUB constraint data structures */
1746 (*gubcons)->gubvarssize = GUBCONSGROWVALUE;
1747 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvars, (*gubcons)->gubvarssize) );
1748 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvarsstatus, (*gubcons)->gubvarssize) );
1749
1750 (*gubcons)->ngubvars = 0;
1751
1752 return SCIP_OKAY;
1753}
1754
1755/** frees GUB constraint */
1756static
1758 SCIP* scip, /**< SCIP data structure */
1759 SCIP_GUBCONS** gubcons /**< pointer to GUB constraint data structure */
1760 )
1761{
1762 assert(scip != NULL);
1763 assert(gubcons != NULL);
1764 assert((*gubcons)->gubvars != NULL);
1765 assert((*gubcons)->gubvarsstatus != NULL);
1766
1767 /* free allocated memory */
1768 SCIPfreeBufferArray(scip, &(*gubcons)->gubvarsstatus);
1769 SCIPfreeBufferArray(scip, &(*gubcons)->gubvars);
1771}
1772
1773/** adds variable to given GUB constraint */
1774static
1776 SCIP* scip, /**< SCIP data structure */
1777 SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1778 int var /**< index of given variable in knapsack constraint */
1779 )
1780{
1781 assert(scip != NULL);
1782 assert(gubcons != NULL);
1783 assert(gubcons->ngubvars >= 0 && gubcons->ngubvars < gubcons->gubvarssize);
1784 assert(gubcons->gubvars != NULL);
1785 assert(gubcons->gubvarsstatus != NULL);
1786 assert(var >= 0);
1787
1788 /* add variable to GUB constraint */
1789 gubcons->gubvars[gubcons->ngubvars] = var;
1790 gubcons->gubvarsstatus[gubcons->ngubvars] = GUBVARSTATUS_UNINITIAL;
1791 gubcons->ngubvars++;
1792
1793 /* increase space allocated to GUB constraint if the number of variables reaches the size */
1794 if( gubcons->ngubvars == gubcons->gubvarssize )
1795 {
1796 int newlen;
1797
1798 newlen = gubcons->gubvarssize + GUBCONSGROWVALUE;
1800 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1801
1802 gubcons->gubvarssize = newlen;
1803 }
1804
1805 return SCIP_OKAY;
1806}
1807
1808/** deletes variable from its current GUB constraint */
1809static
1811 SCIP* scip, /**< SCIP data structure */
1812 SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1813 int var, /**< index of given variable in knapsack constraint */
1814 int gubvarsidx /**< index of the variable in its current GUB constraint */
1815 )
1816{
1817 assert(scip != NULL);
1818 assert(gubcons != NULL);
1819 assert(var >= 0);
1820 assert(gubvarsidx >= 0 && gubvarsidx < gubcons->ngubvars);
1821 assert(gubcons->ngubvars >= gubvarsidx+1);
1822 assert(gubcons->gubvars[gubvarsidx] == var);
1823
1824 /* delete variable from GUB by swapping it replacing in by the last variable in the GUB constraint */
1825 gubcons->gubvars[gubvarsidx] = gubcons->gubvars[gubcons->ngubvars-1];
1826 gubcons->gubvarsstatus[gubvarsidx] = gubcons->gubvarsstatus[gubcons->ngubvars-1];
1827 gubcons->ngubvars--;
1828
1829 /* decrease space allocated for the GUB constraint, if the last GUBCONSGROWVALUE+1 array entries are now empty */
1830 if( gubcons->ngubvars < gubcons->gubvarssize - GUBCONSGROWVALUE && gubcons->ngubvars > 0 )
1831 {
1832 int newlen;
1833
1834 newlen = gubcons->gubvarssize - GUBCONSGROWVALUE;
1835
1837 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1838
1839 gubcons->gubvarssize = newlen;
1840 }
1841
1842 return SCIP_OKAY;
1843}
1844
1845/** moves variable from current GUB constraint to a different existing (nonempty) GUB constraint */
1846static
1848 SCIP* scip, /**< SCIP data structure */
1849 SCIP_GUBSET* gubset, /**< GUB set data structure */
1850 SCIP_VAR** vars, /**< variables in knapsack constraint */
1851 int var, /**< index of given variable in knapsack constraint */
1852 int oldgubcons, /**< index of old GUB constraint of given variable */
1853 int newgubcons /**< index of new GUB constraint of given variable */
1854 )
1855{
1856 int oldgubvaridx;
1857 int replacevar;
1858 int j;
1859
1860 assert(scip != NULL);
1861 assert(gubset != NULL);
1862 assert(var >= 0);
1866 assert(gubset->gubconssidx[var] == oldgubcons);
1867 assert(gubset->gubconss[oldgubcons]->ngubvars > 0);
1868 assert(gubset->gubconss[newgubcons]->ngubvars >= 0);
1869
1870 SCIPdebugMsg(scip, " moving variable<%s> from GUB<%d> to GUB<%d>\n", SCIPvarGetName(vars[var]), oldgubcons, newgubcons);
1871
1872 oldgubvaridx = gubset->gubvarsidx[var];
1873
1874 /* delete variable from old GUB constraint by replacing it by the last variable of the GUB constraint */
1876
1877 /* in GUB set, update stored index of variable in old GUB constraint for the variable used for replacement;
1878 * replacement variable is given by old position of the deleted variable
1879 */
1880 replacevar = gubset->gubconss[oldgubcons]->gubvars[oldgubvaridx];
1881 assert(gubset->gubvarsidx[replacevar] == gubset->gubconss[oldgubcons]->ngubvars);
1882 gubset->gubvarsidx[replacevar] = oldgubvaridx;
1883
1884 /* add variable to the end of new GUB constraint */
1886 assert(gubset->gubconss[newgubcons]->gubvars[gubset->gubconss[newgubcons]->ngubvars-1] == var);
1887
1888 /* in GUB set, update stored index of GUB of moved variable and stored index of variable in this GUB constraint */
1889 gubset->gubconssidx[var] = newgubcons;
1890 gubset->gubvarsidx[var] = gubset->gubconss[newgubcons]->ngubvars-1;
1891
1892 /* delete old GUB constraint if it became empty */
1893 if( gubset->gubconss[oldgubcons]->ngubvars == 0 )
1894 {
1895 SCIPdebugMsg(scip, "deleting empty GUB cons<%d> from current GUB set\n", oldgubcons);
1896#ifdef SCIP_DEBUG
1898#endif
1899
1900 /* free old GUB constraint */
1901 GUBconsFree(scip, &gubset->gubconss[oldgubcons]);
1902
1903 /* if empty GUB was not the last one in GUB set data structure, replace it by last GUB constraint */
1904 if( oldgubcons != gubset->ngubconss-1 )
1905 {
1906 gubset->gubconss[oldgubcons] = gubset->gubconss[gubset->ngubconss-1];
1907 gubset->gubconsstatus[oldgubcons] = gubset->gubconsstatus[gubset->ngubconss-1];
1908
1909 /* in GUB set, update stored index of GUB constraint for all variable of the GUB constraint used for replacement;
1910 * replacement GUB is given by old position of the deleted GUB
1911 */
1912 for( j = 0; j < gubset->gubconss[oldgubcons]->ngubvars; j++ )
1913 {
1914 assert(gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] == gubset->ngubconss-1);
1915 gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] = oldgubcons;
1916 }
1917 }
1918
1919 /* update number of GUB constraints */
1920 gubset->ngubconss--;
1921
1922 /* variable should be at given new position, unless new GUB constraint replaced empty old GUB constraint
1923 * (because it was at the end of the GUB constraint array)
1924 */
1925 assert(gubset->gubconssidx[var] == newgubcons
1926 || (newgubcons == gubset->ngubconss && gubset->gubconssidx[var] == oldgubcons));
1927 }
1928#ifndef NDEBUG
1929 else
1930 assert(gubset->gubconssidx[var] == newgubcons);
1931#endif
1932
1933 return SCIP_OKAY;
1934}
1935
1936/** swaps two variables in the same GUB constraint */
1937static
1939 SCIP* scip, /**< SCIP data structure */
1940 SCIP_GUBSET* gubset, /**< GUB set data structure */
1941 int var1, /**< first variable to be swapped */
1942 int var2 /**< second variable to be swapped */
1943 )
1944{
1945 int gubcons;
1946 int var1idx;
1948 int var2idx;
1950
1951 assert(scip != NULL);
1952 assert(gubset != NULL);
1953
1954 gubcons = gubset->gubconssidx[var1];
1955 assert(gubcons == gubset->gubconssidx[var2]);
1956
1957 /* nothing to be done if both variables are the same */
1958 if( var1 == var2 )
1959 return;
1960
1961 /* swap index and status of variables in GUB constraint */
1962 var1idx = gubset->gubvarsidx[var1];
1963 var1status = gubset->gubconss[gubcons]->gubvarsstatus[var1idx];
1964 var2idx = gubset->gubvarsidx[var2];
1965 var2status = gubset->gubconss[gubcons]->gubvarsstatus[var2idx];
1966
1967 gubset->gubvarsidx[var1] = var2idx;
1968 gubset->gubconss[gubcons]->gubvars[var1idx] = var2;
1969 gubset->gubconss[gubcons]->gubvarsstatus[var1idx] = var2status;
1970
1971 gubset->gubvarsidx[var2] = var1idx;
1972 gubset->gubconss[gubcons]->gubvars[var2idx] = var1;
1973 gubset->gubconss[gubcons]->gubvarsstatus[var2idx] = var1status;
1974}
1975
1976/** initializes partition of knapsack variables into nonoverlapping trivial GUB constraints (GUB with one variable) */
1977static
1979 SCIP* scip, /**< SCIP data structure */
1980 SCIP_GUBSET** gubset, /**< pointer to store GUB set data structure */
1981 int nvars, /**< number of variables in the knapsack constraint */
1982 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
1983 SCIP_Longint capacity /**< capacity of knapsack */
1984 )
1985{
1986 int i;
1987
1988 assert(scip != NULL);
1989 assert(gubset != NULL);
1990 assert(nvars > 0);
1991 assert(weights != NULL);
1992 assert(capacity >= 0);
1993
1994 /* allocate memory for GUB set data structures */
1996 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconss, nvars) );
1997 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconsstatus, nvars) );
1998 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconssidx, nvars) );
1999 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubvarsidx, nvars) );
2000 (*gubset)->ngubconss = nvars;
2001 (*gubset)->nvars = nvars;
2002
2003 /* initialize the set of GUB constraints */
2004 for( i = 0; i < nvars; i++ )
2005 {
2006 /* assign each variable to a new (trivial) GUB constraint */
2007 SCIP_CALL( GUBconsCreate(scip, &(*gubset)->gubconss[i]) );
2008 SCIP_CALL( GUBconsAddVar(scip, (*gubset)->gubconss[i], i) );
2009
2010 /* set status of GUB constraint to initial */
2011 (*gubset)->gubconsstatus[i] = GUBCONSSTATUS_UNINITIAL;
2012
2013 (*gubset)->gubconssidx[i] = i;
2014 (*gubset)->gubvarsidx[i] = 0;
2015 assert((*gubset)->gubconss[i]->ngubvars == 1);
2016
2017 /* already updated status of variable in GUB constraint if it exceeds the capacity of the knapsack */
2018 if( weights[i] > capacity )
2019 (*gubset)->gubconss[(*gubset)->gubconssidx[i]]->gubvarsstatus[(*gubset)->gubvarsidx[i]] = GUBVARSTATUS_CAPACITYEXCEEDED;
2020 }
2021
2022 return SCIP_OKAY;
2023}
2024
2025/** frees GUB set data structure */
2026static
2028 SCIP* scip, /**< SCIP data structure */
2029 SCIP_GUBSET** gubset /**< pointer to GUB set data structure */
2030 )
2031{
2032 int i;
2033
2034 assert(scip != NULL);
2035 assert(gubset != NULL);
2036 assert((*gubset)->gubconss != NULL);
2037 assert((*gubset)->gubconsstatus != NULL);
2038 assert((*gubset)->gubconssidx != NULL);
2039 assert((*gubset)->gubvarsidx != NULL);
2040
2041 /* free all GUB constraints */
2042 for( i = (*gubset)->ngubconss-1; i >= 0; --i )
2043 {
2044 assert((*gubset)->gubconss[i] != NULL);
2045 GUBconsFree(scip, &(*gubset)->gubconss[i]);
2046 }
2047
2048 /* free allocated memory */
2049 SCIPfreeBufferArray( scip, &(*gubset)->gubvarsidx );
2050 SCIPfreeBufferArray( scip, &(*gubset)->gubconssidx );
2051 SCIPfreeBufferArray( scip, &(*gubset)->gubconsstatus );
2052 SCIPfreeBufferArray( scip, &(*gubset)->gubconss );
2054}
2055
2056#ifndef NDEBUG
2057/** checks whether GUB set data structure is consistent */
2058static
2060 SCIP* scip, /**< SCIP data structure */
2061 SCIP_GUBSET* gubset, /**< GUB set data structure */
2062 SCIP_VAR** vars /**< variables in the knapsack constraint */
2063 )
2064{
2065 int i;
2066 int gubconsidx;
2067 int gubvaridx;
2068 SCIP_VAR* var1;
2069 SCIP_VAR* var2;
2070 SCIP_Bool var1negated;
2071 SCIP_Bool var2negated;
2072
2073 assert(scip != NULL);
2074 assert(gubset != NULL);
2075
2076 SCIPdebugMsg(scip, " GUB set consistency check:\n");
2077
2078 /* checks for all knapsack vars consistency of stored index of associated gubcons and corresponding index in gubvars */
2079 for( i = 0; i < gubset->nvars; i++ )
2080 {
2081 gubconsidx = gubset->gubconssidx[i];
2082 gubvaridx = gubset->gubvarsidx[i];
2083
2084 if( gubset->gubconss[gubconsidx]->gubvars[gubvaridx] != i )
2085 {
2086 SCIPdebugMsg(scip, " var<%d> should be in GUB<%d> at position<%d>, but stored is var<%d> instead\n", i,
2087 gubconsidx, gubvaridx, gubset->gubconss[gubconsidx]->gubvars[gubvaridx] );
2088 }
2089 assert(gubset->gubconss[gubconsidx]->gubvars[gubvaridx] == i);
2090 }
2091
2092 /* checks for each GUB whether all pairs of its variables have a common clique */
2093 for( i = 0; i < gubset->ngubconss; i++ )
2094 {
2095 int j;
2096
2097 for( j = 0; j < gubset->gubconss[i]->ngubvars; j++ )
2098 {
2099 int k;
2100
2101 /* get corresponding active problem variable */
2102 var1 = vars[gubset->gubconss[i]->gubvars[j]];
2105
2106 for( k = j+1; k < gubset->gubconss[i]->ngubvars; k++ )
2107 {
2108 /* get corresponding active problem variable */
2109 var2 = vars[gubset->gubconss[i]->gubvars[k]];
2112
2114 {
2115 SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2116 SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[j]]), k,
2117 SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[k]]));
2118 SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2121 }
2122
2123 /* @todo: in case we used also negated cliques for the GUB partition, this assert has to be changed */
2125 }
2126 }
2127 }
2128 SCIPdebugMsg(scip, " --> successful\n");
2129
2130 return SCIP_OKAY;
2131}
2132#endif
2133
2134/** calculates a partition of the given set of binary variables into cliques;
2135 * afterwards the output array contains one value for each variable, such that two variables got the same value iff they
2136 * were assigned to the same clique;
2137 * the first variable is always assigned to clique 0, and a variable can only be assigned to clique i if at least one of
2138 * the preceding variables was assigned to clique i-1;
2139 * note: in contrast to SCIPcalcCliquePartition(), variables with LP value 1 are put into trivial cliques (with one
2140 * variable) and for the remaining variables, a partition with a small number of cliques is constructed
2141 */
2142
2143static
2145 SCIP*const scip, /**< SCIP data structure */
2146 SCIP_VAR**const vars, /**< binary variables in the clique from which at most one can be set to 1 */
2147 int const nvars, /**< number of variables in the clique */
2148 int*const cliquepartition, /**< array of length nvars to store the clique partition */
2149 int*const ncliques, /**< pointer to store number of cliques actually contained in the partition */
2150 SCIP_Real* solvals /**< solution values of all given binary variables */
2151 )
2152{
2153 SCIP_VAR** tmpvars;
2155 SCIP_Bool* cliquevalues;
2156 SCIP_Bool* tmpvalues;
2157 int* varseq;
2158 int* sortkeys;
2159 int ncliquevars;
2161 int nignorevars;
2162 int nvarsused;
2163 int i;
2164
2165 assert(scip != NULL);
2166 assert(nvars == 0 || vars != NULL);
2167 assert(nvars == 0 || cliquepartition != NULL);
2168 assert(ncliques != NULL);
2169
2170 if( nvars == 0 )
2171 {
2172 *ncliques = 0;
2173 return SCIP_OKAY;
2174 }
2175
2176 /* allocate temporary memory for storing the variables of the current clique */
2183
2184 /* initialize the cliquepartition array with -1 */
2185 /* initialize the tmpvalues array */
2186 for( i = nvars - 1; i >= 0; --i )
2187 {
2188 tmpvalues[i] = TRUE;
2189 cliquepartition[i] = -1;
2190 }
2191
2192 /* get corresponding active problem variables */
2194
2195 /* ignore variables with LP value 1 (will be assigned to trivial GUBs at the end) and sort remaining variables
2196 * by nondecreasing number of cliques the variables are in
2197 */
2198 nignorevars = 0;
2199 nvarsused = 0;
2200 for( i = 0; i < nvars; i++ )
2201 {
2202 if( SCIPisFeasEQ(scip, solvals[i], 1.0) )
2203 {
2204 /* variables with LP value 1 are put to the end of varseq array and will not be sorted */
2206 nignorevars++;
2207 }
2208 else
2209 {
2210 /* remaining variables are put to the front of varseq array and will be sorted by their number of cliques */
2211 varseq[nvarsused] = i;
2213 nvarsused++;
2214 }
2215 }
2217
2218 /* sort variables with LP value less than 1 by nondecreasing order of the number of cliques they are in */
2220
2222
2223 /* calculate the clique partition */
2224 *ncliques = 0;
2225 for( i = 0; i < nvars; ++i )
2226 {
2227 if( cliquepartition[varseq[i]] == -1 )
2228 {
2229 int j;
2230
2231 /* variable starts a new clique */
2232 cliquepartition[varseq[i]] = *ncliques;
2233 cliquevars[0] = tmpvars[varseq[i]];
2235 ncliquevars = 1;
2236
2237 /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique and
2238 * if the variable has LP value 1 we do not want it to be in nontrivial cliques
2239 */
2240 if( SCIPvarIsActive(tmpvars[varseq[i]]) && i < nvarsused )
2241 {
2242 /* greedily fill up the clique */
2243 for( j = i + 1; j < nvarsused; ++j )
2244 {
2245 /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique */
2246 if( cliquepartition[varseq[j]] == -1 && SCIPvarIsActive(tmpvars[varseq[j]]) )
2247 {
2248 int k;
2249
2250 /* check if every variable in the actual clique is in clique with the new variable */
2251 for( k = ncliquevars - 1; k >= 0; --k )
2252 {
2254 cliquevalues[k], TRUE) )
2255 break;
2256 }
2257
2258 if( k == -1 )
2259 {
2260 /* put the variable into the same clique */
2261 cliquepartition[varseq[j]] = cliquepartition[varseq[i]];
2262 cliquevars[ncliquevars] = tmpvars[varseq[j]];
2264 ++ncliquevars;
2265 }
2266 }
2267 }
2268 }
2269
2270 /* this clique is finished */
2271 ++(*ncliques);
2272 }
2273 assert(cliquepartition[varseq[i]] >= 0 && cliquepartition[varseq[i]] < i + 1);
2274
2275 /* break if we reached the maximal number of comparisons */
2276 if( i * nvars > maxncliquevarscomp )
2277 break;
2278 }
2279 /* if we had too many variables fill up the cliquepartition and put each variable in a separate clique */
2280 for( ; i < nvars; ++i )
2281 {
2282 if( cliquepartition[varseq[i]] == -1 )
2283 {
2284 cliquepartition[varseq[i]] = *ncliques;
2285 ++(*ncliques);
2286 }
2287 }
2288
2289 /* free temporary memory */
2292 SCIPfreeBufferArray(scip, &tmpvars);
2296
2297 return SCIP_OKAY;
2298}
2299
2300/** constructs sophisticated partition of knapsack variables into non-overlapping GUBs; current partition uses trivial GUBs */
2301static
2303 SCIP* scip, /**< SCIP data structure */
2304 SCIP_GUBSET* gubset, /**< GUB set data structure */
2305 SCIP_VAR** vars, /**< variables in the knapsack constraint */
2306 SCIP_Real* solvals /**< solution values of all knapsack variables */
2307 )
2308{
2309 int* cliquepartition;
2310 int* gubfirstvar;
2311 int ncliques;
2313 int newgubconsidx;
2314 int cliqueidx;
2315 int nvars;
2316 int i;
2317
2318 assert(scip != NULL);
2319 assert(gubset != NULL);
2320 assert(vars != NULL);
2321
2322 nvars = gubset->nvars;
2323 assert(nvars >= 0);
2324
2325 /* allocate temporary memory for clique partition */
2326 SCIP_CALL( SCIPallocBufferArray(scip, &cliquepartition, nvars) );
2327
2328 /* compute sophisticated clique partition */
2329 SCIP_CALL( GUBsetCalcCliquePartition(scip, vars, nvars, cliquepartition, &ncliques, solvals) );
2330
2331 /* allocate temporary memory for GUB set data structure */
2333
2334 /* translate GUB partition into GUB set data structure */
2335 for( i = 0; i < ncliques; i++ )
2336 {
2337 /* initialize first variable for every GUB */
2338 gubfirstvar[i] = -1;
2339 }
2340 /* move every knapsack variable into GUB defined by clique partition */
2341 for( i = 0; i < nvars; i++ )
2342 {
2343 assert(cliquepartition[i] >= 0);
2344
2345 cliqueidx = cliquepartition[i];
2346 currentgubconsidx = gubset->gubconssidx[i];
2347 assert(gubset->gubconss[currentgubconsidx]->ngubvars == 1 );
2348
2349 /* variable is first element in GUB constraint defined by clique partition */
2350 if( gubfirstvar[cliqueidx] == -1 )
2351 {
2352 /* corresponding GUB constraint in GUB set data structure was already constructed (as initial trivial GUB);
2353 * note: no assert for gubconssidx, because it can changed due to deleting empty GUBs in GUBsetMoveVar()
2354 */
2355 assert(gubset->gubvarsidx[i] == 0);
2356 assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2357
2358 /* remember the first variable found for the current GUB */
2360 }
2361 /* variable is additional element of GUB constraint defined by clique partition */
2362 else
2363 {
2365
2366 /* move variable to GUB constraint defined by clique partition; index of this GUB constraint is given by the
2367 * first variable of this GUB constraint
2368 */
2369 newgubconsidx = gubset->gubconssidx[gubfirstvar[cliqueidx]];
2370 assert(newgubconsidx != currentgubconsidx); /* because initially every variable is in a different GUB */
2372
2373 assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2374 }
2375 }
2376
2377#ifdef SCIP_DEBUG
2378 /* prints GUB set data structure */
2379 GUBsetPrint(scip, gubset, vars, solvals);
2380#endif
2381
2382#ifndef NDEBUG
2383 /* checks consistency of GUB set data structure */
2385#endif
2386
2387 /* free temporary memory */
2389 SCIPfreeBufferArray(scip, &cliquepartition);
2390
2391 return SCIP_OKAY;
2392}
2393
2394/** gets a most violated cover C (\f$\sum_{j \in C} a_j > a_0\f$) for a given knapsack constraint \f$\sum_{j \in N} a_j x_j \leq a_0\f$
2395 * taking into consideration the following fixing: \f$j \in C\f$, if \f$j \in N_1 = \{j \in N : x^*_j = 1\}\f$ and
2396 * \f$j \in N \setminus C\f$, if \f$j \in N_0 = \{j \in N : x^*_j = 0\}\f$, if one exists.
2397 */
2398static
2400 SCIP* scip, /**< SCIP data structure */
2401 SCIP_VAR** vars, /**< variables in knapsack constraint */
2402 int nvars, /**< number of variables in knapsack constraint */
2403 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2404 SCIP_Longint capacity, /**< capacity of knapsack */
2405 SCIP_Real* solvals, /**< solution values of all problem variables */
2406 int* covervars, /**< pointer to store cover variables */
2407 int* noncovervars, /**< pointer to store noncover variables */
2408 int* ncovervars, /**< pointer to store number of cover variables */
2409 int* nnoncovervars, /**< pointer to store number of noncover variables */
2410 SCIP_Longint* coverweight, /**< pointer to store weight of cover */
2411 SCIP_Bool* found, /**< pointer to store whether a cover was found */
2412 SCIP_Bool modtransused, /**< should modified transformed separation problem be used to find cover */
2413 int* ntightened, /**< pointer to store number of variables with tightened upper bound */
2414 SCIP_Bool* fractional /**< pointer to store whether the LP sol for knapsack vars is fractional */
2415 )
2416{
2417 SCIP_Longint* transweights;
2418 SCIP_Real* transprofits;
2419 SCIP_Longint transcapacity;
2420 SCIP_Longint fixedonesweight;
2421 SCIP_Longint itemsweight;
2422 SCIP_Bool infeasible;
2423 int* fixedones;
2424 int* fixedzeros;
2425 int* items;
2426 int nfixedones;
2427 int nfixedzeros;
2428 int nitems;
2429 int j;
2430
2431 assert(scip != NULL);
2432 assert(vars != NULL);
2433 assert(nvars > 0);
2434 assert(weights != NULL);
2435 assert(capacity >= 0);
2436 assert(solvals != NULL);
2437 assert(covervars != NULL);
2442 assert(found != NULL);
2443 assert(ntightened != NULL);
2445
2446 SCIPdebugMsg(scip, " get cover for knapsack constraint\n");
2447
2448 /* allocates temporary memory */
2454
2455 *found = FALSE;
2456 *ncovervars = 0;
2457 *nnoncovervars = 0;
2458 *coverweight = 0;
2459 *fractional = TRUE;
2460
2461 /* gets the following sets
2462 * N_1 = {j in N : x*_j = 1} (fixedones),
2463 * N_0 = {j in N : x*_j = 0} (fixedzeros) and
2464 * N\‍(N_0 & N_1) (items),
2465 * where x*_j is the solution value of variable x_j
2466 */
2467 nfixedones = 0;
2468 nfixedzeros = 0;
2469 nitems = 0;
2470 fixedonesweight = 0;
2471 itemsweight = 0;
2472 *ntightened = 0;
2473 for( j = 0; j < nvars; j++ )
2474 {
2476
2477 /* tightens upper bound of x_j if weight of x_j is greater than capacity of knapsack */
2478 if( weights[j] > capacity )
2479 {
2480 SCIP_CALL( SCIPtightenVarUb(scip, vars[j], 0.0, FALSE, &infeasible, NULL) );
2481 assert(!infeasible);
2482 (*ntightened)++;
2483 continue;
2484 }
2485
2486 /* variable x_j has solution value one */
2487 if( SCIPisFeasEQ(scip, solvals[j], 1.0) )
2488 {
2489 fixedones[nfixedones] = j;
2490 nfixedones++;
2491 fixedonesweight += weights[j];
2492 }
2493 /* variable x_j has solution value zero */
2494 else if( SCIPisFeasEQ(scip, solvals[j], 0.0) )
2495 {
2496 fixedzeros[nfixedzeros] = j;
2497 nfixedzeros++;
2498 }
2499 /* variable x_j has fractional solution value */
2500 else
2501 {
2502 assert( SCIPisFeasGT(scip, solvals[j], 0.0) && SCIPisFeasLT(scip, solvals[j], 1.0) );
2503 items[nitems] = j;
2504 nitems++;
2505 itemsweight += weights[j];
2506 }
2507 }
2508 assert(nfixedones + nfixedzeros + nitems == nvars - (*ntightened));
2509
2510 /* sets whether the LP solution x* for the knapsack variables is fractional; if it is not fractional we stop
2511 * the separation routine
2512 */
2513 assert(nitems >= 0);
2514 if( nitems == 0 )
2515 {
2516 *fractional = FALSE;
2517 goto TERMINATE;
2518 }
2520
2521 /* transforms the traditional separation problem (under consideration of the following fixing:
2522 * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2523 *
2524 * min sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) z_j
2525 * sum_{j in N\‍(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2526 * z_j in {0,1}, j in N\‍(N_0 & N_1)
2527 *
2528 * to a knapsack problem in maximization form by complementing the variables
2529 *
2530 * sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) -
2531 * max sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) z_j
2532 * sum_{j in N\‍(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2533 * z_j in {0,1}, j in N\‍(N_0 & N_1)
2534 */
2535
2536 /* gets weight and profit of variables in transformed knapsack problem */
2537 for( j = 0; j < nitems; j++ )
2538 {
2539 transweights[j] = weights[items[j]];
2540 transprofits[j] = 1.0 - solvals[items[j]];
2541 }
2542 /* gets capacity of transformed knapsack problem */
2543 transcapacity = fixedonesweight + itemsweight - capacity - 1;
2544
2545 /* if capacity of transformed knapsack problem is less than zero, there is no cover
2546 * (when variables fixed to zero are not used)
2547 */
2548 if( transcapacity < 0 )
2549 {
2550 assert(!(*found));
2551 goto TERMINATE;
2552 }
2553
2554 if( modtransused )
2555 {
2556 /* transforms the modified separation problem (under consideration of the following fixing:
2557 * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2558 *
2559 * min sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) a_j z_j
2560 * sum_{j in N\‍(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2561 * z_j in {0,1}, j in N\‍(N_0 & N_1)
2562 *
2563 * to a knapsack problem in maximization form by complementing the variables
2564 *
2565 * sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) a_j -
2566 * max sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) a_j z_j
2567 * sum_{j in N\‍(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2568 * z_j in {0,1}, j in N\‍(N_0 & N_1)
2569 */
2570
2571 /* gets weight and profit of variables in modified transformed knapsack problem */
2572 for( j = 0; j < nitems; j++ )
2573 {
2574 transprofits[j] *= weights[items[j]];
2576 }
2577 }
2578
2579 /* solves (modified) transformed knapsack problem approximately by solving the LP-relaxation of the (modified)
2580 * transformed knapsack problem using Dantzig's method and rounding down the solution.
2581 * let z* be the solution, then
2582 * j in C, if z*_j = 0 and
2583 * i in N\C, if z*_j = 1.
2584 */
2587 /*assert(checkSolveKnapsack(scip, nitems, transweights, transprofits, items, weights, solvals, modtransused));*/
2588
2589 /* constructs cover C (sum_{j in C} a_j > a_0) */
2590 for( j = 0; j < *ncovervars; j++ )
2591 {
2592 (*coverweight) += weights[covervars[j]];
2593 }
2594
2595 /* adds all variables from N_1 to C */
2596 for( j = 0; j < nfixedones; j++ )
2597 {
2599 (*ncovervars)++;
2600 (*coverweight) += weights[fixedones[j]];
2601 }
2602
2603 /* adds all variables from N_0 to N\C */
2604 for( j = 0; j < nfixedzeros; j++ )
2605 {
2607 (*nnoncovervars)++;
2608 }
2609 assert((*ncovervars) + (*nnoncovervars) == nvars - (*ntightened));
2610 assert((*coverweight) > capacity);
2611 *found = TRUE;
2612
2613 TERMINATE:
2614 /* frees temporary memory */
2620
2621 SCIPdebugMsg(scip, " get cover for knapsack constraint -- end\n");
2622
2623 return SCIP_OKAY;
2624}
2625
2626#ifndef NDEBUG
2627/** checks if minweightidx is set correctly
2628 */
2629static
2631 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2632 SCIP_Longint capacity, /**< capacity of knapsack */
2633 int* covervars, /**< pointer to store cover variables */
2634 int ncovervars, /**< pointer to store number of cover variables */
2635 SCIP_Longint coverweight, /**< pointer to store weight of cover */
2636 int minweightidx, /**< index of variable in cover variables with minimum weight */
2637 int j /**< current index in cover variables */
2638 )
2639{
2640 SCIP_Longint minweight;
2641 int i;
2642
2643 assert(weights != NULL);
2644 assert(covervars != NULL);
2645 assert(ncovervars > 0);
2646
2647 minweight = weights[covervars[minweightidx]];
2648
2649 /* checks if all cover variables before index j have weight greater than minweight */
2650 for( i = 0; i < j; i++ )
2651 {
2652 assert(weights[covervars[i]] > minweight);
2653 if( weights[covervars[i]] <= minweight )
2654 return FALSE;
2655 }
2656
2657 /* checks if all variables before index j cannot be removed, i.e. i cannot be the next minweightidx */
2658 for( i = 0; i < j; i++ )
2659 {
2660 assert(coverweight - weights[covervars[i]] <= capacity);
2661 if( coverweight - weights[covervars[i]] > capacity )
2662 return FALSE;
2663 }
2664 return TRUE;
2665}
2666#endif
2667
2668
2669/** gets partition \f$(C_1,C_2)\f$ of minimal cover \f$C\f$, i.e. \f$C_1 \cup C_2 = C\f$ and \f$C_1 \cap C_2 = \emptyset\f$,
2670 * with \f$C_1\f$ not empty; chooses partition as follows \f$C_2 = \{ j \in C : x^*_j = 1 \}\f$ and \f$C_1 = C \setminus C_2\f$
2671 */
2672static
2674 SCIP* scip, /**< SCIP data structure */
2675 SCIP_Real* solvals, /**< solution values of all problem variables */
2676 int* covervars, /**< cover variables */
2677 int ncovervars, /**< number of cover variables */
2678 int* varsC1, /**< pointer to store variables in C1 */
2679 int* varsC2, /**< pointer to store variables in C2 */
2680 int* nvarsC1, /**< pointer to store number of variables in C1 */
2681 int* nvarsC2 /**< pointer to store number of variables in C2 */
2682 )
2683{
2684 int j;
2685
2686 assert(scip != NULL);
2687 assert(ncovervars >= 0);
2688 assert(solvals != NULL);
2689 assert(covervars != NULL);
2690 assert(varsC1 != NULL);
2691 assert(varsC2 != NULL);
2692 assert(nvarsC1 != NULL);
2693 assert(nvarsC2 != NULL);
2694
2695 *nvarsC1 = 0;
2696 *nvarsC2 = 0;
2697 for( j = 0; j < ncovervars; j++ )
2698 {
2699 assert(SCIPisFeasGT(scip, solvals[covervars[j]], 0.0));
2700
2701 /* variable has solution value one */
2702 if( SCIPisGE(scip, solvals[covervars[j]], 1.0) )
2703 {
2705 (*nvarsC2)++;
2706 }
2707 /* variable has solution value less than one */
2708 else
2709 {
2710 assert(SCIPisLT(scip, solvals[covervars[j]], 1.0));
2712 (*nvarsC1)++;
2713 }
2714 }
2715 assert((*nvarsC1) + (*nvarsC2) == ncovervars);
2716}
2717
2718/** changes given partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one and two (if possible) variables from
2719 * C2 to C1 if |C1| = 1 and |C1| = 0, respectively.
2720 */
2721static
2723 SCIP* scip, /**< SCIP data structure */
2724 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2725 int* varsC1, /**< pointer to store variables in C1 */
2726 int* varsC2, /**< pointer to store variables in C2 */
2727 int* nvarsC1, /**< pointer to store number of variables in C1 */
2728 int* nvarsC2 /**< pointer to store number of variables in C2 */
2729 )
2730{
2731 SCIP_Real* sortkeysC2;
2732 int j;
2733
2734 assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2735 assert(*nvarsC2 > 0);
2736
2737 /* allocates temporary memory */
2739
2740 /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2741 for( j = 0; j < *nvarsC2; j++ )
2742 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2744
2745 /* adds one or two variable from C2 with smallest weight to C1 and removes them from C2 */
2746 assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2747 while( *nvarsC1 < 2 && *nvarsC2 > 0 )
2748 {
2749 varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2750 (*nvarsC1)++;
2751 (*nvarsC2)--;
2752 }
2753
2754 /* frees temporary memory */
2756
2757 return SCIP_OKAY;
2758}
2759
2760/** changes given partition (C_1,C_2) of feasible set C, if |C1| = 1, by moving one variable from C2 to C1 */
2761static
2763 SCIP* scip, /**< SCIP data structure */
2764 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2765 int* varsC1, /**< pointer to store variables in C1 */
2766 int* varsC2, /**< pointer to store variables in C2 */
2767 int* nvarsC1, /**< pointer to store number of variables in C1 */
2768 int* nvarsC2 /**< pointer to store number of variables in C2 */
2769 )
2770{
2771 SCIP_Real* sortkeysC2;
2772 int j;
2773
2774 assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2775 assert(*nvarsC2 > 0);
2776
2777 /* allocates temporary memory */
2779
2780 /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2781 for( j = 0; j < *nvarsC2; j++ )
2782 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2784
2785 /* adds variable from C2 with smallest weight to C1 and removes it from C2 */
2786 assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2787 varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2788 (*nvarsC1)++;
2789 (*nvarsC2)--;
2790
2791 /* frees temporary memory */
2793
2794 return SCIP_OKAY;
2795}
2796
2797
2798/** gets partition \f$(F,R)\f$ of \f$N \setminus C\f$ where \f$C\f$ is a minimal cover, i.e. \f$F \cup R = N \setminus C\f$
2799 * and \f$F \cap R = \emptyset\f$; chooses partition as follows \f$R = \{ j \in N \setminus C : x^*_j = 0 \}\f$ and
2800 * \f$F = (N \setminus C) \setminus F\f$
2801 */
2802static
2804 SCIP* scip, /**< SCIP data structure */
2805 SCIP_Real* solvals, /**< solution values of all problem variables */
2806 int* noncovervars, /**< noncover variables */
2807 int nnoncovervars, /**< number of noncover variables */
2808 int* varsF, /**< pointer to store variables in F */
2809 int* varsR, /**< pointer to store variables in R */
2810 int* nvarsF, /**< pointer to store number of variables in F */
2811 int* nvarsR /**< pointer to store number of variables in R */
2812 )
2813{
2814 int j;
2815
2816 assert(scip != NULL);
2817 assert(nnoncovervars >= 0);
2818 assert(solvals != NULL);
2820 assert(varsF != NULL);
2821 assert(varsR != NULL);
2822 assert(nvarsF != NULL);
2823 assert(nvarsR != NULL);
2824
2825 *nvarsF = 0;
2826 *nvarsR = 0;
2827
2828 for( j = 0; j < nnoncovervars; j++ )
2829 {
2830 /* variable has solution value zero */
2831 if( SCIPisFeasEQ(scip, solvals[noncovervars[j]], 0.0) )
2832 {
2834 (*nvarsR)++;
2835 }
2836 /* variable has solution value greater than zero */
2837 else
2838 {
2839 assert(SCIPisFeasGT(scip, solvals[noncovervars[j]], 0.0));
2841 (*nvarsF)++;
2842 }
2843 }
2844 assert((*nvarsF) + (*nvarsR) == nnoncovervars);
2845}
2846
2847/** sorts variables in F, C_2, and R according to the second level lifting sequence that will be used in the sequential
2848 * lifting procedure
2849 */
2850static
2852 SCIP* scip, /**< SCIP data structure */
2853 SCIP_Real* solvals, /**< solution values of all problem variables */
2854 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2855 int* varsF, /**< pointer to store variables in F */
2856 int* varsC2, /**< pointer to store variables in C2 */
2857 int* varsR, /**< pointer to store variables in R */
2858 int nvarsF, /**< number of variables in F */
2859 int nvarsC2, /**< number of variables in C2 */
2860 int nvarsR /**< number of variables in R */
2861 )
2862{
2865 SCIP_Real* sortkeysC2;
2866 SCIP_Real* sortkeysR;
2867 int j;
2868
2869 assert(scip != NULL);
2870 assert(solvals != NULL);
2871 assert(weights != NULL);
2872 assert(varsF != NULL);
2873 assert(varsC2 != NULL);
2874 assert(varsR != NULL);
2875 assert(nvarsF >= 0);
2876 assert(nvarsC2 >= 0);
2877 assert(nvarsR >= 0);
2878
2879 /* allocates temporary memory */
2884
2885 /* gets sorting key for variables in F corresponding to the following lifting sequence
2886 * sequence 1: non-increasing absolute difference between x*_j and the value the variable is fixed to, i.e.
2887 * x*_1 >= x*_2 >= ... >= x*_|F|
2888 * in case of equality uses
2889 * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2890 */
2891 for( j = 0; j < nvarsF; j++ )
2892 {
2894 sortkeypairsF[j]->key1 = solvals[varsF[j]];
2895 sortkeypairsF[j]->key2 = (SCIP_Real) weights[varsF[j]];
2896 }
2897
2898 /* gets sorting key for variables in C_2 corresponding to the following lifting sequence
2899 * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2900 */
2901 for( j = 0; j < nvarsC2; j++ )
2902 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2903
2904 /* gets sorting key for variables in R corresponding to the following lifting sequence
2905 * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|R|
2906 */
2907 for( j = 0; j < nvarsR; j++ )
2908 sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
2909
2910 /* sorts F, C2 and R */
2911 if( nvarsF > 0 )
2912 {
2914 }
2915 if( nvarsC2 > 0 )
2916 {
2918 }
2919 if( nvarsR > 0)
2920 {
2922 }
2923
2924 /* frees temporary memory */
2929
2930 return SCIP_OKAY;
2931}
2932
2933/** categorizes GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of the GUBs
2934 * for the sequential GUB wise lifting procedure
2935 */
2936static
2938 SCIP* scip, /**< SCIP data structure */
2939 SCIP_GUBSET* gubset, /**< GUB set data structure */
2940 SCIP_Real* solvals, /**< solution values of variables in knapsack constraint */
2941 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2942 int* varsC1, /**< variables in C1 */
2943 int* varsC2, /**< variables in C2 */
2944 int* varsF, /**< variables in F */
2945 int* varsR, /**< variables in R */
2946 int nvarsC1, /**< number of variables in C1 */
2947 int nvarsC2, /**< number of variables in C2 */
2948 int nvarsF, /**< number of variables in F */
2949 int nvarsR, /**< number of variables in R */
2950 int* gubconsGC1, /**< pointer to store GUBs in GC1(GNC1+GOC1) */
2951 int* gubconsGC2, /**< pointer to store GUBs in GC2 */
2952 int* gubconsGFC1, /**< pointer to store GUBs in GFC1(GNC1+GF) */
2953 int* gubconsGR, /**< pointer to store GUBs in GR */
2954 int* ngubconsGC1, /**< pointer to store number of GUBs in GC1(GNC1+GOC1) */
2955 int* ngubconsGC2, /**< pointer to store number of GUBs in GC2 */
2956 int* ngubconsGFC1, /**< pointer to store number of GUBs in GFC1(GNC1+GF) */
2957 int* ngubconsGR, /**< pointer to store number of GUBs in GR */
2958 int* ngubconscapexceed, /**< pointer to store number of GUBs with only capacity exceeding variables */
2959 int* maxgubvarssize /**< pointer to store the maximal size of GUB constraints */
2960 )
2961{
2964 SCIP_Real* sortkeysC1;
2965 SCIP_Real* sortkeysC2;
2966 SCIP_Real* sortkeysR;
2967 int* nC1varsingubcons;
2968 int var;
2969 int gubconsidx;
2970 int varidx;
2971 int ngubconss;
2972 int ngubconsGOC1;
2973 int targetvar;
2974#ifndef NDEBUG
2975 int nvarsprocessed = 0;
2976#endif
2977 int i;
2978 int j;
2979
2980#if GUBSPLITGNC1GUBS
2981 SCIP_Bool gubconswithF;
2982 int origngubconss;
2983 origngubconss = gubset->ngubconss;
2984#endif
2985
2986 assert(scip != NULL);
2987 assert(gubset != NULL);
2988 assert(solvals != NULL);
2989 assert(weights != NULL);
2990 assert(varsC1 != NULL);
2991 assert(varsC2 != NULL);
2992 assert(varsF != NULL);
2993 assert(varsR != NULL);
2994 assert(nvarsC1 > 0);
2995 assert(nvarsC2 >= 0);
2996 assert(nvarsF >= 0);
2997 assert(nvarsR >= 0);
3001 assert(gubconsGR != NULL);
3007
3008 ngubconss = gubset->ngubconss;
3009 ngubconsGOC1 = 0;
3010
3011 /* GUBs are categorized into different types according to the variables in volved
3012 * - GOC1: involves variables in C1 only -- no C2, R, F
3013 * - GNC1: involves variables in C1 and F (and R) -- no C2
3014 * - GF: involves variables in F (and R) only -- no C1, C2
3015 * - GC2: involves variables in C2 only -- no C1, R, F
3016 * - GR: involves variables in R only -- no C1, C2, F
3017 * which requires splitting GUBs in case they include variable in F and R.
3018 *
3019 * afterwards all GUBs (except GOC1 GUBs, which we do not need to lift) are sorted by a two level lifting sequence.
3020 * - first ordering level is: GFC1 (GNC1+GF), GC2, and GR.
3021 * - second ordering level is
3022 * GFC1: non-increasing number of variables in F and non-increasing max{x*_k : k in GFC1_j} in case of equality
3023 * GC2: non-increasing max{ a_k : k in GC2_j}; note that |GFC2_j| = 1
3024 * GR: non-increasing max{ a_k : k in GR_j}
3025 *
3026 * in additon, another GUB union, which is helpful for the lifting procedure, is formed
3027 * - GC1: GUBs of category GOC1 and GNC1
3028 * with second ordering level non-decreasing min{ a_k : k in GC1_j };
3029 * note that min{ a_k : k in GC1_j } always comes from the first variable in the GUB
3030 */
3031
3032 /* allocates temporary memory */
3036
3037 /* to get the GUB lifting sequence, we first sort all variables in F, C2, and R
3038 * - F: non-increasing x*_j and non-increasing a_j in case of equality
3039 * - C2: non-increasing a_j
3040 * - R: non-increasing a_j
3041 * furthermore, sort C1 variables as needed for initializing the minweight table (non-increasing a_j).
3042 */
3043
3044 /* gets sorting key for variables in C1 corresponding to the following ordering
3045 * non-decreasing a_j, i.e. a_1 <= a_2 <= ... <= a_|C_1|
3046 */
3047 for( j = 0; j < nvarsC1; j++ )
3048 {
3049 /* gets sortkeys */
3050 sortkeysC1[j] = (SCIP_Real) weights[varsC1[j]];
3051
3052 /* update status of variable in its gub constraint */
3053 gubconsidx = gubset->gubconssidx[varsC1[j]];
3054 varidx = gubset->gubvarsidx[varsC1[j]];
3055 gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C1;
3056 }
3057
3058 /* gets sorting key for variables in F corresponding to the following ordering
3059 * non-increasing x*_j, i.e., x*_1 >= x*_2 >= ... >= x*_|F|, and
3060 * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|F| in case of equality
3061 * and updates status of each variable in F in GUB set data structure
3062 */
3063 for( j = 0; j < nvarsF; j++ )
3064 {
3065 /* update status of variable in its gub constraint */
3066 gubconsidx = gubset->gubconssidx[varsF[j]];
3067 varidx = gubset->gubvarsidx[varsF[j]];
3068 gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_F;
3069 }
3070
3071 /* gets sorting key for variables in C2 corresponding to the following ordering
3072 * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|C2|
3073 * and updates status of each variable in F in GUB set data structure
3074 */
3075 for( j = 0; j < nvarsC2; j++ )
3076 {
3077 /* gets sortkeys */
3078 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
3079
3080 /* update status of variable in its gub constraint */
3081 gubconsidx = gubset->gubconssidx[varsC2[j]];
3082 varidx = gubset->gubvarsidx[varsC2[j]];
3083 gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C2;
3084 }
3085
3086 /* gets sorting key for variables in R corresponding to the following ordering
3087 * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|R|
3088 * and updates status of each variable in F in GUB set data structure
3089 */
3090 for( j = 0; j < nvarsR; j++ )
3091 {
3092 /* gets sortkeys */
3093 sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
3094
3095 /* update status of variable in its gub constraint */
3096 gubconsidx = gubset->gubconssidx[varsR[j]];
3097 varidx = gubset->gubvarsidx[varsR[j]];
3098 gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_R;
3099 }
3100
3101 /* sorts C1, F, C2 and R */
3102 assert(nvarsC1 > 0);
3104
3105 if( nvarsC2 > 0 )
3106 {
3108 }
3109 if( nvarsR > 0)
3110 {
3112 }
3113
3114 /* frees temporary memory */
3118
3119 /* allocate and initialize temporary memory for sorting GUB constraints */
3124 for( i = 0; i < ngubconss; i++)
3125 {
3127 sortkeypairsGFC1[i]->key1 = 0.0;
3128 sortkeypairsGFC1[i]->key2 = 0.0;
3129 }
3130 *ngubconsGC1 = 0;
3131 *ngubconsGC2 = 0;
3132 *ngubconsGFC1 = 0;
3133 *ngubconsGR = 0;
3134 *ngubconscapexceed = 0;
3135 *maxgubvarssize = 0;
3136
3137#ifndef NDEBUG
3138 for( i = 0; i < gubset->ngubconss; i++ )
3139 assert(gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL);
3140#endif
3141
3142 /* stores GUBs of group GC1 (GOC1+GNC1) and part of the GUBs of group GFC1 (GNC1 GUBs) and sorts variables in these GUBs
3143 * s.t. C1 variables come first (will automatically be sorted by non-decreasing weight).
3144 * gets sorting keys for GUBs of type GFC1 corresponding to the following ordering
3145 * non-increasing number of variables in F, and
3146 * non-increasing max{x*_k : k in GFC1_j} in case of equality
3147 */
3148 for( i = 0; i < nvarsC1; i++ )
3149 {
3150 int nvarsC1capexceed;
3151
3152 nvarsC1capexceed = 0;
3153
3154 var = varsC1[i];
3155 gubconsidx = gubset->gubconssidx[var];
3156 varidx = gubset->gubvarsidx[var];
3157
3159 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C1);
3160
3161 /* current C1 variable is put to the front of its GUB where C1 part is stored by non-decreasing weigth;
3162 * note that variables in C1 are already sorted by non-decreasing weigth
3163 */
3164 targetvar = gubset->gubconss[gubconsidx]->gubvars[nC1varsingubcons[gubconsidx]];
3167
3168 /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3169 if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3170 {
3172 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3173 continue;
3174 }
3175
3176 /* determine the status of the current GUB constraint, GOC1 or GNC1; GUBs involving R variables are split into
3177 * GOC1/GNC1 and GF, if wanted. also update sorting key if GUB is of type GFC1 (GNC1)
3178 */
3179#if GUBSPLITGNC1GUBS
3181#endif
3182 for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3183 {
3184 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2);
3185
3186 /* C1-variable: update number of C1/capacity exceeding variables */
3187 if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_C1 )
3188 {
3190#ifndef NDEBUG
3192#endif
3193 }
3194 /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3195 else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3196 {
3197#if GUBSPLITGNC1GUBS
3199#endif
3200 sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3201
3202 if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3203 sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3204 }
3205 else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_CAPACITYEXCEEDED )
3206 {
3208 }
3209 else
3210 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_R);
3211 }
3212
3213 /* update set of GC1 GUBs */
3215 (*ngubconsGC1)++;
3216
3217 /* update maximum size of all GUB constraints */
3218 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3219 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3220
3221 /* set status of GC1-GUB (GOC1 or GNC1) and update set of GFC1 GUBs */
3222 if( nvarsC1capexceed == gubset->gubconss[gubconsidx]->ngubvars )
3223 {
3225 ngubconsGOC1++;
3226 }
3227 else
3228 {
3229#if GUBSPLITGNC1GUBS
3230 /* only variables in C1 and R -- no in F: GUB will be split into GR and GOC1 GUBs */
3231 if( !gubconswithF )
3232 {
3234
3235 assert(gubset->ngubconss < gubset->nvars);
3236
3237 /* create a new GUB for GR part of splitting */
3238 SCIP_CALL( GUBconsCreate(scip, &gubset->gubconss[gubset->ngubconss]) );
3239 gubset->ngubconss++;
3240 ngubconss = gubset->ngubconss;
3241
3242 /* fill GR with R variables in current GUB */
3243 for( j = gubset->gubconss[gubconsidx]->ngubvars-1; j >= 0; j-- )
3244 {
3245 movevarstatus = gubset->gubconss[gubconsidx]->gubvarsstatus[j];
3247 {
3249 SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, gubset->gubconss[gubconsidx]->gubvars[j],
3250 gubconsidx, ngubconss-1) );
3251 gubset->gubconss[ngubconss-1]->gubvarsstatus[gubset->gubconss[ngubconss-1]->ngubvars-1] =
3253 }
3254 }
3255
3257 ngubconsGOC1++;
3258
3261 (*ngubconsGR)++;
3262 }
3263 /* variables in C1, F, and maybe R: GNC1 GUB */
3264 else
3265 {
3267
3270 (*ngubconsGFC1)++;
3271 }
3272#else
3275 (*ngubconsGFC1)++;
3276#endif
3277 }
3278 }
3279
3280 /* stores GUBs of group GC2 (only trivial GUBs); sorting is not required because the C2 variables (which we loop over)
3281 * are already sorted correctly
3282 */
3283 for( i = 0; i < nvarsC2; i++ )
3284 {
3285 var = varsC2[i];
3286 gubconsidx = gubset->gubconssidx[var];
3287 varidx = gubset->gubvarsidx[var];
3288
3290 assert(gubset->gubconss[gubconsidx]->ngubvars == 1);
3291 assert(varidx == 0);
3292 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C2);
3293 assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_UNINITIAL);
3294
3295 /* set status of GC2 GUB */
3297
3298 /* update group of GC2 GUBs */
3300 (*ngubconsGC2)++;
3301
3302 /* update maximum size of all GUB constraints */
3303 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3304 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3305
3306#ifndef NDEBUG
3308#endif
3309 }
3310
3311 /* stores remaining part of the GUBs of group GFC1 (GF GUBs) and gets GUB sorting keys corresp. to following ordering
3312 * non-increasing number of variables in F, and
3313 * non-increasing max{x*_k : k in GFC1_j} in case of equality
3314 */
3315 for( i = 0; i < nvarsF; i++ )
3316 {
3317 var = varsF[i];
3318 gubconsidx = gubset->gubconssidx[var];
3319 varidx = gubset->gubvarsidx[var];
3320
3322 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_F);
3323
3324#ifndef NDEBUG
3326#endif
3327
3328 /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3329 if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3330 {
3332 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3333 continue;
3334 }
3335
3336 /* set status of GF GUB */
3338
3339 /* update sorting key of corresponding GFC1 GUB */
3340 for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3341 {
3342 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2
3343 && gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C1);
3344
3345 /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3346 if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3347 {
3348 sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3349
3350 if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3351 sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3352 }
3353 }
3354
3355 /* update set of GFC1 GUBs */
3357 (*ngubconsGFC1)++;
3358
3359 /* update maximum size of all GUB constraints */
3360 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3361 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3362 }
3363
3364 /* stores GUBs of group GR; sorting is not required because the R variables (which we loop over) are already sorted
3365 * correctly
3366 */
3367 for( i = 0; i < nvarsR; i++ )
3368 {
3369 var = varsR[i];
3370 gubconsidx = gubset->gubconssidx[var];
3371 varidx = gubset->gubvarsidx[var];
3372
3374 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_R);
3375
3376#ifndef NDEBUG
3378#endif
3379
3380 /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3381 if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3382 {
3384 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3385 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3386 continue;
3387 }
3388
3389 /* set status of GR GUB */
3391
3392 /* update set of GR GUBs */
3394 (*ngubconsGR)++;
3395
3396 /* update maximum size of all GUB constraints */
3397 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3398 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3399 }
3401
3402 /* update number of GUBs with only capacity exceeding variables (will not be used for lifting) */
3403 (*ngubconscapexceed) = ngubconss - (ngubconsGOC1 + (*ngubconsGC2) + (*ngubconsGFC1) + (*ngubconsGR));
3405#ifndef NDEBUG
3406 {
3407 int check;
3408
3409 check = 0;
3410
3411 /* remaining not handled GUBs should only contain capacity exceeding variables */
3412 for( i = 0; i < ngubconss; i++ )
3413 {
3414 if( gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL )
3415 check++;
3416 }
3417 assert(check == *ngubconscapexceed);
3418 }
3419#endif
3420
3421 /* sort GFCI GUBs according to computed sorting keys */
3422 if( (*ngubconsGFC1) > 0 )
3423 {
3425 }
3426
3427 /* free temporary memory */
3428#if GUBSPLITGNC1GUBS
3430#endif
3434
3435 return SCIP_OKAY;
3436}
3437
3438/** enlarges minweight table to at least the given length */
3439static
3441 SCIP* scip, /**< SCIP data structure */
3442 SCIP_Longint** minweightsptr, /**< pointer to minweights table */
3443 int* minweightslen, /**< pointer to store number of entries in minweights table (incl. z=0) */
3444 int* minweightssize, /**< pointer to current size of minweights table */
3445 int newlen /**< new length of minweights table */
3446 )
3447{
3448 int j;
3449
3453 assert(*minweightslen >= 0);
3455 assert(*minweightssize >= 0);
3456
3457 if( newlen > *minweightssize )
3458 {
3459 int newsize;
3460
3461 /* reallocate table memory */
3465 }
3467
3468 /* initialize new elements */
3469 for( j = *minweightslen; j < newlen; ++j )
3472
3473 return SCIP_OKAY;
3474}
3475
3476/** lifts given inequality
3477 * sum_{j in M_1} x_j <= alpha_0
3478 * valid for
3479 * S^0 = { x in {0,1}^|M_1| : sum_{j in M_1} a_j x_j <= a_0 - sum_{j in M_2} a_j }
3480 * to a valid inequality
3481 * sum_{j in M_1} x_j + sum_{j in F} alpha_j x_j + sum_{j in M_2} alpha_j x_j + sum_{j in R} alpha_j x_j
3482 * <= alpha_0 + sum_{j in M_2} alpha_j
3483 * for
3484 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 };
3485 * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in M_2, and
3486 * sequential up-lifting for the variables in R; procedure can be used to strengthen minimal cover inequalities and
3487 * extended weight inequalities.
3488 */
3489static
3491 SCIP* scip, /**< SCIP data structure */
3492 SCIP_VAR** vars, /**< variables in knapsack constraint */
3493 int nvars, /**< number of variables in knapsack constraint */
3494 int ntightened, /**< number of variables with tightened upper bound */
3495 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3496 SCIP_Longint capacity, /**< capacity of knapsack */
3497 SCIP_Real* solvals, /**< solution values of all problem variables */
3498 int* varsM1, /**< variables in M_1 */
3499 int* varsM2, /**< variables in M_2 */
3500 int* varsF, /**< variables in F */
3501 int* varsR, /**< variables in R */
3502 int nvarsM1, /**< number of variables in M_1 */
3503 int nvarsM2, /**< number of variables in M_2 */
3504 int nvarsF, /**< number of variables in F */
3505 int nvarsR, /**< number of variables in R */
3506 int alpha0, /**< rights hand side of given valid inequality */
3507 int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3508 SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3509 int* liftrhs /**< pointer to store right hand side of the lifted valid inequality */
3510 )
3511{
3512 SCIP_Longint* minweights;
3513 SCIP_Real* sortkeys;
3514 SCIP_Longint fixedonesweight;
3515 int minweightssize;
3516 int minweightslen;
3517 int j;
3518 int w;
3519
3520 assert(scip != NULL);
3521 assert(vars != NULL);
3522 assert(nvars >= 0);
3523 assert(weights != NULL);
3524 assert(capacity >= 0);
3525 assert(solvals != NULL);
3526 assert(varsM1 != NULL);
3527 assert(varsM2 != NULL);
3528 assert(varsF != NULL);
3529 assert(varsR != NULL);
3530 assert(nvarsM1 >= 0 && nvarsM1 <= nvars - ntightened);
3531 assert(nvarsM2 >= 0 && nvarsM2 <= nvars - ntightened);
3532 assert(nvarsF >= 0 && nvarsF <= nvars - ntightened);
3533 assert(nvarsR >= 0 && nvarsR <= nvars - ntightened);
3534 assert(nvarsM1 + nvarsM2 + nvarsF + nvarsR == nvars - ntightened);
3535 assert(alpha0 >= 0);
3536 assert(liftcoefs != NULL);
3537 assert(cutact != NULL);
3538 assert(liftrhs != NULL);
3539
3540 /* allocates temporary memory */
3541 minweightssize = nvarsM1 + 1;
3544
3545 /* initializes data structures */
3547 *cutact = 0.0;
3548
3549 /* sets lifting coefficient of variables in M1, sorts variables in M1 such that a_1 <= a_2 <= ... <= a_|M1|
3550 * and calculates activity of the current valid inequality
3551 */
3552 for( j = 0; j < nvarsM1; j++ )
3553 {
3554 assert(liftcoefs[varsM1[j]] == 0);
3555 liftcoefs[varsM1[j]] = 1;
3556 sortkeys[j] = (SCIP_Real) (weights[varsM1[j]]);
3557 (*cutact) += solvals[varsM1[j]];
3558 }
3559
3561
3562 /* initializes (i = 1) the minweight table, defined as: minweights_i[w] =
3563 * min sum_{j in M_1} a_j x_j + sum_{k=1}^{i-1} a_{j_k} x_{j_k}
3564 * s.t. sum_{j in M_1} x_j + sum_{k=1}^{i-1} alpha_{j_k} x_{j_k} >= w
3565 * x_j in {0,1} for j in M_1 & {j_i,...,j_i-1},
3566 * for i = 1,...,t with t = |N\M1| and w = 0,...,|M1| + sum_{k=1}^{i-1} alpha_{j_k};
3567 */
3568 minweights[0] = 0;
3569 for( w = 1; w <= nvarsM1; w++ )
3570 minweights[w] = minweights[w-1] + weights[varsM1[w-1]];
3571 minweightslen = nvarsM1 + 1;
3572
3573 /* gets sum of weights of variables fixed to one, i.e. sum of weights of variables in M_2 */
3574 fixedonesweight = 0;
3575 for( j = 0; j < nvarsM2; j++ )
3576 fixedonesweight += weights[varsM2[j]];
3577 assert(fixedonesweight >= 0);
3578
3579 /* initializes right hand side of lifted valid inequality */
3580 *liftrhs = alpha0;
3581
3582 /* sequentially up-lifts all variables in F: */
3583 for( j = 0; j < nvarsF; j++ )
3584 {
3585 SCIP_Longint weight;
3586 int liftvar;
3587 int liftcoef;
3588 int z;
3589
3590 liftvar = varsF[j];
3591 weight = weights[liftvar];
3592 assert(liftvar >= 0 && liftvar < nvars);
3593 assert(SCIPisFeasGT(scip, solvals[liftvar], 0.0));
3594 assert(weight > 0);
3595
3596 /* knapsack problem is infeasible:
3597 * sets z = 0
3598 */
3599 if( capacity - fixedonesweight - weight < 0 )
3600 {
3601 z = 0;
3602 }
3603 /* knapsack problem is feasible:
3604 * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
3605 * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
3606 */
3607 else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
3608 {
3609 z = *liftrhs;
3610 }
3611 /* knapsack problem is feasible:
3612 * uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} }
3613 */
3614 else
3615 {
3616 int left;
3617 int right;
3618 int middle;
3619
3620 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
3621 left = 0;
3622 right = (*liftrhs) + 1;
3623 while( left < right - 1 )
3624 {
3625 middle = (left + right) / 2;
3626 assert(0 <= middle && middle < minweightslen);
3627 if( minweights[middle] <= capacity - fixedonesweight - weight )
3628 left = middle;
3629 else
3630 right = middle;
3631 }
3632 assert(left == right - 1);
3633 assert(0 <= left && left < minweightslen);
3634 assert(minweights[left] <= capacity - fixedonesweight - weight );
3635 assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
3636
3637 /* now z = left */
3638 z = left;
3639 assert(z <= *liftrhs);
3640 }
3641
3642 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3643 liftcoef = (*liftrhs) - z;
3645 assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
3646
3647 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3648 if( liftcoef == 0 )
3649 continue;
3650
3651 /* updates activity of current valid inequality */
3652 (*cutact) += liftcoef * solvals[liftvar];
3653
3654 /* enlarges current minweight table:
3655 * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3656 * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3657 * and sets minweights_i[w] = infinity for
3658 * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3659 */
3661
3662 /* updates minweight table: minweight_i+1[w] =
3663 * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3664 * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3665 */
3666 for( w = minweightslen - 1; w >= 0; w-- )
3667 {
3668 SCIP_Longint min;
3669 if( w < liftcoef )
3670 {
3671 min = MIN(minweights[w], weight);
3672 minweights[w] = min;
3673 }
3674 else
3675 {
3676 assert(w >= liftcoef);
3677 min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3678 minweights[w] = min;
3679 }
3680 }
3681 }
3682 assert(minweights[0] == 0);
3683
3684 /* sequentially down-lifts all variables in M_2: */
3685 for( j = 0; j < nvarsM2; j++ )
3686 {
3687 SCIP_Longint weight;
3688 int liftvar;
3689 int liftcoef;
3690 int left;
3691 int right;
3692 int middle;
3693 int z;
3694
3695 liftvar = varsM2[j];
3696 weight = weights[liftvar];
3697 assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
3698 assert(liftvar >= 0 && liftvar < nvars);
3699 assert(weight > 0);
3700
3701 /* uses binary search to find
3702 * z = max { w : 0 <= w <= |M_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
3703 */
3704 left = 0;
3705 right = minweightslen;
3706 while( left < right - 1 )
3707 {
3708 middle = (left + right) / 2;
3709 assert(0 <= middle && middle < minweightslen);
3710 if( minweights[middle] <= capacity - fixedonesweight + weight )
3711 left = middle;
3712 else
3713 right = middle;
3714 }
3715 assert(left == right - 1);
3716 assert(0 <= left && left < minweightslen);
3717 assert(minweights[left] <= capacity - fixedonesweight + weight );
3718 assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight + weight);
3719
3720 /* now z = left */
3721 z = left;
3722 assert(z >= *liftrhs);
3723
3724 /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
3725 liftcoef = z - (*liftrhs);
3727 assert(liftcoef >= 0);
3728
3729 /* updates sum of weights of variables fixed to one */
3730 fixedonesweight -= weight;
3731
3732 /* updates right-hand side of current valid inequality */
3733 (*liftrhs) += liftcoef;
3734 assert(*liftrhs >= alpha0);
3735
3736 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3737 if( liftcoef == 0 )
3738 continue;
3739
3740 /* updates activity of current valid inequality */
3741 (*cutact) += liftcoef * solvals[liftvar];
3742
3743 /* enlarges current minweight table:
3744 * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3745 * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3746 * and sets minweights_i[w] = infinity for
3747 * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3748 */
3750
3751 /* updates minweight table: minweight_i+1[w] =
3752 * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3753 * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3754 */
3755 for( w = minweightslen - 1; w >= 0; w-- )
3756 {
3757 SCIP_Longint min;
3758 if( w < liftcoef )
3759 {
3760 min = MIN(minweights[w], weight);
3761 minweights[w] = min;
3762 }
3763 else
3764 {
3765 assert(w >= liftcoef);
3766 min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3767 minweights[w] = min;
3768 }
3769 }
3770 }
3771 assert(fixedonesweight == 0);
3772 assert(*liftrhs >= alpha0);
3773
3774 /* sequentially up-lifts all variables in R: */
3775 for( j = 0; j < nvarsR; j++ )
3776 {
3777 SCIP_Longint weight;
3778 int liftvar;
3779 int liftcoef;
3780 int z;
3781
3782 liftvar = varsR[j];
3783 weight = weights[liftvar];
3784 assert(liftvar >= 0 && liftvar < nvars);
3785 assert(SCIPisFeasEQ(scip, solvals[liftvar], 0.0));
3786 assert(weight > 0);
3787 assert(capacity - weight >= 0);
3788 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
3789
3790 /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
3791 * if minweights_i[liftrhs] <= a_0 - a_{j_i}
3792 */
3793 if( minweights[*liftrhs] <= capacity - weight )
3794 {
3795 z = *liftrhs;
3796 }
3797 /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
3798 */
3799 else
3800 {
3801 int left;
3802 int right;
3803 int middle;
3804
3805 left = 0;
3806 right = (*liftrhs) + 1;
3807 while( left < right - 1)
3808 {
3809 middle = (left + right) / 2;
3810 assert(0 <= middle && middle < minweightslen);
3811 if( minweights[middle] <= capacity - weight )
3812 left = middle;
3813 else
3814 right = middle;
3815 }
3816 assert(left == right - 1);
3817 assert(0 <= left && left < minweightslen);
3818 assert(minweights[left] <= capacity - weight );
3819 assert(left == minweightslen - 1 || minweights[left+1] > capacity - weight);
3820
3821 /* now z = left */
3822 z = left;
3823 assert(z <= *liftrhs);
3824 }
3825
3826 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3827 liftcoef = (*liftrhs) - z;
3829 assert(liftcoef >= 0 && liftcoef <= *liftrhs);
3830
3831 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3832 if( liftcoef == 0 )
3833 continue;
3834
3835 /* updates activity of current valid inequality */
3836 (*cutact) += liftcoef * solvals[liftvar];
3837
3838 /* updates minweight table: minweight_i+1[w] =
3839 * min{ minweight_i[w], a_{j_i}}, if w < alpha_j_i
3840 * min{ minweight_i[w], minweight_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3841 */
3842 for( w = *liftrhs; w >= 0; w-- )
3843 {
3844 SCIP_Longint min;
3845 if( w < liftcoef )
3846 {
3847 min = MIN(minweights[w], weight);
3848 minweights[w] = min;
3849 }
3850 else
3851 {
3852 assert(w >= liftcoef);
3853 min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3854 minweights[w] = min;
3855 }
3856 }
3857 }
3858
3859 /* frees temporary memory */
3862
3863 return SCIP_OKAY;
3864}
3865
3866/** adds two minweight values in a safe way, i.e,, ensures no overflow */
3867static
3869 SCIP_Longint val1, /**< first value to add */
3870 SCIP_Longint val2 /**< second value to add */
3871 )
3872{
3873 assert(val1 >= 0);
3874 assert(val2 >= 0);
3875
3877 return SCIP_LONGINT_MAX;
3878 else
3879 {
3881 return (val1 + val2);
3882 }
3883}
3884
3885/** computes minweights table for lifting with GUBs by combining unfished and fished tables */
3886static
3888 SCIP_Longint* minweights, /**< minweight table to compute */
3889 SCIP_Longint* finished, /**< given finished table */
3890 SCIP_Longint* unfinished, /**< given unfinished table */
3891 int minweightslen /**< length of minweight, finished, and unfinished tables */
3892 )
3893{
3894 int w1;
3895 int w2;
3896
3897 /* minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
3898 * note that finished and unfished arrays sorted by non-decreasing weight
3899 */
3900
3901 /* initialize minweight with w2 = 0 */
3902 w2 = 0;
3903 assert(unfinished[w2] == 0);
3904 for( w1 = 0; w1 < minweightslen; w1++ )
3906
3907 /* consider w2 = 1, ..., minweightslen-1 */
3908 for( w2 = 1; w2 < minweightslen; w2++ )
3909 {
3911 break;
3912
3913 for( w1 = 0; w1 < minweightslen - w2; w1++ )
3914 {
3915 SCIP_Longint temp;
3916
3918 if( temp <= minweights[w1+w2] )
3919 minweights[w1+w2] = temp;
3920 }
3921 }
3922}
3923
3924/** lifts given inequality
3925 * sum_{j in C_1} x_j <= alpha_0
3926 * valid for
3927 * S^0 = { x in {0,1}^|C_1| : sum_{j in C_1} a_j x_j <= a_0 - sum_{j in C_2} a_j;
3928 * sum_{j in Q_i} x_j <= 1, forall i in I }
3929 * to a valid inequality
3930 * sum_{j in C_1} x_j + sum_{j in F} alpha_j x_j + sum_{j in C_2} alpha_j x_j + sum_{j in R} alpha_j x_j
3931 * <= alpha_0 + sum_{j in C_2} alpha_j
3932 * for
3933 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0; sum_{j in Q_i} x_j <= 1, forall i in I };
3934 * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
3935 * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
3936 * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
3937 */
3938static
3940 SCIP* scip, /**< SCIP data structure */
3941 SCIP_GUBSET* gubset, /**< GUB set data structure */
3942 SCIP_VAR** vars, /**< variables in knapsack constraint */
3943 int ngubconscapexceed, /**< number of GUBs with only capacity exceeding variables */
3944 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3945 SCIP_Longint capacity, /**< capacity of knapsack */
3946 SCIP_Real* solvals, /**< solution values of all knapsack variables */
3947 int* gubconsGC1, /**< GUBs in GC1(GNC1+GOC1) */
3948 int* gubconsGC2, /**< GUBs in GC2 */
3949 int* gubconsGFC1, /**< GUBs in GFC1(GNC1+GF) */
3950 int* gubconsGR, /**< GUBs in GR */
3951 int ngubconsGC1, /**< number of GUBs in GC1(GNC1+GOC1) */
3952 int ngubconsGC2, /**< number of GUBs in GC2 */
3953 int ngubconsGFC1, /**< number of GUBs in GFC1(GNC1+GF) */
3954 int ngubconsGR, /**< number of GUBs in GR */
3955 int alpha0, /**< rights hand side of given valid inequality */
3956 int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3957 SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3958 int* liftrhs, /**< pointer to store right hand side of the lifted valid inequality */
3959 int maxgubvarssize /**< maximal size of GUB constraints */
3960 )
3961{
3962 SCIP_Longint* minweights;
3963 SCIP_Longint* finished;
3964 SCIP_Longint* unfinished;
3965 int* gubconsGOC1;
3966 int* gubconsGNC1;
3967 int* liftgubvars;
3968 SCIP_Longint fixedonesweight;
3969 SCIP_Longint weight;
3970 SCIP_Longint weightdiff1;
3971 SCIP_Longint weightdiff2;
3972 SCIP_Longint min;
3973 int minweightssize;
3974 int minweightslen;
3975 int nvars;
3976 int varidx;
3977 int liftgubconsidx;
3978 int liftvar;
3979 int sumliftcoef;
3980 int liftcoef;
3981 int ngubconsGOC1;
3982 int ngubconsGNC1;
3983 int left;
3984 int right;
3985 int middle;
3986 int nliftgubvars;
3987 int tmplen;
3988 int tmpsize;
3989 int j;
3990 int k;
3991 int w;
3992 int z;
3993#ifndef NDEBUG
3994 int ngubconss;
3995 int nliftgubC1;
3996
3997 assert(gubset != NULL);
3998 ngubconss = gubset->ngubconss;
3999#else
4000 assert(gubset != NULL);
4001#endif
4002
4003 nvars = gubset->nvars;
4004
4005 assert(scip != NULL);
4006 assert(vars != NULL);
4007 assert(nvars >= 0);
4008 assert(weights != NULL);
4009 assert(capacity >= 0);
4010 assert(solvals != NULL);
4014 assert(gubconsGR != NULL);
4019 assert(alpha0 >= 0);
4020 assert(liftcoefs != NULL);
4021 assert(cutact != NULL);
4022 assert(liftrhs != NULL);
4023
4025
4026 /* allocates temporary memory */
4033
4034 /* initializes data structures */
4036 *cutact = 0.0;
4037
4038 /* gets GOC1 and GNC1 GUBs, sets lifting coefficient of variables in C1 and calculates activity of the current
4039 * valid inequality
4040 */
4041 ngubconsGOC1 = 0;
4042 ngubconsGNC1 = 0;
4043 for( j = 0; j < ngubconsGC1; j++ )
4044 {
4045 if( gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GOC1 )
4046 {
4048 ngubconsGOC1++;
4049 }
4050 else
4051 {
4054 ngubconsGNC1++;
4055 }
4056 for( k = 0; k < gubset->gubconss[gubconsGC1[j]]->ngubvars
4057 && gubset->gubconss[gubconsGC1[j]]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4058 {
4059 varidx = gubset->gubconss[gubconsGC1[j]]->gubvars[k];
4060 assert(varidx >= 0 && varidx < nvars);
4061 assert(liftcoefs[varidx] == 0);
4062
4063 liftcoefs[varidx] = 1;
4064 (*cutact) += solvals[varidx];
4065 }
4066 assert(k >= 1);
4067 }
4070
4071 /* initialize the minweight tables, defined as: for i = 1,...,m with m = |I| and w = 0,...,|gubconsGC1|;
4072 * - finished_i[w] =
4073 * min sum_{k = 1,2,...,i-1} sum_{j in Q_k} a_j x_j
4074 * s.t. sum_{k = 1,2,...,i-1} sum_{j in Q_k} alpha_j x_j >= w
4075 * sum_{j in Q_k} x_j <= 1
4076 * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4077 * - unfinished_i[w] =
4078 * min sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} a_j x_j
4079 * s.t. sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} x_j >= w
4080 * sum_{j in Q_k} x_j <= 1
4081 * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4082 * - minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
4083 */
4084
4085 /* initialize finished table; note that variables in GOC1 GUBs (includes C1 and capacity exceeding variables)
4086 * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4087 * GUBs in the group GCI are sorted by non-decreasing min{ a_k : k in GC1_j } where min{ a_k : k in GC1_j } always
4088 * comes from the first variable in the GUB
4089 */
4091 finished[0] = 0;
4092 for( w = 1; w <= ngubconsGOC1; w++ )
4093 {
4095
4097 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4098
4099 varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4100
4101 assert(varidx >= 0 && varidx < nvars);
4102 assert(liftcoefs[varidx] == 1);
4103
4104 min = weights[varidx];
4105 finished[w] = finished[w-1] + min;
4106
4107#ifndef NDEBUG
4108 for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4109 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4110 {
4111 varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4112 assert(varidx >= 0 && varidx < nvars);
4113 assert(liftcoefs[varidx] == 1);
4114 assert(weights[varidx] >= min);
4115 }
4116#endif
4117 }
4118 for( w = ngubconsGOC1+1; w <= ngubconsGC1; w++ )
4120
4121 /* initialize unfinished table; note that variables in GNC1 GUBs
4122 * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4123 * GUBs in the group GCI are sorted by non-decreasing min{ a_k : k in GC1_j } where min{ a_k : k in GC1_j } always
4124 * comes from the first variable in the GUB
4125 */
4127 unfinished[0] = 0;
4128 for( w = 1; w <= ngubconsGNC1; w++ )
4129 {
4131
4133 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4134
4135 varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4136
4137 assert(varidx >= 0 && varidx < nvars);
4138 assert(liftcoefs[varidx] == 1);
4139
4140 min = weights[varidx];
4141 unfinished[w] = unfinished[w-1] + min;
4142
4143#ifndef NDEBUG
4144 for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4145 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4146 {
4147 varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4148 assert(varidx >= 0 && varidx < nvars);
4149 assert(liftcoefs[varidx] == 1);
4150 assert(weights[varidx] >= min );
4151 }
4152#endif
4153 }
4154 for( w = ngubconsGNC1 + 1; w <= ngubconsGC1; w++ )
4156
4157 /* initialize minweights table; note that variables in GC1 GUBs
4158 * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4159 * we can directly initialize minweights instead of computing it from finished and unfinished (which would be more time
4160 * consuming) because is it has to be build using weights from C1 only.
4161 */
4163 minweights[0] = 0;
4164 for( w = 1; w <= ngubconsGC1; w++ )
4165 {
4167
4170 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4171
4172 varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4173
4174 assert(varidx >= 0 && varidx < nvars);
4175 assert(liftcoefs[varidx] == 1);
4176
4177 min = weights[varidx];
4178 minweights[w] = minweights[w-1] + min;
4179
4180#ifndef NDEBUG
4181 for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4182 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4183 {
4184 varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4185 assert(varidx >= 0 && varidx < nvars);
4186 assert(liftcoefs[varidx] == 1);
4187 assert(weights[varidx] >= min);
4188 }
4189#endif
4190 }
4192
4193 /* gets sum of weights of variables fixed to one, i.e. sum of weights of C2 variables GC2 GUBs */
4194 fixedonesweight = 0;
4195 for( j = 0; j < ngubconsGC2; j++ )
4196 {
4197 varidx = gubset->gubconss[gubconsGC2[j]]->gubvars[0];
4198
4199 assert(gubset->gubconss[gubconsGC2[j]]->ngubvars == 1);
4200 assert(varidx >= 0 && varidx < nvars);
4201 assert(gubset->gubconss[gubconsGC2[j]]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4202
4203 fixedonesweight += weights[varidx];
4204 }
4205 assert(fixedonesweight >= 0);
4206
4207 /* initializes right hand side of lifted valid inequality */
4208 *liftrhs = alpha0;
4209
4210 /* sequentially up-lifts all variables in GFC1 GUBs */
4211 for( j = 0; j < ngubconsGFC1; j++ )
4212 {
4215
4216 /* GNC1 GUB: update unfinished table (remove current GUB, i.e., remove min weight of C1 vars in GUB) and
4217 * compute minweight table via updated unfinished table and aleady upto date finished table;
4218 */
4219 k = 0;
4221 {
4223 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4224 assert(ngubconsGNC1 > 0);
4225
4226 /* get number of C1 variables of current GNC1 GUB and put them into array of variables in GUB that
4227 * are considered for the lifting, i.e., not capacity exceeding
4228 */
4229 for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars
4230 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4231 liftgubvars[k] = gubset->gubconss[liftgubconsidx]->gubvars[k];
4232 assert(k >= 1);
4233
4234 /* update unfinished table by removing current GNC1 GUB, i.e, remove C1 variable with minimal weight
4235 * unfinished[w] = MAX{unfinished[w], unfinished[w+1] - weight}, "weight" is the minimal weight of current GUB
4236 */
4237 weight = weights[liftgubvars[0]];
4238
4241 for( w = ngubconsGNC1-1; w >= 1; w-- )
4242 {
4244 weightdiff2 = unfinished[w] - weight;
4245
4246 if( unfinished[w] < weightdiff1 )
4248 else
4249 break;
4250 }
4251 ngubconsGNC1--;
4252
4253 /* computes minweights table by combining unfished and fished tables */
4255 assert(minweights[0] == 0);
4256 }
4257 /* GF GUB: no update of unfinished table (and minweight table) required because GF GUBs have no C1 variables and
4258 * are therefore not in the unfinished table
4259 */
4260 else
4262
4263#ifndef NDEBUG
4264 nliftgubC1 = k;
4265#endif
4266 nliftgubvars = k;
4267 sumliftcoef = 0;
4268
4269 /* compute lifting coefficient of F and R variables in GNC1 and GF GUBs (C1 vars have already liftcoef 1) */
4270 for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4271 {
4272 if( gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_F
4273 || gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4274 {
4275 liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4276 weight = weights[liftvar];
4277 assert(weight > 0);
4278 assert(liftvar >= 0 && liftvar < nvars);
4279 assert(capacity - weight >= 0);
4280
4281 /* put variable into array of variables in GUB that are considered for the lifting,
4282 * i.e., not capacity exceeding
4283 */
4285 nliftgubvars++;
4286
4287 /* knapsack problem is infeasible:
4288 * sets z = 0
4289 */
4290 if( capacity - fixedonesweight - weight < 0 )
4291 {
4292 z = 0;
4293 }
4294 /* knapsack problem is feasible:
4295 * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
4296 * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
4297 */
4298 else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
4299 {
4300 z = *liftrhs;
4301 }
4302 /* knapsack problem is feasible:
4303 * binary search to find z = max {w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i}}
4304 */
4305 else
4306 {
4307 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
4308 left = 0;
4309 right = (*liftrhs) + 1;
4310 while( left < right - 1 )
4311 {
4312 middle = (left + right) / 2;
4313 assert(0 <= middle && middle < minweightslen);
4314 if( minweights[middle] <= capacity - fixedonesweight - weight )
4315 left = middle;
4316 else
4317 right = middle;
4318 }
4319 assert(left == right - 1);
4320 assert(0 <= left && left < minweightslen);
4321 assert(minweights[left] <= capacity - fixedonesweight - weight);
4322 assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
4323
4324 /* now z = left */
4325 z = left;
4326 assert(z <= *liftrhs);
4327 }
4328
4329 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4330 liftcoef = (*liftrhs) - z;
4332 assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4333
4334 /* updates activity of current valid inequality */
4335 (*cutact) += liftcoef * solvals[liftvar];
4336
4337 /* updates sum of all lifting coefficients in GUB */
4339 }
4340 else
4341 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4342 }
4343 /* at least one variable is in F or R (j = number of C1 variables in current GUB) */
4345
4346 /* activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0
4347 * and finished and minweight table can be updated easily as only C1 variables need to be considered;
4348 * not needed for GF GUBs
4349 */
4350 if( sumliftcoef == 0 )
4351 {
4353 {
4354 weight = weights[liftgubvars[0]];
4355 /* update finished table and minweights table by applying special case of
4356 * finished[w] = MIN{finished[w], finished[w-1] + weight}, "weight" is the minimal weight of current GUB
4357 * minweights[w] = MIN{minweights[w], minweights[w-1] + weight}, "weight" is the minimal weight of current GUB
4358 */
4359 for( w = minweightslen-1; w >= 1; w-- )
4360 {
4361 SCIP_Longint tmpval;
4362
4363 tmpval = safeAddMinweightsGUB(finished[w-1], weight);
4364 finished[w] = MIN(finished[w], tmpval);
4365
4368 }
4369 }
4370 else
4372
4373 continue;
4374 }
4375
4376 /* enlarges current minweights tables(finished, unfinished, minweights):
4377 * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4378 * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4379 * and sets minweights_i[w] = infinity for
4380 * w = |gubconsGC1| + sum_{k=1,2,..,i-1}sum_{j in Q_k} alpha_j+1,..,|C1| + sum_{k=1,2,..,i}sum_{j in Q_k} alpha_j
4381 */
4382 tmplen = minweightslen; /* will be updated in enlargeMinweights() */
4389
4390 /* update finished table and minweight table;
4391 * note that instead of computing minweight table from updated finished and updated unfinished table again
4392 * (for the lifting coefficient, we had to update unfinished table and compute minweight table), we here
4393 * only need to update the minweight table and the updated finished in the same way (i.e., computing for minweight
4394 * not needed because only finished table changed at this point and the change was "adding" one weight)
4395 *
4396 * update formular for minweight table is: minweight_i+1[w] =
4397 * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4398 * formular for finished table has the same pattern.
4399 */
4400 for( w = minweightslen-1; w >= 0; w-- )
4401 {
4402 SCIP_Longint minminweight;
4403 SCIP_Longint minfinished;
4404
4405 for( k = 0; k < nliftgubvars; k++ )
4406 {
4408 weight = weights[liftgubvars[k]];
4409
4410 if( w < liftcoef )
4411 {
4412 minfinished = MIN(finished[w], weight);
4413 minminweight = MIN(minweights[w], weight);
4414
4417 }
4418 else
4419 {
4420 SCIP_Longint tmpval;
4421
4422 assert(w >= liftcoef);
4423
4426
4429
4432 }
4433 }
4434 }
4435 assert(minweights[0] == 0);
4436 }
4437 assert(ngubconsGNC1 == 0);
4438
4439 /* note: now the unfinished table no longer exists, i.e., it is "0, MAX, MAX, ..." and minweight equals to finished;
4440 * therefore, only work with minweight table from here on
4441 */
4442
4443 /* sequentially down-lifts C2 variables contained in trivial GC2 GUBs */
4444 for( j = 0; j < ngubconsGC2; j++ )
4445 {
4447
4450 assert(gubset->gubconss[liftgubconsidx]->ngubvars == 1);
4451 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4452
4453 liftvar = gubset->gubconss[liftgubconsidx]->gubvars[0]; /* C2 GUBs contain only one variable */
4454 weight = weights[liftvar];
4455
4456 assert(liftvar >= 0 && liftvar < nvars);
4457 assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
4458 assert(weight > 0);
4459
4460 /* uses binary search to find
4461 * z = max { w : 0 <= w <= |C_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
4462 */
4463 left = 0;
4464 right = minweightslen;
4465 while( left < right - 1 )
4466 {
4467 middle = (left + right) / 2;
4468 assert(0 <= middle && middle < minweightslen);
4469 if( minweights[middle] <= capacity - fixedonesweight + weight )
4470 left = middle;
4471 else
4472 right = middle;
4473 }
4474 assert(left == right - 1);
4475 assert(0 <= left && left < minweightslen);
4476 assert(minweights[left] <= capacity - fixedonesweight + weight);
4477 assert(left == minweightslen - 1 || minweights[left + 1] > capacity - fixedonesweight + weight);
4478
4479 /* now z = left */
4480 z = left;
4481 assert(z >= *liftrhs);
4482
4483 /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
4484 liftcoef = z - (*liftrhs);
4486 assert(liftcoef >= 0);
4487
4488 /* updates sum of weights of variables fixed to one */
4489 fixedonesweight -= weight;
4490
4491 /* updates right-hand side of current valid inequality */
4492 (*liftrhs) += liftcoef;
4493 assert(*liftrhs >= alpha0);
4494
4495 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
4496 if( liftcoef == 0 )
4497 continue;
4498
4499 /* updates activity of current valid inequality */
4500 (*cutact) += liftcoef * solvals[liftvar];
4501
4502 /* enlarges current minweight table:
4503 * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4504 * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4505 * and sets minweights_i[w] = infinity for
4506 * w = |C1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 , ... , |C1| + sum_{k=1,2,...,i}sum_{j in Q_k} alpha_j
4507 */
4509
4510 /* updates minweight table: minweight_i+1[w] =
4511 * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
4512 * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
4513 */
4514 for( w = minweightslen - 1; w >= 0; w-- )
4515 {
4516 if( w < liftcoef )
4517 {
4518 min = MIN(minweights[w], weight);
4519 minweights[w] = min;
4520 }
4521 else
4522 {
4523 SCIP_Longint tmpval;
4524
4525 assert(w >= liftcoef);
4526
4528 min = MIN(minweights[w], tmpval);
4529 minweights[w] = min;
4530 }
4531 }
4532 }
4533 assert(fixedonesweight == 0);
4534 assert(*liftrhs >= alpha0);
4535
4536 /* sequentially up-lifts variables in GUB constraints in GR GUBs */
4537 for( j = 0; j < ngubconsGR; j++ )
4538 {
4540
4543
4544 sumliftcoef = 0;
4545 nliftgubvars = 0;
4546 for( k = 0; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4547 {
4548 if(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4549 {
4550 liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4551 weight = weights[liftvar];
4552 assert(weight > 0);
4553 assert(liftvar >= 0 && liftvar < nvars);
4554 assert(capacity - weight >= 0);
4555 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
4556
4557 /* put variable into array of variables in GUB that are considered for the lifting,
4558 * i.e., not capacity exceeding
4559 */
4561 nliftgubvars++;
4562
4563 /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
4564 * if minweights_i[liftrhs] <= a_0 - a_{j_i}
4565 */
4566 if( minweights[*liftrhs] <= capacity - weight )
4567 {
4568 z = *liftrhs;
4569 }
4570 /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
4571 */
4572 else
4573 {
4574 left = 0;
4575 right = (*liftrhs) + 1;
4576 while( left < right - 1 )
4577 {
4578 middle = (left + right) / 2;
4579 assert(0 <= middle && middle < minweightslen);
4580 if( minweights[middle] <= capacity - weight )
4581 left = middle;
4582 else
4583 right = middle;
4584 }
4585 assert(left == right - 1);
4586 assert(0 <= left && left < minweightslen);
4587 assert(minweights[left] <= capacity - weight);
4588 assert(left == minweightslen - 1 || minweights[left + 1] > capacity - weight);
4589
4590 /* now z = left */
4591 z = left;
4592 assert(z <= *liftrhs);
4593 }
4594 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4595 liftcoef = (*liftrhs) - z;
4597 assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4598
4599 /* updates activity of current valid inequality */
4600 (*cutact) += liftcoef * solvals[liftvar];
4601
4602 /* updates sum of all lifting coefficients in GUB */
4604 }
4605 else
4606 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4607 }
4608 assert(nliftgubvars >= 1); /* at least one variable is in R */
4609
4610 /* minweight table and activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0 */
4611 if( sumliftcoef == 0 )
4612 continue;
4613
4614 /* updates minweight table: minweight_i+1[w] =
4615 * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4616 */
4617 for( w = *liftrhs; w >= 0; w-- )
4618 {
4619 for( k = 0; k < nliftgubvars; k++ )
4620 {
4622 weight = weights[liftgubvars[k]];
4623
4624 if( w < liftcoef )
4625 {
4626 min = MIN(minweights[w], weight);
4627 minweights[w] = min;
4628 }
4629 else
4630 {
4631 SCIP_Longint tmpval;
4632
4633 assert(w >= liftcoef);
4634
4636 min = MIN(minweights[w], tmpval);
4637 minweights[w] = min;
4638 }
4639 }
4640 }
4641 assert(minweights[0] == 0);
4642 }
4643
4644 /* frees temporary memory */
4651
4652 return SCIP_OKAY;
4653}
4654
4655/** lifts given minimal cover inequality
4656 * \f[
4657 * \sum_{j \in C} x_j \leq |C| - 1
4658 * \f]
4659 * valid for
4660 * \f[
4661 * S^0 = \{ x \in {0,1}^{|C|} : \sum_{j \in C} a_j x_j \leq a_0 \}
4662 * \f]
4663 * to a valid inequality
4664 * \f[
4665 * \sum_{j \in C} x_j + \sum_{j \in N \setminus C} \alpha_j x_j \leq |C| - 1
4666 * \f]
4667 * for
4668 * \f[
4669 * S = \{ x \in {0,1}^{|N|} : \sum_{j \in N} a_j x_j \leq a_0 \};
4670 * \f]
4671 * uses superadditive up-lifting for the variables in \f$N \setminus C\f$.
4672 */
4673static
4675 SCIP* scip, /**< SCIP data structure */
4676 SCIP_VAR** vars, /**< variables in knapsack constraint */
4677 int nvars, /**< number of variables in knapsack constraint */
4678 int ntightened, /**< number of variables with tightened upper bound */
4679 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4680 SCIP_Longint capacity, /**< capacity of knapsack */
4681 SCIP_Real* solvals, /**< solution values of all problem variables */
4682 int* covervars, /**< cover variables */
4683 int* noncovervars, /**< noncover variables */
4684 int ncovervars, /**< number of cover variables */
4685 int nnoncovervars, /**< number of noncover variables */
4686 SCIP_Longint coverweight, /**< weight of cover */
4687 SCIP_Real* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
4688 SCIP_Real* cutact /**< pointer to store activity of lifted valid inequality */
4689 )
4690{
4691 SCIP_Longint* maxweightsums;
4692 SCIP_Longint* intervalends;
4693 SCIP_Longint* rhos;
4694 SCIP_Real* sortkeys;
4695 SCIP_Longint lambda;
4696 int j;
4697 int h;
4698
4699 assert(scip != NULL);
4700 assert(vars != NULL);
4701 assert(nvars >= 0);
4702 assert(weights != NULL);
4703 assert(capacity >= 0);
4704 assert(solvals != NULL);
4705 assert(covervars != NULL);
4707 assert(ncovervars > 0 && ncovervars <= nvars);
4708 assert(nnoncovervars >= 0 && nnoncovervars <= nvars - ntightened);
4709 assert(ncovervars + nnoncovervars == nvars - ntightened);
4710 assert(liftcoefs != NULL);
4711 assert(cutact != NULL);
4712
4713 /* allocates temporary memory */
4718
4719 /* initializes data structures */
4721 *cutact = 0.0;
4722
4723 /* sets lifting coefficient of variables in C, sorts variables in C such that a_1 >= a_2 >= ... >= a_|C|
4724 * and calculates activity of current valid inequality
4725 */
4726 for( j = 0; j < ncovervars; j++ )
4727 {
4728 assert(liftcoefs[covervars[j]] == 0.0);
4729 liftcoefs[covervars[j]] = 1.0;
4730 sortkeys[j] = (SCIP_Real) weights[covervars[j]];
4731 (*cutact) += solvals[covervars[j]];
4732 }
4734
4735 /* calculates weight excess of cover C */
4736 lambda = coverweight - capacity;
4737 assert(lambda > 0);
4738
4739 /* calculates A_h for h = 0,...,|C|, I_h for h = 1,...,|C| and rho_h for h = 1,...,|C| */
4740 maxweightsums[0] = 0;
4741 for( h = 1; h <= ncovervars; h++ )
4742 {
4743 maxweightsums[h] = maxweightsums[h-1] + weights[covervars[h-1]];
4744 intervalends[h-1] = maxweightsums[h] - lambda;
4745 rhos[h-1] = MAX(0, weights[covervars[h-1]] - weights[covervars[0]] + lambda);
4746 }
4747
4748 /* sorts variables in N\C such that a_{j_1} <= a_{j_2} <= ... <= a_{j_t} */
4749 for( j = 0; j < nnoncovervars; j++ )
4750 sortkeys[j] = (SCIP_Real) (weights[noncovervars[j]]);
4752
4753 /* calculates lifting coefficient for all variables in N\C */
4754 h = 0;
4755 for( j = 0; j < nnoncovervars; j++ )
4756 {
4757 int liftvar;
4758 SCIP_Longint weight;
4759 SCIP_Real liftcoef;
4760
4762 weight = weights[liftvar];
4763
4764 while( intervalends[h] < weight )
4765 h++;
4766
4767 if( h == 0 )
4768 liftcoef = h;
4769 else
4770 {
4771 if( weight <= intervalends[h-1] + rhos[h] )
4772 {
4773 SCIP_Real tmp1;
4774 SCIP_Real tmp2;
4775 tmp1 = (SCIP_Real) (intervalends[h-1] + rhos[h] - weight);
4776 tmp2 = (SCIP_Real) rhos[1];
4777 liftcoef = h - ( tmp1 / tmp2 );
4778 }
4779 else
4780 liftcoef = h;
4781 }
4782
4783 /* sets lifting coefficient */
4784 assert(liftcoefs[liftvar] == 0.0);
4786
4787 /* updates activity of current valid inequality */
4788 (*cutact) += liftcoef * solvals[liftvar];
4789 }
4790
4791 /* frees temporary memory */
4796
4797 return SCIP_OKAY;
4798}
4799
4800
4801/** separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information, if wanted, for
4802 * given knapsack problem
4803*/
4804static
4806 SCIP* scip, /**< SCIP data structure */
4807 SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
4808 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
4809 SCIP_VAR** vars, /**< variables in knapsack constraint */
4810 int nvars, /**< number of variables in knapsack constraint */
4811 int ntightened, /**< number of variables with tightened upper bound */
4812 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4813 SCIP_Longint capacity, /**< capacity of knapsack */
4814 SCIP_Real* solvals, /**< solution values of all problem variables */
4815 int* mincovervars, /**< mincover variables */
4816 int* nonmincovervars, /**< nonmincover variables */
4817 int nmincovervars, /**< number of mincover variables */
4818 int nnonmincovervars, /**< number of nonmincover variables */
4819 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
4820 SCIP_GUBSET* gubset, /**< GUB set data structure, NULL if no GUB information should be used */
4821 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
4822 int* ncuts /**< pointer to add up the number of found cuts */
4823 )
4824{
4825 int* varsC1;
4826 int* varsC2;
4827 int* varsF;
4828 int* varsR;
4829 int nvarsC1;
4830 int nvarsC2;
4831 int nvarsF;
4832 int nvarsR;
4833 SCIP_Real cutact;
4834 int* liftcoefs;
4835 int liftrhs;
4836
4837 assert( cutoff != NULL );
4838 *cutoff = FALSE;
4839
4840 /* allocates temporary memory */
4846
4847 /* gets partition (C_1,C_2) of C, i.e. C_1 & C_2 = C and C_1 cap C_2 = emptyset, with C_1 not empty; chooses partition
4848 * as follows
4849 * C_2 = { j in C : x*_j = 1 } and
4850 * C_1 = C\C_2
4851 */
4854 assert(nmincovervars > 0);
4855 assert(nvarsC1 >= 0); /* nvarsC1 > 0 does not always hold, because relaxed knapsack conss may already be violated */
4856
4857 /* changes partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one variable from C2 to C1 */
4859 {
4861 assert(nvarsC1 >= 1);
4862 }
4863 assert(nvarsC2 == 0 || nvarsC1 >= 1);
4864
4865 /* gets partition (F,R) of N\C, i.e. F & R = N\C and F cap R = emptyset; chooses partition as follows
4866 * R = { j in N\C : x*_j = 0 } and
4867 * F = (N\C)\F
4868 */
4871 assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4872
4873 /* lift cuts without GUB information */
4874 if( gubset == NULL )
4875 {
4876 /* sorts variables in F, C_2, R according to the second level lifting sequence that will be used in the sequential
4877 * lifting procedure
4878 */
4880
4881 /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4882 *
4883 * S^0 = { x in {0,1}^|C_1| : sum_{j in C_1} a_j x_j <= a_0 - sum_{j in C_2} a_j }
4884 *
4885 * to a valid inequality sum_{j in C_1} x_j + sum_{j in N\C_1} alpha_j x_j <= |C_1| - 1 + sum_{j in C_2} alpha_j for
4886 *
4887 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
4888 *
4889 * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in C_2 and sequential
4890 * up-lifting for the variables in R according to the second level lifting sequence
4891 */
4892 SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsC1, varsC2,
4894 }
4895 /* lift cuts with GUB information */
4896 else
4897 {
4898 int* gubconsGC1;
4899 int* gubconsGC2;
4900 int* gubconsGFC1;
4901 int* gubconsGR;
4902 int ngubconsGC1;
4903 int ngubconsGC2;
4904 int ngubconsGFC1;
4905 int ngubconsGR;
4906 int ngubconss;
4907 int nconstightened;
4908 int maxgubvarssize;
4909
4910 assert(nvars == gubset->nvars);
4911
4912 ngubconsGC1 = 0;
4913 ngubconsGC2 = 0;
4914 ngubconsGFC1 = 0;
4915 ngubconsGR = 0;
4916 ngubconss = gubset->ngubconss;
4917 nconstightened = 0;
4918 maxgubvarssize = 0;
4919
4920 /* allocates temporary memory */
4925
4926 /* categorizies GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of
4927 * the GUBs for the sequential GUB wise lifting procedure
4928 */
4932
4933 /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4934 *
4935 * S^0 = { x in {0,1}^|C_1| : sum_{j in C_1} a_j x_j <= a_0 - sum_{j in C_2} a_j,
4936 * sum_{j in Q_i} x_j <= 1, forall i in I }
4937 *
4938 * to a valid inequality sum_{j in C_1} x_j + sum_{j in N\C_1} alpha_j x_j <= |C_1| - 1 + sum_{j in C_2} alpha_j for
4939 *
4940 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0, sum_{j in Q_i} x_j <= 1, forall i in I },
4941 *
4942 * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
4943 * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
4944 * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
4945 */
4949
4950 /* frees temporary memory */
4955 }
4956
4957 /* checks, if lifting yielded a violated cut */
4958 if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
4959 {
4960 SCIP_ROW* row;
4961 char name[SCIP_MAXSTRLEN];
4962 int j;
4963
4964 /* creates LP row */
4965 assert( cons == NULL || sepa == NULL );
4966 if ( cons != NULL )
4967 {
4969 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
4970 cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
4971 cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
4972 }
4973 else if ( sepa != NULL )
4974 {
4976 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4977 }
4978 else
4979 {
4980 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcseq_%d", *ncuts);
4982 }
4983
4984 /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
4986 assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4987 for( j = 0; j < nvarsC1; j++ )
4988 {
4989 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC1[j]], 1.0) );
4990 }
4991 for( j = 0; j < nvarsC2; j++ )
4992 {
4993 if( liftcoefs[varsC2[j]] > 0 )
4994 {
4995 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC2[j]], (SCIP_Real)liftcoefs[varsC2[j]]) );
4996 }
4997 }
4998 for( j = 0; j < nvarsF; j++ )
4999 {
5000 if( liftcoefs[varsF[j]] > 0 )
5001 {
5002 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
5003 }
5004 }
5005 for( j = 0; j < nvarsR; j++ )
5006 {
5007 if( liftcoefs[varsR[j]] > 0 )
5008 {
5009 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
5010 }
5011 }
5013
5014 /* checks, if cut is violated enough */
5015 if( SCIPisCutEfficacious(scip, sol, row) )
5016 {
5017 if( cons != NULL )
5018 {
5020 }
5022 (*ncuts)++;
5023 }
5024 SCIP_CALL( SCIPreleaseRow(scip, &row) );
5025 }
5026
5027 /* frees temporary memory */
5033
5034 return SCIP_OKAY;
5035}
5036
5037/** separates lifted extended weight inequalities using sequential up- and down-lifting for given knapsack problem */
5038static
5040 SCIP* scip, /**< SCIP data structure */
5041 SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5042 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5043 SCIP_VAR** vars, /**< variables in knapsack constraint */
5044 int nvars, /**< number of variables in knapsack constraint */
5045 int ntightened, /**< number of variables with tightened upper bound */
5046 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5047 SCIP_Longint capacity, /**< capacity of knapsack */
5048 SCIP_Real* solvals, /**< solution values of all problem variables */
5049 int* feassetvars, /**< variables in feasible set */
5050 int* nonfeassetvars, /**< variables not in feasible set */
5051 int nfeassetvars, /**< number of variables in feasible set */
5052 int nnonfeassetvars, /**< number of variables not in feasible set */
5053 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5054 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5055 int* ncuts /**< pointer to add up the number of found cuts */
5056 )
5057{
5058 int* varsT1;
5059 int* varsT2;
5060 int* varsF;
5061 int* varsR;
5062 int* liftcoefs;
5063 SCIP_Real cutact;
5064 int nvarsT1;
5065 int nvarsT2;
5066 int nvarsF;
5067 int nvarsR;
5068 int liftrhs;
5069 int j;
5070
5071 assert( cutoff != NULL );
5072 *cutoff = FALSE;
5073
5074 /* allocates temporary memory */
5080
5081 /* gets partition (T_1,T_2) of T, i.e. T_1 & T_2 = T and T_1 cap T_2 = emptyset, with T_1 not empty; chooses partition
5082 * as follows
5083 * T_2 = { j in T : x*_j = 1 } and
5084 * T_1 = T\T_2
5085 */
5088
5089 /* changes partition (T_1,T_2) of feasible set T, if |T1| = 0, by moving one variable from T2 to T1 */
5090 if( nvarsT1 == 0 && nvarsT2 > 0)
5091 {
5093 assert(nvarsT1 == 1);
5094 }
5095 assert(nvarsT2 == 0 || nvarsT1 > 0);
5096
5097 /* gets partition (F,R) of N\T, i.e. F & R = N\T and F cap R = emptyset; chooses partition as follows
5098 * R = { j in N\T : x*_j = 0 } and
5099 * F = (N\T)\F
5100 */
5103 assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5104
5105 /* sorts variables in F, T_2, and R according to the second level lifting sequence that will be used in the sequential
5106 * lifting procedure (the variable removed last from the initial cover does not have to be lifted first, therefore it
5107 * is included in the sorting routine)
5108 */
5110
5111 /* lifts extended weight inequality sum_{j in T_1} x_j <= |T_1| valid for
5112 *
5113 * S^0 = { x in {0,1}^|T_1| : sum_{j in T_1} a_j x_j <= a_0 - sum_{j in T_2} a_j }
5114 *
5115 * to a valid inequality sum_{j in T_1} x_j + sum_{j in N\T_1} alpha_j x_j <= |T_1| + sum_{j in T_2} alpha_j for
5116 *
5117 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5118 *
5119 * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in T_2 and sequential
5120 * up-lifting for the variabels in R according to the second level lifting sequence
5121 */
5122 SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsT1, varsT2, varsF, varsR,
5124
5125 /* checks, if lifting yielded a violated cut */
5126 if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5127 {
5128 SCIP_ROW* row;
5129 char name[SCIP_MAXSTRLEN];
5130
5131 /* creates LP row */
5132 assert( cons == NULL || sepa == NULL );
5133 if( cons != NULL )
5134 {
5137 cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5138 cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5139 }
5140 else if ( sepa != NULL )
5141 {
5143 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5144 }
5145 else
5146 {
5147 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_ewseq_%d", *ncuts);
5149 }
5150
5151 /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5153 assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5154 for( j = 0; j < nvarsT1; j++ )
5155 {
5156 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT1[j]], 1.0) );
5157 }
5158 for( j = 0; j < nvarsT2; j++ )
5159 {
5160 if( liftcoefs[varsT2[j]] > 0 )
5161 {
5162 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT2[j]], (SCIP_Real)liftcoefs[varsT2[j]]) );
5163 }
5164 }
5165 for( j = 0; j < nvarsF; j++ )
5166 {
5167 if( liftcoefs[varsF[j]] > 0 )
5168 {
5169 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
5170 }
5171 }
5172 for( j = 0; j < nvarsR; j++ )
5173 {
5174 if( liftcoefs[varsR[j]] > 0 )
5175 {
5176 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
5177 }
5178 }
5180
5181 /* checks, if cut is violated enough */
5182 if( SCIPisCutEfficacious(scip, sol, row) )
5183 {
5184 if( cons != NULL )
5185 {
5187 }
5189 (*ncuts)++;
5190 }
5191 SCIP_CALL( SCIPreleaseRow(scip, &row) );
5192 }
5193
5194 /* frees temporary memory */
5200
5201 return SCIP_OKAY;
5202}
5203
5204/** separates lifted minimal cover inequalities using superadditive up-lifting for given knapsack problem */
5205static
5207 SCIP* scip, /**< SCIP data structure */
5208 SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5209 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5210 SCIP_VAR** vars, /**< variables in knapsack constraint */
5211 int nvars, /**< number of variables in knapsack constraint */
5212 int ntightened, /**< number of variables with tightened upper bound */
5213 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5214 SCIP_Longint capacity, /**< capacity of knapsack */
5215 SCIP_Real* solvals, /**< solution values of all problem variables */
5216 int* mincovervars, /**< mincover variables */
5217 int* nonmincovervars, /**< nonmincover variables */
5218 int nmincovervars, /**< number of mincover variables */
5219 int nnonmincovervars, /**< number of nonmincover variables */
5220 SCIP_Longint mincoverweight, /**< weight of minimal cover */
5221 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5222 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5223 int* ncuts /**< pointer to add up the number of found cuts */
5224 )
5225{
5226 SCIP_Real* realliftcoefs;
5227 SCIP_Real cutact;
5228 int liftrhs;
5229
5230 assert( cutoff != NULL );
5231 *cutoff = FALSE;
5232 cutact = 0.0;
5233
5234 /* allocates temporary memory */
5236
5237 /* lifts minimal cover inequality sum_{j in C} x_j <= |C| - 1 valid for
5238 *
5239 * S^0 = { x in {0,1}^|C| : sum_{j in C} a_j x_j <= a_0 }
5240 *
5241 * to a valid inequality sum_{j in C} x_j + sum_{j in N\C} alpha_j x_j <= |C| - 1 for
5242 *
5243 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5244 *
5245 * uses superadditive up-lifting for the variables in N\C.
5246 */
5247 SCIP_CALL( superadditiveUpLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, mincovervars,
5249 liftrhs = nmincovervars - 1;
5250
5251 /* checks, if lifting yielded a violated cut */
5252 if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5253 {
5254 SCIP_ROW* row;
5255 char name[SCIP_MAXSTRLEN];
5256 int j;
5257
5258 /* creates LP row */
5259 assert( cons == NULL || sepa == NULL );
5260 if ( cons != NULL )
5261 {
5264 cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5265 cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5266 }
5267 else if ( sepa != NULL )
5268 {
5270 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5271 }
5272 else
5273 {
5274 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcsup_%d", *ncuts);
5276 }
5277
5278 /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5280 assert(nmincovervars + nnonmincovervars == nvars - ntightened);
5281 for( j = 0; j < nmincovervars; j++ )
5282 {
5284 }
5285 for( j = 0; j < nnonmincovervars; j++ )
5286 {
5289 {
5291 }
5292 }
5294
5295 /* checks, if cut is violated enough */
5296 if( SCIPisCutEfficacious(scip, sol, row) )
5297 {
5298 if( cons != NULL )
5299 {
5301 }
5303 (*ncuts)++;
5304 }
5305 SCIP_CALL( SCIPreleaseRow(scip, &row) );
5306 }
5307
5308 /* frees temporary memory */
5310
5311 return SCIP_OKAY;
5312}
5313
5314/** converts given cover C to a minimal cover by removing variables in the reverse order in which the variables were chosen
5315 * to be in C, i.e. in the order of non-increasing (1 - x*_j)/a_j, if the transformed separation problem was used to find
5316 * C and in the order of non-increasing (1 - x*_j), if the modified transformed separation problem was used to find C;
5317 * note that all variables with x*_j = 1 will be removed last
5318 */
5319static
5321 SCIP* scip, /**< SCIP data structure */
5322 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5323 SCIP_Longint capacity, /**< capacity of knapsack */
5324 SCIP_Real* solvals, /**< solution values of all problem variables */
5325 int* covervars, /**< pointer to store cover variables */
5326 int* noncovervars, /**< pointer to store noncover variables */
5327 int* ncovervars, /**< pointer to store number of cover variables */
5328 int* nnoncovervars, /**< pointer to store number of noncover variables */
5329 SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5330 SCIP_Bool modtransused /**< TRUE if mod trans sepa prob was used to find cover */
5331 )
5332{
5335 SCIP_Longint minweight;
5336 int nsortkeypairs;
5337 int minweightidx;
5338 int j;
5339 int k;
5340
5341 assert(scip != NULL);
5342 assert(covervars != NULL);
5345 assert(*ncovervars > 0);
5347 assert(*nnoncovervars >= 0);
5349 assert(*coverweight > 0);
5350 assert(*coverweight > capacity);
5351
5352 /* allocates temporary memory; we need two arrays for the keypairs in order to be able to free them in the correct
5353 * order */
5357
5358 /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5359 * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5360 * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5361 * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5362 */
5364 if( modtransused )
5365 {
5366 for( j = 0; j < *ncovervars; j++ )
5367 {
5368 SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5370
5371 sortkeypairs[j]->key1 = solvals[covervars[j]];
5372 sortkeypairs[j]->key2 = (SCIP_Real) weights[covervars[j]];
5373 }
5374 }
5375 else
5376 {
5377 for( j = 0; j < *ncovervars; j++ )
5378 {
5379 SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5381
5382 sortkeypairs[j]->key1 = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5383 sortkeypairs[j]->key2 = (SCIP_Real) (-weights[covervars[j]]);
5384 }
5385 }
5387
5388 /* gets j' with a_j' = min{ a_j : j in C } */
5389 minweightidx = 0;
5390 minweight = weights[covervars[minweightidx]];
5391 for( j = 1; j < *ncovervars; j++ )
5392 {
5393 if( weights[covervars[j]] <= minweight )
5394 {
5395 minweightidx = j;
5396 minweight = weights[covervars[minweightidx]];
5397 }
5398 }
5400 assert(minweight > 0 && minweight <= *coverweight);
5401
5402 j = 0;
5403 /* removes variables from C until the remaining variables form a minimal cover */
5404 while( j < *ncovervars && ((*coverweight) - minweight > capacity) )
5405 {
5406 assert(minweightidx >= j);
5408
5409 /* if sum_{i in C} a_i - a_j <= a_0, j cannot be removed from C */
5410 if( (*coverweight) - weights[covervars[j]] <= capacity )
5411 {
5412 ++j;
5413 continue;
5414 }
5415
5416 /* adds j to N\C */
5418 (*nnoncovervars)++;
5419
5420 /* removes j from C */
5421 (*coverweight) -= weights[covervars[j]];
5422 for( k = j; k < (*ncovervars) - 1; k++ )
5423 covervars[k] = covervars[k+1];
5424 (*ncovervars)--;
5425
5426 /* updates j' with a_j' = min{ a_j : j in C } */
5427 if( j == minweightidx )
5428 {
5429 minweightidx = 0;
5430 minweight = weights[covervars[minweightidx]];
5431 for( k = 1; k < *ncovervars; k++ )
5432 {
5433 if( weights[covervars[k]] <= minweight )
5434 {
5435 minweightidx = k;
5436 minweight = weights[covervars[minweightidx]];
5437 }
5438 }
5439 assert(minweight > 0 && minweight <= *coverweight);
5441 }
5442 else
5443 {
5445 minweightidx--;
5446 }
5447 /* j needs to stay the same */
5448 }
5449 assert((*coverweight) > capacity);
5450 assert((*coverweight) - minweight <= capacity);
5451
5452 /* frees temporary memory */
5453 for( j = nsortkeypairs-1; j >= 0; j-- )
5454 SCIPfreeBuffer(scip, &(sortkeypairs[j])); /*lint !e866 */
5457
5458 return SCIP_OKAY;
5459}
5460
5461/** converts given initial cover C_init to a feasible set by removing variables in the reverse order in which
5462 * they were chosen to be in C_init:
5463 * non-increasing (1 - x*_j)/a_j, if transformed separation problem was used to find C_init
5464 * non-increasing (1 - x*_j), if modified transformed separation problem was used to find C_init.
5465 * separates lifted extended weight inequalities using sequential up- and down-lifting for this feasible set
5466 * and all subsequent feasible sets.
5467 */
5468static
5470 SCIP* scip, /**< SCIP data structure */
5471 SCIP_CONS* cons, /**< constraint that originates the knapsack problem */
5472 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5473 SCIP_VAR** vars, /**< variables in knapsack constraint */
5474 int nvars, /**< number of variables in knapsack constraint */
5475 int ntightened, /**< number of variables with tightened upper bound */
5476 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5477 SCIP_Longint capacity, /**< capacity of knapsack */
5478 SCIP_Real* solvals, /**< solution values of all problem variables */
5479 int* covervars, /**< pointer to store cover variables */
5480 int* noncovervars, /**< pointer to store noncover variables */
5481 int* ncovervars, /**< pointer to store number of cover variables */
5482 int* nnoncovervars, /**< pointer to store number of noncover variables */
5483 SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5484 SCIP_Bool modtransused, /**< TRUE if mod trans sepa prob was used to find cover */
5485 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5486 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5487 int* ncuts /**< pointer to add up the number of found cuts */
5488 )
5489{
5490 SCIP_Real* sortkeys;
5491 int j;
5492 int k;
5493
5494 assert(scip != NULL);
5495 assert(covervars != NULL);
5498 assert(*ncovervars > 0);
5500 assert(*nnoncovervars >= 0);
5502 assert(*coverweight > 0);
5503 assert(*coverweight > capacity);
5504 assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5505 assert(cutoff != NULL);
5506
5507 *cutoff = FALSE;
5508
5509 /* allocates temporary memory */
5511
5512 /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5513 * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5514 * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5515 * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5516 */
5517 if( modtransused )
5518 {
5519 for( j = 0; j < *ncovervars; j++ )
5520 {
5521 sortkeys[j] = solvals[covervars[j]];
5523 }
5524 }
5525 else
5526 {
5527 for( j = 0; j < *ncovervars; j++ )
5528 {
5529 sortkeys[j] = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5531 }
5532 }
5534
5535 /* removes variables from C_init and separates lifted extended weight inequalities using sequential up- and down-lifting;
5536 * in addition to an extended weight inequality this gives cardinality inequalities */
5537 while( *ncovervars >= 2 )
5538 {
5539 /* adds first element of C_init to N\C_init */
5541 (*nnoncovervars)++;
5542
5543 /* removes first element from C_init */
5544 (*coverweight) -= weights[covervars[0]];
5545 for( k = 0; k < (*ncovervars) - 1; k++ )
5546 covervars[k] = covervars[k+1];
5547 (*ncovervars)--;
5548
5549 assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5550 if( (*coverweight) <= capacity )
5551 {
5552 SCIP_CALL( separateSequLiftedExtendedWeightInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals,
5554 }
5555
5556 /* stop if cover is too large */
5558 break;
5559 }
5560
5561 /* frees temporary memory */
5563
5564 return SCIP_OKAY;
5565}
5566
5567/** separates different classes of valid inequalities for the 0-1 knapsack problem */
5569 SCIP* scip, /**< SCIP data structure */
5570 SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5571 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5572 SCIP_VAR** vars, /**< variables in knapsack constraint */
5573 int nvars, /**< number of variables in knapsack constraint */
5574 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5575 SCIP_Longint capacity, /**< capacity of knapsack */
5576 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5577 SCIP_Bool usegubs, /**< should GUB information be used for separation? */
5578 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
5579 int* ncuts /**< pointer to add up the number of found cuts */
5580 )
5581{
5582 SCIP_Real* solvals;
5583 int* covervars;
5584 int* noncovervars;
5585 SCIP_Bool coverfound;
5586 SCIP_Bool fractional;
5587 SCIP_Bool modtransused;
5588 SCIP_Longint coverweight;
5589 int ncovervars;
5590 int nnoncovervars;
5591 int ntightened;
5592
5593 assert(scip != NULL);
5594 assert(capacity >= 0);
5595 assert(cutoff != NULL);
5596 assert(ncuts != NULL);
5597
5598 *cutoff = FALSE;
5599
5600 if( nvars == 0 )
5601 return SCIP_OKAY;
5602
5603 assert(vars != NULL);
5604 assert(nvars > 0);
5605 assert(weights != NULL);
5606
5607 /* increase age of constraint (age is reset to zero, if a cut was found) */
5608 if( cons != NULL )
5609 {
5610 SCIP_CALL( SCIPincConsAge(scip, cons) );
5611 }
5612
5613 /* allocates temporary memory */
5617
5618 /* gets solution values of all problem variables */
5619 SCIP_CALL( SCIPgetSolVals(scip, sol, nvars, vars, solvals) );
5620
5621#ifdef SCIP_DEBUG
5622 {
5623 int i;
5624
5625 SCIPdebugMsg(scip, "separate cuts for knapsack constraint originated by cons <%s>:\n",
5626 cons == NULL ? "-" : SCIPconsGetName(cons));
5627 for( i = 0; i < nvars; ++i )
5628 {
5629 SCIPdebugMsgPrint(scip, "%+" SCIP_LONGINT_FORMAT "<%s>(%g)", weights[i], SCIPvarGetName(vars[i]), solvals[i]);
5630 }
5631 SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT "\n", capacity);
5632 }
5633#endif
5634
5635 /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting) using GUB information
5636 */
5637 if( usegubs )
5638 {
5640
5641 SCIPdebugMsg(scip, "separate LMCI1-GUB cuts:\n");
5642
5643 /* initializes partion of knapsack variables into nonoverlapping GUB constraints */
5644 SCIP_CALL( GUBsetCreate(scip, &gubset, nvars, weights, capacity) );
5645
5646 /* constructs sophisticated partition of knapsack variables into nonoverlapping GUBs */
5648 assert(gubset->ngubconss <= nvars);
5649
5650 /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5651 * MODIFIED transformed separation problem and taking into account the following fixing:
5652 * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5653 * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5654 * if one exists
5655 */
5657 SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5659
5660 assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5661
5662 /* if x* is not fractional we stop the separation routine */
5663 if( !fractional )
5664 {
5665 SCIPdebugMsg(scip, " LMCI1-GUB terminated by no variable with fractional LP value.\n");
5666
5667 /* frees memory for GUB set data structure */
5669
5670 goto TERMINATE;
5671 }
5672
5673 /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5674 if( coverfound )
5675 {
5676 /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5677 * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5678 */
5679 SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5681
5682 /* only separate with GUB information if we have at least one nontrivial GUB (with more than one variable) */
5683 if( gubset->ngubconss < nvars )
5684 {
5685 /* separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information */
5686 SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5688 }
5689 else
5690 {
5691 /* separates lifted minimal cover inequalities using sequential up- and down-lifting, but do not use trivial
5692 * GUB information
5693 */
5694 SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5695 solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5696 }
5697 }
5698
5699 /* frees memory for GUB set data structure */
5701 }
5702 else
5703 {
5704 /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting)
5705 * (and LMCI2 (lifted minimal cover inequalities using superadditive up-lifting))
5706 */
5707
5708 /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5709 * MODIFIED transformed separation problem and taking into account the following fixing:
5710 * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5711 * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5712 * if one exists
5713 */
5714 SCIPdebugMsg(scip, "separate LMCI1 cuts:\n");
5716 SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5718 assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5719
5720 /* if x* is not fractional we stop the separation routine */
5721 if( !fractional )
5722 goto TERMINATE;
5723
5724 /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5725 if( coverfound )
5726 {
5727 /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5728 * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5729 */
5730 SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5732
5733 /* separates lifted minimal cover inequalities using sequential up- and down-lifting */
5734 SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5735 solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5736
5737 if( USESUPADDLIFT ) /*lint !e506 !e774*/
5738 {
5739 SCIPdebugMsg(scip, "separate LMCI2 cuts:\n");
5740 /* separates lifted minimal cover inequalities using superadditive up-lifting */
5741 SCIP_CALL( separateSupLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5743 }
5744 }
5745 }
5746
5747 /* LEWI (lifted extended weight inequalities using sequential up- and down-lifting) */
5748 if ( ! (*cutoff) )
5749 {
5750 /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5751 * transformed separation problem and taking into account the following fixing:
5752 * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5753 * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5754 * if one exists
5755 */
5756 SCIPdebugMsg(scip, "separate LEWI cuts:\n");
5758 SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5761 assert(!coverfound || ncovervars + nnoncovervars == nvars - ntightened);
5762
5763 /* if no cover was found we stop the separation routine */
5764 if( coverfound )
5765 {
5766 /* converts initial cover C_init to a feasible set by removing variables in the reverse order in which
5767 * they were chosen to be in C_init and separates lifted extended weight inequalities using sequential
5768 * up- and down-lifting for this feasible set and all subsequent feasible sets.
5769 */
5770 SCIP_CALL( getFeasibleSet(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals, covervars, noncovervars,
5772 }
5773 }
5774
5775 TERMINATE:
5776 /* frees temporary memory */
5779 SCIPfreeBufferArray(scip, &solvals);
5780
5781 return SCIP_OKAY;
5782}
5783
5784/* relaxes given general linear constraint into a knapsack constraint and separates lifted knapsack cover inequalities */
5786 SCIP* scip, /**< SCIP data structure */
5787 SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5788 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5789 int nknapvars, /**< number of variables in the continuous knapsack constraint */
5790 SCIP_VAR** knapvars, /**< variables in the continuous knapsack constraint */
5791 SCIP_Real* knapvals, /**< coefficients of the variables in the continuous knapsack constraint */
5792 SCIP_Real valscale, /**< -1.0 if lhs of row is used as rhs of c. k. constraint, +1.0 otherwise */
5793 SCIP_Real rhs, /**< right hand side of the continuous knapsack constraint */
5794 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
5795 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff was found */
5796 int* ncuts /**< pointer to add up the number of found cuts */
5797 )
5798{
5799 SCIP_VAR** binvars;
5800 SCIP_VAR** consvars;
5801 SCIP_Real* binvals;
5802 SCIP_Longint* consvals;
5803 SCIP_Longint minact;
5804 SCIP_Longint maxact;
5805 SCIP_Real intscalar;
5806 SCIP_Bool success;
5807 int nbinvars;
5808 int nconsvars;
5809 int i;
5810
5811 int* tmpindices;
5812 int tmp;
5813 SCIP_CONSHDLR* conshdlr;
5814 SCIP_CONSHDLRDATA* conshdlrdata;
5815 SCIP_Bool noknapsackconshdlr;
5816 SCIP_Bool usegubs;
5817
5818 assert(nknapvars > 0);
5819 assert(knapvars != NULL);
5820 assert(cutoff != NULL);
5821
5822 tmpindices = NULL;
5823
5824 SCIPdebugMsg(scip, "separate linear constraint <%s> relaxed to knapsack\n", cons != NULL ? SCIPconsGetName(cons) : "-");
5825 SCIPdebug( if( cons != NULL ) { SCIPdebugPrintCons(scip, cons, NULL); } );
5826
5827 binvars = SCIPgetVars(scip);
5828
5829 /* all variables which are of integral type can be potentially of binary type; this can be checked via the method SCIPvarIsBinary(var) */
5831
5832 *cutoff = FALSE;
5833
5834 if( nbinvars == 0 )
5835 return SCIP_OKAY;
5836
5837 /* set up data structures */
5840
5841 /* get conshdlrdata to use cleared memory */
5842 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
5843 if( conshdlr == NULL )
5844 {
5846 usegubs = DEFAULT_USEGUBS;
5847
5850 }
5851 else
5852 {
5854 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5855 assert(conshdlrdata != NULL);
5856 usegubs = conshdlrdata->usegubs;
5857
5859
5860 /* increase array size to avoid an endless loop in the next block; this might happen if continuous variables
5861 * change their types to SCIP_VARTYPE_BINARY during presolving
5862 */
5863 if( conshdlrdata->reals1size == 0 )
5864 {
5865 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, conshdlrdata->reals1size, 1) );
5866 conshdlrdata->reals1size = 1;
5867 conshdlrdata->reals1[0] = 0.0;
5868 }
5869
5870 assert(conshdlrdata->reals1size > 0);
5871
5872 /* next if condition should normally not be true, because it means that presolving has created more binary
5873 * variables than binary + integer variables existed at the constraint initialization method, but for example if you would
5874 * transform all integers into their binary representation then it maybe happens
5875 */
5876 if( conshdlrdata->reals1size < nbinvars )
5877 {
5878 int oldsize = conshdlrdata->reals1size;
5879
5880 conshdlrdata->reals1size = nbinvars;
5881 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, oldsize, conshdlrdata->reals1size) );
5882 BMSclearMemoryArray(&(conshdlrdata->reals1[oldsize]), conshdlrdata->reals1size - oldsize); /*lint !e866 */
5883 }
5884 binvals = conshdlrdata->reals1;
5885
5886 /* check for cleared array, all entries have to be zero */
5887#ifndef NDEBUG
5888 for( tmp = nbinvars - 1; tmp >= 0; --tmp )
5889 {
5890 assert(binvals[tmp] == 0);
5891 }
5892#endif
5893 }
5894
5895 tmp = 0;
5896
5897 /* relax continuous knapsack constraint:
5898 * 1. make all variables binary:
5899 * if x_j is continuous or integer variable substitute:
5900 * - a_j < 0: x_j = lb or x_j = b*z + d with variable lower bound b*z + d with binary variable z
5901 * - a_j > 0: x_j = ub or x_j = b*z + d with variable upper bound b*z + d with binary variable z
5902 * 2. convert coefficients of all variables to positive integers:
5903 * - scale all coefficients a_j to a~_j integral
5904 * - substitute x~_j = 1 - x_j if a~_j < 0
5905 */
5906
5907 /* replace integer and continuous variables with binary variables */
5908 for( i = 0; i < nknapvars; i++ )
5909 {
5910 SCIP_VAR* var;
5911
5912 var = knapvars[i];
5913
5915 {
5916 SCIP_Real solval;
5918
5919 solval = SCIPgetSolVal(scip, sol, var);
5920
5921 /* knapsack relaxation assumes solution values between 0.0 and 1.0 for binary variables */
5922 if( SCIPisFeasLT(scip, solval, 0.0 )
5923 || SCIPisFeasGT(scip, solval, 1.0) )
5924 {
5925 SCIPdebugMsg(scip, "Solution value %.15g <%s> outside domain [0.0, 1.0]\n",
5926 solval, SCIPvarGetName(var));
5927 goto TERMINATE;
5928 }
5929
5931 if( !noknapsackconshdlr )
5932 {
5934
5936 ++tmp;
5937 }
5938 SCIPdebugMsg(scip, " -> binary variable %+.15g<%s>(%.15g)\n", valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var));
5939 }
5940 else if( valscale * knapvals[i] > 0.0 )
5941 {
5942 SCIP_VAR** zvlb;
5943 SCIP_Real* bvlb;
5944 SCIP_Real* dvlb;
5945 SCIP_Real bestlbsol;
5946 int bestlbtype;
5947 int nvlb;
5948 int j;
5949
5950 /* a_j > 0: substitution with lb or vlb */
5955
5956 /* search for lb or vlb with maximal bound value */
5958 bestlbtype = -1;
5959 for( j = 0; j < nvlb; j++ )
5960 {
5961 /* use only numerical stable vlb with binary variable z */
5963 {
5964 SCIP_Real vlbsol;
5965
5966 if( (bvlb[j] >= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetLbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) ||
5968 {
5969 *cutoff = TRUE;
5970 SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] >= %g<%s>[%g,%g] + %g implies local cutoff\n",
5973 goto TERMINATE;
5974 }
5975
5977 vlbsol = bvlb[j] * SCIPgetSolVal(scip, sol, zvlb[j]) + dvlb[j];
5978 if( SCIPisGE(scip, vlbsol, bestlbsol) )
5979 {
5980 bestlbsol = vlbsol;
5981 bestlbtype = j;
5982 }
5983 }
5984 }
5985
5986 /* if no lb or vlb with binary variable was found, we have to abort */
5988 goto TERMINATE;
5989
5990 if( bestlbtype == -1 )
5991 {
5992 rhs -= valscale * knapvals[i] * bestlbsol;
5993 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with lower bound %.15g (rhs=%.15g)\n",
5995 }
5996 else
5997 {
5999 rhs -= valscale * knapvals[i] * dvlb[bestlbtype];
6001
6003 goto TERMINATE;
6004
6005 if( !noknapsackconshdlr )
6006 {
6008
6010 ++tmp;
6011 }
6012 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable lower bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
6016 }
6017 }
6018 else
6019 {
6020 SCIP_VAR** zvub;
6021 SCIP_Real* bvub;
6022 SCIP_Real* dvub;
6023 SCIP_Real bestubsol;
6024 int bestubtype;
6025 int nvub;
6026 int j;
6027
6028 assert(valscale * knapvals[i] < 0.0);
6029
6030 /* a_j < 0: substitution with ub or vub */
6035
6036 /* search for ub or vub with minimal bound value */
6038 bestubtype = -1;
6039 for( j = 0; j < nvub; j++ )
6040 {
6041 /* use only numerical stable vub with active binary variable z */
6043 {
6044 SCIP_Real vubsol;
6045
6046 if( (bvub[j] >= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetUbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) ||
6048 {
6049 *cutoff = TRUE;
6050 SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] <= %g<%s>[%g,%g] + %g implies local cutoff\n",
6053 goto TERMINATE;
6054 }
6055
6057 vubsol = bvub[j] * SCIPgetSolVal(scip, sol, zvub[j]) + dvub[j];
6058 if( SCIPisLE(scip, vubsol, bestubsol) )
6059 {
6060 bestubsol = vubsol;
6061 bestubtype = j;
6062 }
6063 }
6064 }
6065
6066 /* if no ub or vub with binary variable was found, we have to abort */
6068 goto TERMINATE;
6069
6070 if( bestubtype == -1 )
6071 {
6072 rhs -= valscale * knapvals[i] * bestubsol;
6073 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with upper bound %.15g (rhs=%.15g)\n",
6075 }
6076 else
6077 {
6079 rhs -= valscale * knapvals[i] * dvub[bestubtype];
6081
6083 goto TERMINATE;
6084
6085 if( !noknapsackconshdlr )
6086 {
6088
6090 ++tmp;
6091 }
6092 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable upper bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
6096 }
6097 }
6098 }
6099
6100 /* convert coefficients of all (now binary) variables to positive integers:
6101 * - make all coefficients integral
6102 * - make all coefficients positive (substitute negated variable)
6103 */
6104 nconsvars = 0;
6105
6106 /* calculate scalar which makes all coefficients integral in relative allowed difference in between
6107 * -SCIPepsilon(scip) and KNAPSACKRELAX_MAXDELTA
6108 */
6111 SCIPdebugMsg(scip, " -> intscalar = %.15g\n", intscalar);
6112
6113 /* if coefficients cannot be made integral, we have to use a scalar of 1.0 and only round fractional coefficients down */
6114 if( !success )
6115 intscalar = 1.0;
6116
6117 /* make all coefficients integral and positive:
6118 * - scale a~_j = a_j * intscalar
6119 * - substitute x~_j = 1 - x_j if a~_j < 0
6120 */
6121 rhs = rhs * intscalar;
6122
6123 SCIPdebugMsg(scip, " -> rhs = %.15g\n", rhs);
6124 minact = 0;
6125 maxact = 0;
6126 for( i = 0; i < nbinvars; i++ )
6127 {
6128 SCIP_VAR* var;
6129 SCIP_Longint val;
6130
6132 if( val == 0 )
6133 continue;
6134
6135 if( val > 0 )
6136 {
6137 var = binvars[i];
6138 SCIPdebugMsg(scip, " -> positive scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): not changed (rhs=%.15g)\n",
6139 val, SCIPvarGetName(var), binvals[i], rhs);
6140 }
6141 else
6142 {
6143 assert(val < 0);
6144
6145 SCIP_CALL( SCIPgetNegatedVar(scip, binvars[i], &var) );
6146 val = -val; /*lint !e2704*/
6147 rhs += val;
6148 SCIPdebugMsg(scip, " -> negative scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): substituted by (1 - <%s>) (rhs=%.15g)\n",
6149 -val, SCIPvarGetName(binvars[i]), binvals[i], SCIPvarGetName(var), rhs);
6150 }
6151
6152 if( SCIPvarGetLbLocal(var) > 0.5 )
6153 minact += val;
6154 if( SCIPvarGetUbLocal(var) > 0.5 )
6155 maxact += val;
6156 consvals[nconsvars] = val;
6157 consvars[nconsvars] = var;
6158 nconsvars++;
6159 }
6160
6161 if( nconsvars > 0 )
6162 {
6163 SCIP_Longint capacity;
6164
6165 assert(consvars != NULL);
6166 assert(consvals != NULL);
6167 capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
6168
6169#ifdef SCIP_DEBUG
6170 {
6171 SCIP_Real act;
6172
6173 SCIPdebugMsg(scip, " -> linear constraint <%s> relaxed to knapsack:", cons != NULL ? SCIPconsGetName(cons) : "-");
6174 act = 0.0;
6175 for( i = 0; i < nconsvars; ++i )
6176 {
6177 SCIPdebugMsgPrint(scip, " %+" SCIP_LONGINT_FORMAT "<%s>(%.15g)", consvals[i], SCIPvarGetName(consvars[i]),
6178 SCIPgetSolVal(scip, sol, consvars[i]));
6179 act += consvals[i] * SCIPgetSolVal(scip, sol, consvars[i]);
6180 }
6181 SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT " (%.15g) [act: %.15g, min: %" SCIP_LONGINT_FORMAT " max: %" SCIP_LONGINT_FORMAT "]\n",
6182 capacity, rhs, act, minact, maxact);
6183 }
6184#endif
6185
6186 if( minact > capacity )
6187 {
6188 SCIPdebugMsg(scip, "minactivity of knapsack relaxation implies local cutoff\n");
6189 *cutoff = TRUE;
6190 goto TERMINATE;
6191 }
6192
6193 if( maxact > capacity )
6194 {
6195 /* separate lifted cut from relaxed knapsack constraint */
6196 SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, sepa, consvars, nconsvars, consvals, capacity, sol, usegubs, cutoff, ncuts) );
6197 }
6198 }
6199
6200 TERMINATE:
6201 /* free data structures */
6203 {
6205 }
6206 else
6207 {
6208 /* clear binvals */
6209 for( --tmp; tmp >= 0; --tmp)
6210 {
6212 binvals[tmpindices[tmp]] = 0;
6213 }
6215 }
6217 SCIPfreeBufferArray(scip, &consvars);
6218
6219 return SCIP_OKAY;
6220}
6221
6222/** separates given knapsack constraint */
6223static
6225 SCIP* scip, /**< SCIP data structure */
6226 SCIP_CONS* cons, /**< knapsack constraint */
6227 SCIP_SOL* sol, /**< primal SCIP solution, NULL for current LP solution */
6228 SCIP_Bool sepacuts, /**< should knapsack cuts be separated? */
6229 SCIP_Bool usegubs, /**< should GUB information be used for separation? */
6230 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
6231 int* ncuts /**< pointer to add up the number of found cuts */
6232 )
6233{
6234 SCIP_CONSDATA* consdata;
6235 SCIP_Bool violated;
6236
6237 assert(ncuts != NULL);
6238 assert(cutoff != NULL);
6239 *cutoff = FALSE;
6240
6241 consdata = SCIPconsGetData(cons);
6242 assert(consdata != NULL);
6243
6244 SCIPdebugMsg(scip, "separating knapsack constraint <%s>\n", SCIPconsGetName(cons));
6245
6246 /* check knapsack constraint itself for feasibility */
6247 SCIP_CALL( checkCons(scip, cons, sol, (sol != NULL), FALSE, &violated) );
6248
6249 if( violated )
6250 {
6251 /* add knapsack constraint as LP row to the LP */
6253 (*ncuts)++;
6254 }
6255 else if( sepacuts )
6256 {
6257 SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, NULL, consdata->vars, consdata->nvars, consdata->weights,
6258 consdata->capacity, sol, usegubs, cutoff, ncuts) );
6259 }
6260
6261 return SCIP_OKAY;
6262}
6263
6264/** adds coefficient to constraint data */
6265static
6267 SCIP* scip, /**< SCIP data structure */
6268 SCIP_CONS* cons, /**< knapsack constraint */
6269 SCIP_VAR* var, /**< variable to add to knapsack */
6270 SCIP_Longint weight /**< weight of variable in knapsack */
6271 )
6272{
6273 SCIP_CONSDATA* consdata;
6274
6275 consdata = SCIPconsGetData(cons);
6276 assert(consdata != NULL);
6278 assert(weight > 0);
6279
6280 /* add the new coefficient to the LP row */
6281 if( consdata->row != NULL )
6282 {
6283 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, (SCIP_Real)weight) );
6284 }
6285
6286 /* check for fixed variable */
6287 if( SCIPvarGetLbGlobal(var) > 0.5 )
6288 {
6289 /* variable is fixed to one: reduce capacity */
6290 consdata->capacity -= weight;
6291 }
6292 else if( SCIPvarGetUbGlobal(var) > 0.5 )
6293 {
6294 SCIP_Bool negated;
6295
6296 /* get binary representative of variable */
6298
6299 /* insert coefficient */
6300 SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1, SCIPconsIsTransformed(cons)) );
6301 consdata->vars[consdata->nvars] = var;
6302 consdata->weights[consdata->nvars] = weight;
6303 consdata->nvars++;
6304
6305 /* capture variable */
6307
6308 /* install the rounding locks of variable */
6309 SCIP_CALL( lockRounding(scip, cons, var) );
6310
6311 /* catch events */
6312 if( SCIPconsIsTransformed(cons) )
6313 {
6314 SCIP_CONSHDLRDATA* conshdlrdata;
6315
6316 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6317 assert(conshdlrdata != NULL);
6318 SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[consdata->nvars-1], cons, weight) );
6320 conshdlrdata->eventhdlr, consdata->eventdata[consdata->nvars-1],
6321 &consdata->eventdata[consdata->nvars-1]->filterpos) );
6322
6323 if( !consdata->existmultaggr && SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR )
6324 consdata->existmultaggr = TRUE;
6325
6326 /* mark constraint to be propagated and presolved */
6328 consdata->presolvedtiming = 0;
6329 consdata->cliquesadded = FALSE; /* new coefficient might lead to larger cliques */
6330 }
6331
6332 /* update weight sums */
6333 updateWeightSums(consdata, var, weight);
6334
6335 consdata->sorted = FALSE;
6336 consdata->cliquepartitioned = FALSE;
6337 consdata->negcliquepartitioned = FALSE;
6338 consdata->merged = FALSE;
6339 }
6340
6341 return SCIP_OKAY;
6342}
6343
6344/** deletes coefficient at given position from constraint data */
6345static
6347 SCIP* scip, /**< SCIP data structure */
6348 SCIP_CONS* cons, /**< knapsack constraint */
6349 int pos /**< position of coefficient to delete */
6350 )
6351{
6352 SCIP_CONSDATA* consdata;
6353 SCIP_VAR* var;
6354
6355 consdata = SCIPconsGetData(cons);
6356 assert(consdata != NULL);
6357 assert(0 <= pos && pos < consdata->nvars);
6358
6359 var = consdata->vars[pos];
6360 assert(var != NULL);
6362
6363 /* delete the coefficient from the LP row */
6364 if( consdata->row != NULL )
6365 {
6366 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, -(SCIP_Real)consdata->weights[pos]) );
6367 }
6368
6369 /* remove the rounding locks of variable */
6370 SCIP_CALL( unlockRounding(scip, cons, var) );
6371
6372 /* drop events and mark constraint to be propagated and presolved */
6373 if( SCIPconsIsTransformed(cons) )
6374 {
6375 SCIP_CONSHDLRDATA* conshdlrdata;
6376
6377 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6378 assert(conshdlrdata != NULL);
6380 conshdlrdata->eventhdlr, consdata->eventdata[pos], consdata->eventdata[pos]->filterpos) );
6381 SCIP_CALL( eventdataFree(scip, &consdata->eventdata[pos]) );
6382
6384 consdata->presolvedtiming = 0;
6385 consdata->sorted = (consdata->sorted && pos == consdata->nvars - 1);
6386 }
6387
6388 /* decrease weight sums */
6389 updateWeightSums(consdata, var, -consdata->weights[pos]);
6390
6391 /* move the last variable to the free slot */
6392 consdata->vars[pos] = consdata->vars[consdata->nvars-1];
6393 consdata->weights[pos] = consdata->weights[consdata->nvars-1];
6394 if( consdata->eventdata != NULL )
6395 consdata->eventdata[pos] = consdata->eventdata[consdata->nvars-1];
6396
6397 /* release variable */
6399
6400 /* try to use old clique partitions */
6401 if( consdata->cliquepartitioned )
6402 {
6403 assert(consdata->cliquepartition != NULL);
6404 /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6405 * change the clique number */
6406 if( consdata->cliquepartition[consdata->nvars - 1] != consdata->nvars - 1 )
6407 {
6408 int oldcliqenum;
6409
6410 oldcliqenum = consdata->cliquepartition[pos];
6411 consdata->cliquepartition[pos] = consdata->cliquepartition[consdata->nvars-1];
6412
6413 /* the following if and else cases assure that we have increasing clique numbers */
6414 if( consdata->cliquepartition[pos] > pos )
6415 consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6416 else
6417 {
6418 int i;
6419 int cliquenumbefore;
6420
6421 /* if the old clique number was greater than the new one we have to check that before a bigger clique number
6422 * occurs the same as the old one is still in the cliquepartition */
6423 if( oldcliqenum > consdata->cliquepartition[pos] )
6424 {
6425 for( i = 0; i < consdata->nvars; ++i )
6426 if( oldcliqenum == consdata->cliquepartition[i] )
6427 break;
6428 else if( oldcliqenum < consdata->cliquepartition[i] )
6429 {
6430 consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6431 break;
6432 }
6433 /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6434 * the biggest index, so decrease the number of cliques
6435 */
6436 if( i == consdata->nvars )
6437 --(consdata->ncliques);
6438 }
6439 /* if the old clique number was smaller than the new one we have to check the front for an element with
6440 * clique number minus 1 */
6441 else if( oldcliqenum < consdata->cliquepartition[pos] )
6442 {
6443 cliquenumbefore = consdata->cliquepartition[pos] - 1;
6444 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6445
6446 if( i < cliquenumbefore )
6447 consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6448 }
6449 /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6450 else if( pos == consdata->nvars - 1)
6451 {
6452 cliquenumbefore = consdata->cliquepartition[pos];
6453 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6454
6455 if( i < cliquenumbefore )
6456 --(consdata->ncliques);
6457 }
6458 /* if the old clique number is equal to the new one the cliquepartition should be ok */
6459 }
6460 }
6461 else
6462 --(consdata->ncliques);
6463 }
6464
6465 if( consdata->negcliquepartitioned )
6466 {
6467 assert(consdata->negcliquepartition != NULL);
6468 /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6469 * change the clique number */
6470 if( consdata->negcliquepartition[consdata->nvars-1] != consdata->nvars - 1 )
6471 {
6472 int oldcliqenum;
6473
6474 oldcliqenum = consdata->negcliquepartition[pos];
6475 consdata->negcliquepartition[pos] = consdata->negcliquepartition[consdata->nvars-1];
6476
6477 /* the following if and else cases assure that we have increasing clique numbers */
6478 if( consdata->negcliquepartition[pos] > pos )
6479 consdata->negcliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6480 else
6481 {
6482 int i;
6483 int cliquenumbefore;
6484
6485 /* if the old clique number was greater than the new one we have to check that, before a bigger clique number
6486 * occurs, the same as the old one occurs */
6487 if( oldcliqenum > consdata->negcliquepartition[pos] )
6488 {
6489 for( i = 0; i < consdata->nvars; ++i )
6490 if( oldcliqenum == consdata->negcliquepartition[i] )
6491 break;
6492 else if( oldcliqenum < consdata->negcliquepartition[i] )
6493 {
6494 consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6495 break;
6496 }
6497 /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6498 * the biggest index, so decrease the number of negated cliques
6499 */
6500 if( i == consdata->nvars )
6501 --(consdata->nnegcliques);
6502 }
6503 /* if the old clique number was smaller than the new one we have to check the front for an element with
6504 * clique number minus 1 */
6505 else if( oldcliqenum < consdata->negcliquepartition[pos] )
6506 {
6507 cliquenumbefore = consdata->negcliquepartition[pos] - 1;
6508 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6509
6510 if( i < cliquenumbefore )
6511 consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6512 }
6513 /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6514 else if( pos == consdata->nvars - 1)
6515 {
6516 cliquenumbefore = consdata->negcliquepartition[pos];
6517 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6518
6519 if( i < cliquenumbefore )
6520 --(consdata->nnegcliques);
6521 }
6522 /* otherwise if the old clique number is equal to the new one the cliquepartition should be ok */
6523 }
6524 }
6525 else
6526 --(consdata->nnegcliques);
6527 }
6528
6529 --(consdata->nvars);
6530
6531 return SCIP_OKAY;
6532}
6533
6534/** removes all items with weight zero from knapsack constraint */
6535static
6537 SCIP* scip, /**< SCIP data structure */
6538 SCIP_CONS* cons /**< knapsack constraint */
6539 )
6540{
6541 SCIP_CONSDATA* consdata;
6542 int v;
6543
6544 consdata = SCIPconsGetData(cons);
6545 assert(consdata != NULL);
6546
6547 for( v = consdata->nvars-1; v >= 0; --v )
6548 {
6549 if( consdata->weights[v] == 0 )
6550 {
6551 SCIP_CALL( delCoefPos(scip, cons, v) );
6552 }
6553 }
6554
6555 return SCIP_OKAY;
6556}
6557
6558/* perform deletion of variables in all constraints of the constraint handler */
6559static
6561 SCIP* scip, /**< SCIP data structure */
6562 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6563 SCIP_CONS** conss, /**< array of constraints */
6564 int nconss /**< number of constraints */
6565 )
6566{
6567 SCIP_CONSDATA* consdata;
6568 int i;
6569 int v;
6570
6571 assert(scip != NULL);
6572 assert(conshdlr != NULL);
6573 assert(conss != NULL);
6574 assert(nconss >= 0);
6576
6577 /* iterate over all constraints */
6578 for( i = 0; i < nconss; i++ )
6579 {
6580 consdata = SCIPconsGetData(conss[i]);
6581
6582 /* constraint is marked, that some of its variables were deleted */
6583 if( consdata->varsdeleted )
6584 {
6585 /* iterate over all variables of the constraint and delete them from the constraint */
6586 for( v = consdata->nvars - 1; v >= 0; --v )
6587 {
6588 if( SCIPvarIsDeleted(consdata->vars[v]) )
6589 {
6590 SCIP_CALL( delCoefPos(scip, conss[i], v) );
6591 }
6592 }
6593 consdata->varsdeleted = FALSE;
6594 }
6595 }
6596
6597 return SCIP_OKAY;
6598}
6599
6600/** replaces multiple occurrences of a variable or its negation by a single coefficient */
6601static
6603 SCIP* scip, /**< SCIP data structure */
6604 SCIP_CONS* cons, /**< knapsack constraint */
6605 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
6606 )
6607{
6608 SCIP_CONSDATA* consdata;
6609 int v;
6610 int prev;
6611
6612 assert(scip != NULL);
6613 assert(cons != NULL);
6614 assert(cutoff != NULL);
6615
6616 consdata = SCIPconsGetData(cons);
6617 assert(consdata != NULL);
6618
6619 *cutoff = FALSE;
6620
6621 if( consdata->merged )
6622 return SCIP_OKAY;
6623
6624 if( consdata->nvars <= 1 )
6625 {
6626 consdata->merged = TRUE;
6627 return SCIP_OKAY;
6628 }
6629
6630 assert(consdata->vars != NULL || consdata->nvars == 0);
6631
6632 /* sorting array after indices of variables, that's only for faster merging */
6633 SCIPsortPtrPtrLongIntInt((void**)consdata->vars, (void**)consdata->eventdata, consdata->weights,
6634 consdata->cliquepartition, consdata->negcliquepartition, SCIPvarCompActiveAndNegated, consdata->nvars);
6635
6636 /* knapsack-sorting (decreasing weights) now lost */
6637 consdata->sorted = FALSE;
6638
6639 v = consdata->nvars - 1;
6640 prev = v - 1;
6641 /* loop backwards through the items: deletion only affects rear items */
6642 while( prev >= 0 )
6643 {
6644 SCIP_VAR* var1;
6645 SCIP_VAR* var2;
6646 SCIP_Bool negated1;
6647 SCIP_Bool negated2;
6648
6649 negated1 = FALSE;
6650 negated2 = FALSE;
6651
6652 var1 = consdata->vars[v];
6656 {
6658 negated1 = TRUE;
6659 }
6660 assert(var1 != NULL);
6661
6662 var2 = consdata->vars[prev];
6666 {
6668 negated2 = TRUE;
6669 }
6670 assert(var2 != NULL);
6671
6672 if( var1 == var2 )
6673 {
6674 /* both variables are either active or negated */
6675 if( negated1 == negated2 )
6676 {
6677 /* variables var1 and var2 are equal: add weight of var1 to var2, and delete var1 */
6678 consdataChgWeight(consdata, prev, consdata->weights[v] + consdata->weights[prev]);
6679 SCIP_CALL( delCoefPos(scip, cons, v) );
6680 }
6681 /* variables var1 and var2 are opposite: subtract smaller weight from larger weight, reduce capacity,
6682 * and delete item of smaller weight
6683 */
6684 else if( consdata->weights[v] == consdata->weights[prev] )
6685 {
6686 /* both variables eliminate themselves: w*x + w*(1-x) == w */
6687 consdata->capacity -= consdata->weights[v];
6688 SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6689 SCIP_CALL( delCoefPos(scip, cons, prev) );
6690
6691 --prev;
6692 }
6693 else if( consdata->weights[v] < consdata->weights[prev] )
6694 {
6695 consdata->capacity -= consdata->weights[v];
6696 consdataChgWeight(consdata, prev, consdata->weights[prev] - consdata->weights[v]);
6697 assert(consdata->weights[prev] > 0);
6698 SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6699 }
6700 else
6701 {
6702 consdata->capacity -= consdata->weights[prev];
6703 consdataChgWeight(consdata, v, consdata->weights[v] - consdata->weights[prev]);
6704 assert(consdata->weights[v] > 0);
6705 SCIP_CALL( delCoefPos(scip, cons, prev) ); /* attention: normally we lose our order */
6706 /* restore order iff necessary */
6707 if( consdata->nvars != v ) /* otherwise the order still stands */
6708 {
6709 assert(prev == 0 || ((prev > 0) && (SCIPvarIsActive(consdata->vars[prev - 1]) || SCIPvarGetStatus(consdata->vars[prev - 1]) == SCIP_VARSTATUS_NEGATED)) );
6710 /* either that was the last pair or both, the negated and "normal" variable in front doesn't match var1, so the order is irrelevant */
6711 if( prev == 0 || (var1 != consdata->vars[prev - 1] && var1 != SCIPvarGetNegatedVar(consdata->vars[prev - 1])) )
6712 --prev;
6713 else /* we need to let v at the same position*/
6714 {
6715 consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6716 /* don't decrease v, the same variable may exist up front */
6717 --prev;
6718 continue;
6719 }
6720 }
6721 }
6722 consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6723 }
6724 v = prev;
6725 --prev;
6726 }
6727
6728 consdata->merged = TRUE;
6729
6730 /* check infeasibility */
6731 if( consdata->onesweightsum > consdata->capacity )
6732 {
6733 SCIPdebugMsg(scip, "merge multiples detected cutoff.\n");
6734 *cutoff = TRUE;
6735 return SCIP_OKAY;
6736 }
6737
6738 return SCIP_OKAY;
6739}
6740
6741/** in case the knapsack constraint is independent of every else, solve the knapsack problem (exactly) and apply the
6742 * fixings (dual reductions)
6743 */
6744static
6746 SCIP* scip, /**< SCIP data structure */
6747 SCIP_CONS* cons, /**< knapsack constraint */
6748 int* nfixedvars, /**< pointer to count number of fixings */
6749 int* ndelconss, /**< pointer to count number of deleted constraints */
6750 SCIP_Bool* deleted /**< pointer to store if the constraint is deleted */
6751 )
6752{
6753 SCIP_CONSDATA* consdata;
6754 SCIP_VAR** vars;
6755 SCIP_Real* profits;
6756 int* solitems;
6757 int* nonsolitems;
6758 int* items;
6759 SCIP_Real solval;
6760 SCIP_Bool infeasible;
6761 SCIP_Bool tightened;
6762 SCIP_Bool applicable;
6763 int nsolitems;
6764 int nnonsolitems;
6765 int nvars;
6766 int v;
6767
6769
6770 /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
6771 * use the locks to decide for a dual reduction using this constraint; for example after a restart the cuts which are
6772 * added to the problems have the check flag set to FALSE
6773 */
6774 if( !SCIPconsIsChecked(cons) )
6775 return SCIP_OKAY;
6776
6777 consdata = SCIPconsGetData(cons);
6778 assert(consdata != NULL);
6779
6780 nvars = consdata->nvars;
6781 vars = consdata->vars;
6782
6787
6788 applicable = TRUE;
6789
6790 /* check if we can apply the dual reduction; this can be done if the knapsack has the only locks on this constraint;
6791 * collect object values which are the profits of the knapsack problem
6792 */
6793 for( v = 0; v < nvars; ++v )
6794 {
6795 SCIP_VAR* var;
6796 SCIP_Bool negated;
6797
6798 var = vars[v];
6799 assert(var != NULL);
6800
6801 /* the variable should not be (globally) fixed */
6803
6806 {
6807 applicable = FALSE;
6808 break;
6809 }
6810
6811 negated = FALSE;
6812
6813 /* get the active variable */
6816
6817 if( negated )
6819 else
6820 profits[v] = -SCIPvarGetObj(var);
6821
6822 SCIPdebugMsg(scip, "variable <%s> -> item size %" SCIP_LONGINT_FORMAT ", profit <%g>\n",
6823 SCIPvarGetName(vars[v]), consdata->weights[v], profits[v]);
6824 items[v] = v;
6825 }
6826
6827 if( applicable )
6828 {
6829 SCIP_Bool success;
6830
6831 SCIPdebugMsg(scip, "the knapsack constraint <%s> is independent to rest of the problem\n", SCIPconsGetName(cons));
6833
6834 /* solve knapsack problem exactly */
6835 SCIP_CALL( SCIPsolveKnapsackExactly(scip, consdata->nvars, consdata->weights, profits, consdata->capacity,
6837
6838 if( success )
6839 {
6840 SCIP_VAR* var;
6841
6842 /* apply solution of the knapsack as dual reductions */
6843 for( v = 0; v < nsolitems; ++v )
6844 {
6845 var = vars[solitems[v]];
6846 assert(var != NULL);
6847
6848 SCIPdebugMsg(scip, "variable <%s> only locked up in knapsack constraints: dual presolve <%s>[%.15g,%.15g] >= 1.0\n",
6850 SCIP_CALL( SCIPtightenVarLb(scip, var, 1.0, TRUE, &infeasible, &tightened) );
6851 assert(!infeasible);
6852 assert(tightened);
6853 (*nfixedvars)++;
6854 }
6855
6856 for( v = 0; v < nnonsolitems; ++v )
6857 {
6858 var = vars[nonsolitems[v]];
6859 assert(var != NULL);
6860
6861 SCIPdebugMsg(scip, "variable <%s> has no down locks: dual presolve <%s>[%.15g,%.15g] <= 0.0\n",
6863 SCIP_CALL( SCIPtightenVarUb(scip, var, 0.0, TRUE, &infeasible, &tightened) );
6864 assert(!infeasible);
6865 assert(tightened);
6866 (*nfixedvars)++;
6867 }
6868
6869 SCIP_CALL( SCIPdelCons(scip, cons) );
6870 (*ndelconss)++;
6871 (*deleted) = TRUE;
6872 }
6873 }
6874
6879
6880 return SCIP_OKAY;
6881}
6882
6883/** check if the knapsack constraint is parallel to objective function; if so update the cutoff bound and avoid that the
6884 * constraint enters the LP by setting the initial and separated flag to FALSE
6885 */
6886static
6888 SCIP* scip, /**< SCIP data structure */
6889 SCIP_CONS* cons, /**< knapsack constraint */
6890 SCIP_CONSHDLRDATA* conshdlrdata /**< knapsack constraint handler data */
6891 )
6892{
6893 SCIP_CONSDATA* consdata;
6894 SCIP_VAR** vars;
6895 SCIP_VAR* var;
6896 SCIP_Real offset;
6897 SCIP_Real scale;
6898 SCIP_Real objval;
6899 SCIP_Bool applicable;
6900 SCIP_Bool negated;
6901 int nobjvars;
6902 int nvars;
6903 int v;
6904
6905 assert(scip != NULL);
6906 assert(cons != NULL);
6907 assert(conshdlrdata != NULL);
6908
6909 consdata = SCIPconsGetData(cons);
6910 assert(consdata != NULL);
6911
6912 nvars = consdata->nvars;
6913 nobjvars = SCIPgetNObjVars(scip);
6914
6915 /* check if the knapsack constraints has the same number of variables as the objective function and if the initial
6916 * and/or separated flag is set to FALSE
6917 */
6918 if( nvars != nobjvars || (!SCIPconsIsInitial(cons) && !SCIPconsIsSeparated(cons)) )
6919 return SCIP_OKAY;
6920
6921 /* There are no variables in the ojective function and in the constraint. Thus, the constraint is redundant. Since we
6922 * have a pure feasibility problem, we do not want to set a cutoff or lower bound.
6923 */
6924 if( nobjvars == 0 )
6925 return SCIP_OKAY;
6926
6927 vars = consdata->vars;
6928 assert(vars != NULL);
6929
6930 applicable = TRUE;
6931 offset = 0.0;
6932 scale = 1.0;
6933
6934 for( v = 0; v < nvars && applicable; ++v )
6935 {
6936 negated = FALSE;
6937 var = vars[v];
6938 assert(var != NULL);
6939
6940 if( SCIPvarIsNegated(var) )
6941 {
6942 negated = TRUE;
6944 assert(var != NULL);
6945 }
6946
6948
6949 /* if a variable has a zero objective coefficient the knapsack constraint is not parallel to objective function */
6950 if( SCIPisZero(scip, objval) )
6951 applicable = FALSE;
6952 else
6953 {
6954 SCIP_Real weight;
6955
6956 weight = (SCIP_Real)consdata->weights[v];
6957
6958 if( negated )
6959 {
6960 if( v == 0 )
6961 {
6962 /* the first variable defines the scale */
6963 scale = weight / -objval;
6964
6965 offset += weight;
6966 }
6967 else if( SCIPisEQ(scip, -objval * scale, weight) )
6968 offset += weight;
6969 else
6970 applicable = FALSE;
6971 }
6972 else if( v == 0 )
6973 {
6974 /* the first variable define the scale */
6975 scale = weight / objval;
6976 }
6977 else if( !SCIPisEQ(scip, objval * scale, weight) )
6978 applicable = FALSE;
6979 }
6980 }
6981
6982 if( applicable )
6983 {
6984 if( SCIPisPositive(scip, scale) && conshdlrdata->detectcutoffbound )
6985 {
6986 SCIP_Real cutoffbound;
6987
6988 /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
6991
6992 cutoffbound = (consdata->capacity - offset) / scale;
6993
6994 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
6995 SCIPconsGetName(cons), cutoffbound);
6996
6997 /* increase the cutoff bound value by an epsilon to ensue that solution with the value of the cutoff bound are
6998 * still excepted
6999 */
7000 cutoffbound += SCIPcutoffbounddelta(scip);
7001
7002 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
7003 SCIPconsGetName(cons), cutoffbound);
7004
7005 if( cutoffbound < SCIPgetCutoffbound(scip) )
7006 {
7007 SCIPdebugMsg(scip, "update cutoff bound <%g>\n", cutoffbound);
7008
7009 SCIP_CALL( SCIPupdateCutoffbound(scip, cutoffbound) );
7010 }
7011 else
7012 {
7013 /* in case the cutoff bound is worse then currently known one we avoid additionaly enforcement and
7014 * propagation
7015 */
7018 }
7019 }
7020 else if( SCIPisNegative(scip, scale) && conshdlrdata->detectlowerbound )
7021 {
7022 SCIP_Real lowerbound;
7023
7024 /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
7027
7028 lowerbound = (consdata->capacity - offset) / scale;
7029
7030 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a lower bound <%g>\n",
7031 SCIPconsGetName(cons), lowerbound);
7032
7034 }
7035 }
7036
7037 return SCIP_OKAY;
7038}
7039
7040/** sort the variables and weights w.r.t. the clique partition; thereby ensure the current order of the variables when a
7041 * weight of one variable is greater or equal another weight and both variables are in the same cliques */
7042static
7044 SCIP* scip, /**< SCIP data structure */
7045 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
7046 SCIP_VAR** vars, /**< array for sorted variables */
7047 SCIP_Longint* weights, /**< array for sorted weights */
7048 int* cliquestartposs, /**< starting position array for each clique */
7049 SCIP_Bool usenegatedclique /**< should negated or normal clique partition be used */
7050 )
7051{
7052 SCIP_VAR** origvars;
7053 int norigvars;
7054 SCIP_Longint* origweights;
7055 int* cliquepartition;
7056 int ncliques;
7057
7059 SCIP_Longint** weightpointers;
7060 int* cliquecount;
7061
7062 int nextpos;
7063 int c;
7064 int v;
7065
7066 assert(scip != NULL);
7067 assert(consdata != NULL);
7068 assert(vars != NULL);
7069 assert(weights != NULL);
7071
7072 origweights = consdata->weights;
7073 origvars = consdata->vars;
7074 norigvars = consdata->nvars;
7075
7076 assert(origvars != NULL || norigvars == 0);
7077 assert(origweights != NULL || norigvars == 0);
7078
7079 if( norigvars == 0 )
7080 return SCIP_OKAY;
7081
7082 if( usenegatedclique )
7083 {
7084 assert(consdata->negcliquepartitioned);
7085
7086 cliquepartition = consdata->negcliquepartition;
7087 ncliques = consdata->nnegcliques;
7088 }
7089 else
7090 {
7091 assert(consdata->cliquepartitioned);
7092
7093 cliquepartition = consdata->cliquepartition;
7094 ncliques = consdata->ncliques;
7095 }
7096
7097 assert(cliquepartition != NULL);
7098 assert(ncliques > 0);
7099
7100 /* we first count all clique items and alloc temporary memory for a bucket sort */
7103
7104 /* first we count for each clique the number of elements */
7105 for( v = norigvars - 1; v >= 0; --v )
7106 {
7107 assert(0 <= cliquepartition[v] && cliquepartition[v] < ncliques);
7108 ++(cliquecount[cliquepartition[v]]);
7109 }
7110
7111 /*@todo: maybe it is better to put largest cliques up front */
7112
7113#ifndef NDEBUG
7116#endif
7119
7120 nextpos = 0;
7121 /* now we initialize all start pointers for each clique, so they will be ordered */
7122 for( c = 0; c < ncliques; ++c )
7123 {
7124 /* to reach the goal that all variables of each clique will be standing next to each other we will initialize the
7125 * starting pointers for each clique by adding the number of each clique to the last clique starting pointer
7126 * e.g. clique1 has 4 elements and clique2 has 3 elements the the starting pointer for clique1 will be the pointer
7127 * to vars[0], the starting pointer to clique2 will be the pointer to vars[4] and to clique3 it will be
7128 * vars[7]
7129 *
7130 */
7131 varpointers[c] = (SCIP_VAR**) (vars + nextpos);
7132 cliquestartposs[c] = nextpos;
7133 weightpointers[c] = (SCIP_Longint*) (weights + nextpos);
7134 assert(cliquecount[c] > 0);
7135 nextpos += cliquecount[c];
7136 assert(nextpos > 0);
7137 }
7138 assert(nextpos == norigvars);
7139 cliquestartposs[c] = nextpos;
7140
7141 /* now we copy all variable and weights to the right order */
7142 for( v = 0; v < norigvars; ++v )
7143 {
7144 *(varpointers[cliquepartition[v]]) = origvars[v]; /*lint !e613*/
7145 ++(varpointers[cliquepartition[v]]);
7146 *(weightpointers[cliquepartition[v]]) = origweights[v]; /*lint !e613*/
7147 ++(weightpointers[cliquepartition[v]]);
7148 }
7149#ifndef NDEBUG
7150 for( v = 0; v < norigvars; ++v )
7151 {
7152 assert(vars[v] != NULL);
7153 assert(weights[v] > 0);
7154 }
7155#endif
7156
7157 /* free temporary memory */
7161
7162 return SCIP_OKAY;
7163}
7164
7165/** deletes all fixed variables from knapsack constraint, and replaces variables with binary representatives */
7166static
7168 SCIP* scip, /**< SCIP data structure */
7169 SCIP_CONS* cons, /**< knapsack constraint */
7170 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off, or NULL if this
7171 * information is not needed; in this case, we apply all fixings
7172 * instead of stopping after the first infeasible one */
7173 )
7174{
7175 SCIP_CONSDATA* consdata;
7176 int v;
7177
7178 assert(scip != NULL);
7179 assert(cons != NULL);
7180
7181 consdata = SCIPconsGetData(cons);
7182 assert(consdata != NULL);
7183 assert(consdata->nvars == 0 || consdata->vars != NULL);
7184
7185 if( cutoff != NULL )
7186 *cutoff = FALSE;
7187
7188 SCIPdebugMsg(scip, "apply fixings:\n");
7190
7191 /* check infeasibility */
7192 if ( consdata->onesweightsum > consdata->capacity )
7193 {
7194 SCIPdebugMsg(scip, "apply fixings detected cutoff.\n");
7195
7196 if( cutoff != NULL )
7197 *cutoff = TRUE;
7198
7199 return SCIP_OKAY;
7200 }
7201
7202 /* all multi-aggregations should be resolved */
7203 consdata->existmultaggr = FALSE;
7204
7205 v = 0;
7206 while( v < consdata->nvars )
7207 {
7208 SCIP_VAR* var;
7209
7210 var = consdata->vars[v];
7212
7213 if( SCIPvarGetLbGlobal(var) > 0.5 )
7214 {
7216 consdata->capacity -= consdata->weights[v];
7217 SCIP_CALL( delCoefPos(scip, cons, v) );
7218 consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
7219 }
7220 else if( SCIPvarGetUbGlobal(var) < 0.5 )
7221 {
7223 SCIP_CALL( delCoefPos(scip, cons, v) );
7224 }
7225 else
7226 {
7230 SCIP_Longint weight;
7231 SCIP_Bool negated;
7232
7233 weight = consdata->weights[v];
7234
7235 /* get binary representative of variable */
7237 assert(repvar != NULL);
7238
7239 /* check for multi-aggregation */
7241 {
7243 assert(workvar != NULL);
7244 negated = TRUE;
7245 }
7246 else
7247 {
7248 workvar = repvar;
7249 negated = FALSE;
7250 }
7251
7252 /* @todo maybe resolve the problem that the eliminating of the multi-aggregation leads to a non-knapsack
7253 * constraint (converting into a linear constraint), for example the multi-aggregation consist of a non-binary
7254 * variable or due to resolving now their are non-integral coefficients or a non-integral capacity
7255 *
7256 * If repvar is not negated so workvar = repvar, otherwise workvar = 1 - repvar. This means,
7257 * weight * workvar = weight * (a_1*y_1 + ... + a_n*y_n + c)
7258 *
7259 * The explanation for the following block:
7260 * 1a) If repvar is a multi-aggregated variable weight * repvar should be replaced by
7261 * weight * (a_1*y_1 + ... + a_n*y_n + c).
7262 * 1b) If repvar is a negated variable of a multi-aggregated variable weight * repvar should be replaced by
7263 * weight - weight * (a_1*y_1 + ... + a_n*y_n + c), for better further use here we switch the sign of weight
7264 * so now we have the replacement -weight + weight * (a_1*y_1 + ... + a_n*y_n + c).
7265 * 2) For all replacement variable we check:
7266 * 2a) weight * a_i < 0 than we add -weight * a_i * y_i_neg to the constraint and adjust the capacity through
7267 * capacity -= weight * a_i caused by the negation of y_i.
7268 * 2b) weight * a_i >= 0 than we add weight * a_i * y_i to the constraint.
7269 * 3a) If repvar was not negated we need to subtract weight * c from capacity.
7270 * 3b) If repvar was negated we need to subtract weight * (c - 1) from capacity(note we switched the sign of
7271 * weight in this case.
7272 */
7274 {
7276 SCIP_Real* aggrscalars;
7277 SCIP_Real aggrconst;
7278 int naggrvars;
7279 int i;
7280
7282 naggrvars = SCIPvarGetMultaggrNVars(workvar);
7286 assert((aggrvars != NULL && aggrscalars != NULL) || naggrvars == 0);
7287
7288 if( !SCIPisIntegral(scip, weight * aggrconst) )
7289 {
7290 SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrconst = %g\n", weight*aggrconst);
7291 return SCIP_ERROR;
7292 }
7293
7294 /* if workvar was negated, we have to flip the weight */
7295 if( negated )
7296 weight *= -1;
7297
7298 for( i = naggrvars - 1; i >= 0; --i )
7299 {
7300 assert(aggrvars != NULL);
7302
7303 if( !SCIPvarIsBinary(aggrvars[i]) )
7304 {
7305 SCIPerrorMessage("try to resolve a multi-aggregation with a non-binary %svariable <%s> with bounds [%g,%g]\n",
7307 return SCIP_ERROR;
7308 }
7309 if( !SCIPisIntegral(scip, weight * aggrscalars[i]) )
7310 {
7311 SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrscalars = %g\n", weight*aggrscalars[i]);
7312 return SCIP_ERROR;
7313 }
7314 /* if the new coefficient is smaller than zero, we need to add the negated variable instead and adjust the capacity */
7315 if( SCIPisNegative(scip, weight * aggrscalars[i]) )
7316 {
7318 assert(negvar != NULL);
7319 SCIP_CALL( addCoef(scip, cons, negvar, (SCIP_Longint)(SCIPfloor(scip, -weight * aggrscalars[i] + 0.5))) );
7320 consdata->capacity -= (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5));
7321 }
7322 else
7323 {
7324 SCIP_CALL( addCoef(scip, cons, aggrvars[i], (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5))) );
7325 }
7326 }
7327 /* delete old coefficient */
7328 SCIP_CALL( delCoefPos(scip, cons, v) );
7329
7330 /* adjust the capacity with the aggregation constant and if necessary the extra weight through the negation */
7331 if( negated )
7332 consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * (aggrconst - 1) + 0.5);
7333 else
7334 consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * aggrconst + 0.5);
7335
7336 if( consdata->capacity < 0 )
7337 {
7338 if( cutoff != NULL )
7339 {
7340 *cutoff = TRUE;
7341 break;
7342 }
7343 }
7344 }
7345 /* check, if the variable should be replaced with the representative */
7346 else if( repvar != var )
7347 {
7348 /* delete old (aggregated) variable */
7349 SCIP_CALL( delCoefPos(scip, cons, v) );
7350
7351 /* add representative instead */
7352 SCIP_CALL( addCoef(scip, cons, repvar, weight) );
7353 }
7354 else
7355 ++v;
7356 }
7357 }
7358 assert(consdata->onesweightsum == 0);
7359
7360 SCIPdebugMsg(scip, "after applyFixings, before merging:\n");
7362
7363 /* if aggregated variables have been replaced, multiple entries of the same variable are possible and we have to
7364 * clean up the constraint
7365 */
7366 if( cutoff != NULL && !(*cutoff) )
7367 {
7369 SCIPdebugMsg(scip, "after applyFixings and merging:\n");
7371 }
7372
7373 return SCIP_OKAY;
7374}
7375
7376
7377/** propagation method for knapsack constraints */
7378static
7380 SCIP* scip, /**< SCIP data structure */
7381 SCIP_CONS* cons, /**< knapsack constraint */
7382 SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
7383 SCIP_Bool* redundant, /**< pointer to store whether constraint is redundant */
7384 int* nfixedvars, /**< pointer to count number of fixings */
7385 SCIP_Bool usenegatedclique /**< should negated clique information be used */
7386 )
7387{
7388 SCIP_CONSDATA* consdata;
7389 SCIP_Bool infeasible;
7390 SCIP_Bool tightened;
7391 SCIP_Longint* secondmaxweights;
7392 SCIP_Longint minweightsum;
7393 SCIP_Longint residualcapacity;
7394
7395 int nvars;
7396 int i;
7397 int nnegcliques;
7398
7399 SCIP_VAR** myvars;
7400 SCIP_Longint* myweights;
7401 int* cliquestartposs;
7402 int* cliqueendposs;
7403 SCIP_Longint localminweightsum;
7404 SCIP_Bool foundmax;
7405 int c;
7406
7407 assert(scip != NULL);
7408 assert(cons != NULL);
7409 assert(cutoff != NULL);
7410 assert(redundant != NULL);
7411 assert(nfixedvars != NULL);
7412
7413 consdata = SCIPconsGetData(cons);
7414 assert(consdata != NULL);
7415
7416 *cutoff = FALSE;
7417 *redundant = FALSE;
7418
7419 SCIPdebugMsg(scip, "propagating knapsack constraint <%s>\n", SCIPconsGetName(cons));
7420
7421 /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */
7423 {
7424 SCIP_CALL( SCIPincConsAge(scip, cons) );
7425 }
7426
7427#ifndef NDEBUG
7428 /* assert that only active or negated variables are present */
7429 for( i = 0; i < consdata->nvars && consdata->merged; ++i )
7430 {
7431 assert(SCIPvarIsActive(consdata->vars[i]) || SCIPvarIsNegated(consdata->vars[i]) || SCIPvarGetStatus(consdata->vars[i]) == SCIP_VARSTATUS_FIXED);
7432 }
7433#endif
7434
7435 usenegatedclique = usenegatedclique && consdata->merged;
7436
7437 /* init for debugging */
7438 myvars = NULL;
7439 myweights = NULL;
7442 minweightsum = 0;
7443 nvars = consdata->nvars;
7444 /* make sure, the items are sorted by non-increasing weight */
7445 sortItems(consdata);
7446
7447 do
7448 {
7450
7451 /* (1) compute the minimum weight of the knapsack constraint using negated clique information;
7452 * a negated clique means, that at most one of the clique variables can be zero
7453 * - minweightsum = sum_{negated cliques C} ( sum(wi : i \in C) - W_max(C) ), where W_max(C) is the maximal weight of C
7454 *
7455 * if for i \in C (a negated clique) oneweightsum + minweightsum - wi + W_max(C) > capacity => xi = 1
7456 * since replacing i with the element of maximal weight leads to infeasibility
7457 */
7458 if( usenegatedclique && nvars > 0 )
7459 {
7460 SCIP_CONSHDLRDATA* conshdlrdata;
7461 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7462 assert(conshdlrdata != NULL);
7463
7464 /* compute clique partitions */
7465 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
7466 nnegcliques = consdata->nnegcliques;
7467
7468 /* if we have no real negated cliques we can stop here */
7469 if( nnegcliques == nvars )
7470 {
7471 /* run the standard algorithm that does not involve cliques */
7472 usenegatedclique = FALSE;
7473 break;
7474 }
7475
7476 /* allocate temporary memory and initialize it */
7477 SCIP_CALL( SCIPduplicateBufferArray(scip, &myvars, consdata->vars, nvars) );
7478 SCIP_CALL( SCIPduplicateBufferArray(scip, &myweights, consdata->weights, nvars) ) ;
7479 SCIP_CALL( SCIPallocBufferArray(scip, &cliquestartposs, nnegcliques + 1) );
7483
7484 /* resort variables to avoid quadratic algorithm later on */
7486
7487 /* save the end positions of the cliques because start positions are moved in the following loop */
7488 for( c = 0; c < nnegcliques; ++c )
7489 {
7490 cliqueendposs[c] = cliquestartposs[c+1] - 1;
7492 }
7493
7494 c = 0;
7495 foundmax = FALSE;
7496 i = 0;
7497
7498 while( i < nvars )
7499 {
7500 /* ignore variables of the negated clique which are fixed to one since these are counted in
7501 * consdata->onesweightsum
7502 */
7503
7504 /* if there are only one variable negated cliques left we can stop */
7505 if( nnegcliques - c == nvars - i )
7506 {
7509 break;
7510 }
7511
7512 /* for summing up the minimum active weights due to cliques we have to omit the biggest weights of each
7513 * clique, we can only skip this clique if this variables is not fixed to zero, otherwise we have to fix all
7514 * other clique variables to one
7515 */
7516 if( cliquestartposs[c] == i )
7517 {
7518 assert(myweights[i] > 0);
7519 ++c;
7522 foundmax = TRUE;
7523
7524 if( SCIPvarGetLbLocal(myvars[i]) > 0.5 )
7525 foundmax = FALSE;
7526
7527 if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7528 {
7529 ++i;
7530 continue;
7531 }
7532 }
7533
7534 if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7535 {
7536 assert(myweights[i] > 0);
7537
7538 if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7539 {
7541
7542 if( !foundmax )
7543 {
7544 foundmax = TRUE;
7545
7546 /* overwrite cliquestartpos to the position of the first unfixed variable in this clique */
7547 cliquestartposs[c - 1] = i;
7548 ++i;
7549
7550 continue;
7551 }
7552 /* memorize second max weight for each clique */
7553 if( secondmaxweights[c - 1] == 0 )
7554 secondmaxweights[c - 1] = myweights[i];
7555
7557 }
7558 /* we found a fixed variable to zero so all other variables in this negated clique have to be fixed to one */
7559 else
7560 {
7561 int v;
7562 /* fix all other variables of the negated clique to 1 */
7563 for( v = cliquestartposs[c - 1]; v < cliquestartposs[c]; ++v )
7564 {
7565 if( v != i && SCIPvarGetLbLocal(myvars[v]) < 0.5 )
7566 {
7567 SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[v]));
7568 SCIP_CALL( SCIPinferBinvarCons(scip, myvars[v], TRUE, cons, SCIPvarGetIndex(myvars[i]), &infeasible, &tightened) );
7569
7570 if( infeasible )
7571 {
7572 assert( SCIPvarGetUbLocal(myvars[v]) < 0.5 );
7573
7574 /* analyze the infeasibility if conflict analysis is applicable */
7576 {
7577 /* conflict analysis can only be applied in solving stage */
7579
7580 /* initialize the conflict analysis */
7582
7583 /* add the two variables which are fixed to zero within a negated clique */
7586
7587 /* start the conflict analysis */
7589 }
7590 *cutoff = TRUE;
7591 break;
7592 }
7593 assert(tightened);
7594 ++(*nfixedvars);
7596 }
7597 }
7598
7599 /* reset local minweightsum for clique because all fixed to one variables are now counted in consdata->onesweightsum */
7601 /* we can jump to the end of this clique */
7602 i = cliqueendposs[c - 1];
7603
7604 if( *cutoff )
7605 break;
7606 }
7607 }
7608 ++i;
7609 }
7610 /* add last clique minweightsum */
7612
7613 SCIPdebugMsg(scip, "knapsack constraint <%s> has minimum weight sum of <%" SCIP_LONGINT_FORMAT ">\n",
7614 SCIPconsGetName(cons), minweightsum + consdata->onesweightsum );
7615
7616 /* check, if weights of fixed variables don't exceeds knapsack capacity */
7617 if( !(*cutoff) && consdata->capacity >= minweightsum + consdata->onesweightsum )
7618 {
7619 SCIP_Longint maxcliqueweight = -1LL;
7620
7621 /* loop over cliques */
7622 for( c = 0; c < nnegcliques; ++c )
7623 {
7625 SCIP_Bool maxvarfixed;
7626 int endvarposclique;
7628
7629 assert(myvars != NULL);
7630 assert(nnegcliques == consdata->nnegcliques);
7631 assert(myweights != NULL);
7634
7637
7639
7640 /* no need to process this negated clique because all variables are already fixed (which we detect from a fixed maxvar) */
7642 continue;
7643
7646 /* if the sum of all weights of fixed variables to one plus the minimalweightsum (minimal weight which is already
7647 * used in this knapsack due to negated cliques) plus any weight minus the second largest weight in this clique
7648 * exceeds the capacity the maximum weight variable can be fixed to zero.
7649 */
7650 if( consdata->onesweightsum + minweightsum + (maxcliqueweight - secondmaxweights[c]) > consdata->capacity )
7651 {
7652#ifndef NDEBUG
7653 SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7654#endif
7657
7658 SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(maxvar));
7660 SCIP_CALL( SCIPinferBinvarCons(scip, maxvar, FALSE, cons, cliquestartposs[c], &infeasible, &tightened) );
7661 assert(consdata->onesweightsum == oldonesweightsum);
7662 assert(!infeasible);
7663 assert(tightened);
7664 (*nfixedvars)++;
7665 maxvarfixed = TRUE;
7666 }
7667 /* the remaining cliques are singletons such that all subsequent variables have a weight that
7668 * fits into the knapsack
7669 */
7670 else if( nnegcliques - c == nvars - startvarposclique )
7671 break;
7672 /* early termination of the remaining loop because no further variable fixings are possible:
7673 *
7674 * the gain in any of the following negated cliques (the additional term if the maximum weight variable was set to 1, and the second
7675 * largest was set to 0) does not suffice to infer additional variable fixings because
7676 *
7677 * - the cliques are sorted by decreasing maximum weight -> for all c' >= c: maxweights[c'] <= maxcliqueweight
7678 * - their second largest elements are at least as large as the smallest weight of the knapsack
7679 */
7680 else if( consdata->onesweightsum + minweightsum + (maxcliqueweight - consdata->weights[nvars - 1]) <= consdata->capacity )
7681 break;
7682
7683 /* loop over items with non-maximal weight (omitting the first position) */
7684 for( i = endvarposclique; i > startvarposclique; --i )
7685 {
7686 /* there should be no variable fixed to 0 between startvarposclique + 1 and endvarposclique unless we
7687 * messed up the clique preprocessing in the previous loop to filter those variables out */
7689
7690 /* only check variables of negated cliques for which no variable is locally fixed */
7691 if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7692 {
7695
7696 /* we fix the members of this clique with non-maximal weight in two cases to 1:
7697 *
7698 * the maxvar was already fixed to 0 because it has a huge gain.
7699 *
7700 * if for i \in C (a negated clique) onesweightsum - wi + W_max(c) > capacity => xi = 1
7701 * since replacing i with the element of maximal weight leads to infeasibility */
7702 if( maxvarfixed || consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity )
7703 {
7704#ifndef NDEBUG
7705 SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7706#endif
7707 SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[i]));
7708 SCIP_CALL( SCIPinferBinvarCons(scip, myvars[i], TRUE, cons, -i, &infeasible, &tightened) );
7709 assert(consdata->onesweightsum == oldonesweightsum + myweights[i]);
7710 assert(!infeasible);
7711 assert(tightened);
7712 ++(*nfixedvars);
7714
7715 /* update minweightsum because now the variable is fixed to one and its weight is counted by
7716 * consdata->onesweightsum
7717 */
7719 assert(minweightsum >= 0);
7720 }
7721 else
7722 break;
7723 }
7724 }
7725#ifndef NDEBUG
7726 /* in debug mode, we assert that we did not miss possible fixings by the break above */
7727 for( ; i > startvarposclique; --i )
7728 {
7730 SCIP_Bool exceedscapacity = consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity;
7731
7734 }
7735#endif
7736 }
7737 }
7743 }
7744
7745 assert(consdata->negcliquepartitioned || minweightsum == 0);
7746 }
7747 while( FALSE );
7748
7749 assert(usenegatedclique || minweightsum == 0);
7750 /* check, if weights of fixed variables already exceed knapsack capacity */
7751 if( consdata->capacity < minweightsum + consdata->onesweightsum )
7752 {
7753 SCIPdebugMsg(scip, " -> cutoff - fixed weight: %" SCIP_LONGINT_FORMAT ", capacity: %" SCIP_LONGINT_FORMAT " \n",
7754 consdata->onesweightsum, consdata->capacity);
7755
7757 *cutoff = TRUE;
7758
7759 /* analyze the cutoff in SOLVING stage and if conflict analysis is turned on */
7761 {
7762 /* start conflict analysis with the fixed-to-one variables, add only as many as needed to exceed the capacity */
7763 SCIP_Longint weight;
7764
7765 weight = 0;
7766
7768
7769 for( i = 0; i < nvars && weight <= consdata->capacity; i++ )
7770 {
7771 if( SCIPvarGetLbLocal(consdata->vars[i]) > 0.5)
7772 {
7773 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
7774 weight += consdata->weights[i];
7775 }
7776 }
7777
7779 }
7780
7781 return SCIP_OKAY;
7782 }
7783
7784 /* the algorithm below is a special case of propagation involving negated cliques */
7785 if( !usenegatedclique )
7786 {
7787 assert(consdata->sorted);
7788 residualcapacity = consdata->capacity - consdata->onesweightsum;
7789
7790 /* fix all variables to zero, that don't fit into the knapsack anymore */
7791 for( i = 0; i < nvars && consdata->weights[i] > residualcapacity; ++i )
7792 {
7793 /* if all weights of fixed variables to one plus any weight exceeds the capacity the variables have to be fixed
7794 * to zero
7795 */
7796 if( SCIPvarGetLbLocal(consdata->vars[i]) < 0.5 )
7797 {
7798 if( SCIPvarGetUbLocal(consdata->vars[i]) > 0.5 )
7799 {
7800 assert(consdata->onesweightsum + consdata->weights[i] > consdata->capacity);
7801 SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(consdata->vars[i]));
7803 SCIP_CALL( SCIPinferBinvarCons(scip, consdata->vars[i], FALSE, cons, i, &infeasible, &tightened) );
7804 assert(!infeasible);
7805 assert(tightened);
7806 (*nfixedvars)++;
7807 }
7808 }
7809 }
7810 }
7811
7812 /* check if the knapsack is now redundant */
7813 if( !SCIPconsIsModifiable(cons) )
7814 {
7815 SCIP_Longint unfixedweightsum = consdata->onesweightsum;
7816
7817 /* sum up the weights of all unfixed variables, plus the weight sum of all variables fixed to one already */
7818 for( i = 0; i < nvars; ++i )
7819 {
7820 if( SCIPvarGetLbLocal(consdata->vars[i]) + 0.5 < SCIPvarGetUbLocal(consdata->vars[i]) )
7821 {
7822 unfixedweightsum += consdata->weights[i];
7823
7824 /* the weight sum is larger than the capacity, so the constraint is not redundant */
7825 if( unfixedweightsum > consdata->capacity )
7826 return SCIP_OKAY;
7827 }
7828 }
7829 /* we summed up all (unfixed and fixed to one) weights and did not exceed the capacity, so the constraint is redundant */
7830 SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", unfixedweightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
7831 SCIPconsGetName(cons), consdata->weightsum, unfixedweightsum, consdata->capacity);
7833 *redundant = TRUE;
7834 }
7835
7836 return SCIP_OKAY;
7837}
7838
7839/** all but one variable fit into the knapsack constraint, so we can upgrade this constraint to an logicor constraint
7840 * containing all negated variables of this knapsack constraint
7841 */
7842static
7844 SCIP* scip, /**< SCIP data structure */
7845 SCIP_CONS* cons, /**< knapsack constraint */
7846 int* ndelconss, /**< pointer to store the amount of deleted constraints */
7847 int* naddconss /**< pointer to count number of added constraints */
7848 )
7849{
7851 SCIP_CONSDATA* consdata;
7852
7853 assert(scip != NULL);
7854 assert(cons != NULL);
7855 assert(ndelconss != NULL);
7856 assert(naddconss != NULL);
7857
7858 consdata = SCIPconsGetData(cons);
7859 assert(consdata != NULL);
7860 assert(consdata->nvars > 1);
7861
7862 /* if the knapsack constraint consists only of two variables, we can upgrade it to a set-packing constraint */
7863 if( consdata->nvars == 2 )
7864 {
7865 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
7866
7867 SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
7871 SCIPconsIsStickingAtNode(cons)) );
7872 }
7873 /* if the knapsack constraint consists of at least three variables, we can upgrade it to a logicor constraint
7874 * containing all negated variables of the knapsack
7875 */
7876 else
7877 {
7878 SCIP_VAR** consvars;
7879
7880 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a logicor constraint", SCIPconsGetName(cons));
7881
7882 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, consdata->nvars) );
7883 SCIP_CALL( SCIPgetNegatedVars(scip, consdata->nvars, consdata->vars, consvars) );
7884
7885 SCIP_CALL( SCIPcreateConsLogicor(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consvars,
7889 SCIPconsIsStickingAtNode(cons)) );
7890
7891 SCIPfreeBufferArray(scip, &consvars);
7892 }
7893
7896 ++(*naddconss);
7897
7898 SCIP_CALL( SCIPdelCons(scip, cons) );
7899 ++(*ndelconss);
7900
7901 return SCIP_OKAY;
7902}
7903
7904/** delete redundant variables
7905 *
7906 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
7907 *
7908 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
7909 * => x4, x5 always fits into the knapsack, so we can delete them
7910 *
7911 * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
7912 * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
7913 */
7914static
7916 SCIP* scip, /**< SCIP data structure */
7917 SCIP_CONS* cons, /**< knapsack constraint */
7918 SCIP_Longint frontsum, /**< sum of front items which fit if we try to take from the first till the last */
7919 int splitpos, /**< split position till when all front items are fitting, splitpos is the
7920 * first which did not fit */
7921 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
7922 int* nchgsides, /**< pointer to store the amount of changed sides */
7923 int* naddconss /**< pointer to count number of added constraints */
7924 )
7925{
7926 SCIP_CONSHDLRDATA* conshdlrdata;
7927 SCIP_CONSDATA* consdata;
7928 SCIP_VAR** vars;
7929 SCIP_Longint* weights;
7930 SCIP_Longint capacity;
7931 SCIP_Longint gcd;
7932 int nvars;
7933 int w;
7934
7935 assert(scip != NULL);
7936 assert(cons != NULL);
7937 assert(nchgcoefs != NULL);
7938 assert(nchgsides != NULL);
7939 assert(naddconss != NULL);
7940
7941 consdata = SCIPconsGetData(cons);
7942 assert(consdata != NULL);
7943 assert(0 < frontsum && frontsum < consdata->weightsum);
7945
7946 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7947 assert(conshdlrdata != NULL);
7948
7949 vars = consdata->vars;
7950 weights = consdata->weights;
7951 nvars = consdata->nvars;
7952 capacity = consdata->capacity;
7953
7954 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
7955 * weight must not be sorted by their index
7956 */
7957#ifndef NDEBUG
7958 for( w = nvars - 1; w > 0; --w )
7959 assert(weights[w] <= weights[w-1]);
7960#endif
7961
7962 /* if there are no variables rear to splitpos, the constraint has no redundant variables */
7963 if( consdata->nvars - 1 == splitpos )
7964 return SCIP_OKAY;
7965
7966 assert(frontsum + weights[splitpos] > capacity);
7967
7968 /* detect redundant variables */
7969 if( consdata->weightsum - weights[splitpos] <= capacity )
7970 {
7971 /* all rear items are redundant, because leaving one item in front and incl. of splitpos out the rear itmes always
7972 * fit
7973 */
7974 SCIPdebugMsg(scip, "Found redundant variables in constraint <%s>.\n", SCIPconsGetName(cons));
7975
7976 /* delete items and update capacity */
7977 for( w = nvars - 1; w > splitpos; --w )
7978 {
7979 consdata->capacity -= weights[w];
7980 SCIP_CALL( delCoefPos(scip, cons, w) );
7981 }
7982 assert(w == splitpos);
7983
7984 ++(*nchgsides);
7985 *nchgcoefs += (nvars - splitpos);
7986
7987 /* division by greatest common divisor */
7988 gcd = weights[w];
7989 for( ; w >= 0 && gcd > 1; --w )
7990 {
7991 gcd = SCIPcalcGreComDiv(gcd, weights[w]);
7992 }
7993
7994 /* normalize if possible */
7995 if( gcd > 1 )
7996 {
7997 for( w = splitpos; w >= 0; --w )
7998 {
7999 consdataChgWeight(consdata, w, weights[w]/gcd);
8000 }
8001 (*nchgcoefs) += nvars;
8002
8003 consdata->capacity /= gcd;
8004 ++(*nchgsides);
8005 }
8006
8007 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8008 * weight must not be sorted by their index
8009 */
8010#ifndef NDEBUG
8011 for( w = consdata->nvars - 1; w > 0; --w )
8012 assert(weights[w] <= weights[w - 1]);
8013#endif
8014 }
8015 /* rear items can only be redundant, when the sum is smaller to the weight at splitpos and all rear items would
8016 * always fit into the knapsack, therefor the item directly after splitpos needs to be smaller than the one at
8017 * splitpos and needs to fit into the knapsack
8018 */
8019 else if( conshdlrdata->disaggregation && frontsum + weights[splitpos + 1] <= capacity )
8020 {
8021 int* clqpart;
8022 int nclq;
8023 int len;
8024
8025 len = nvars - (splitpos + 1);
8026 /* allocate temporary memory */
8028
8029 /* calculate clique partition */
8030 SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[splitpos+1]), len, clqpart, &nclq) );
8031
8032 /* check if we found at least one clique */
8033 if( nclq < len )
8034 {
8035 SCIP_Longint maxactduetoclq;
8036 int cliquenum;
8037
8038 maxactduetoclq = 0;
8039 cliquenum = 0;
8040
8041 /* calculate maximum activity due to cliques */
8042 for( w = 0; w < len; ++w )
8043 {
8044 assert(clqpart[w] >= 0 && clqpart[w] <= w);
8045 if( clqpart[w] == cliquenum )
8046 {
8047 maxactduetoclq += weights[w + splitpos + 1];
8048 ++cliquenum;
8049 }
8050 }
8051
8052 /* all rear items are redundant due to clique information, if maxactduetoclq is smaller than the weight before,
8053 * so delete them and create for all clique the corresponding clique constraints and update the capacity
8054 */
8055 if( frontsum + maxactduetoclq <= capacity )
8056 {
8057 SCIP_VAR** clqvars;
8058 int nclqvars;
8059 int c;
8060
8061 assert(maxactduetoclq < weights[splitpos]);
8062
8063 SCIPdebugMsg(scip, "Found redundant variables in constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8064
8065 /* allocate temporary memory */
8067
8068 for( c = 0; c < nclq; ++c )
8069 {
8070 nclqvars = 0;
8071 for( w = 0; w < len; ++w )
8072 {
8073 if( clqpart[w] == c )
8074 {
8075 clqvars[nclqvars] = vars[w + splitpos + 1];
8076 ++nclqvars;
8077 }
8078 }
8079
8080 /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8081 if( nclqvars > 1 )
8082 {
8084 char name[SCIP_MAXSTRLEN];
8085
8086 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8091 SCIPconsIsStickingAtNode(cons)) );
8092 SCIPdebugMsg(scip, " -> adding clique constraint: ");
8096 ++(*naddconss);
8097 }
8098 }
8099
8100 /* delete items and update capacity */
8101 for( w = nvars - 1; w > splitpos; --w )
8102 {
8103 SCIP_CALL( delCoefPos(scip, cons, w) );
8104 ++(*nchgcoefs);
8105 }
8106 consdata->capacity -= maxactduetoclq;
8108 ++(*nchgsides);
8109
8110 assert(w == splitpos);
8111
8112 /* renew weights pointer */
8113 weights = consdata->weights;
8114
8115 /* division by greatest common divisor */
8116 gcd = weights[w];
8117 for( ; w >= 0 && gcd > 1; --w )
8118 {
8119 gcd = SCIPcalcGreComDiv(gcd, weights[w]);
8120 }
8121
8122 /* normalize if possible */
8123 if( gcd > 1 )
8124 {
8125 for( w = splitpos; w >= 0; --w )
8126 {
8127 consdataChgWeight(consdata, w, weights[w]/gcd);
8128 }
8129 (*nchgcoefs) += nvars;
8130
8131 consdata->capacity /= gcd;
8132 ++(*nchgsides);
8133 }
8134
8135 /* free temporary memory */
8137
8138 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8139 * weight must not be sorted by their index
8140 */
8141#ifndef NDEBUG
8142 for( w = consdata->nvars - 1; w > 0; --w )
8143 assert(weights[w] <= weights[w - 1]);
8144#endif
8145 }
8146 }
8147
8148 /* free temporary memory */
8150 }
8151
8152 return SCIP_OKAY;
8153}
8154
8155/* detect redundant variables which always fits into the knapsack
8156 *
8157 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
8158 *
8159 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
8160 * => x4, x5 always fits into the knapsack, so we can delete them
8161 *
8162 * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
8163 * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
8164 */
8165static
8167 SCIP* scip, /**< SCIP data structure */
8168 SCIP_CONS* cons, /**< knapsack constraint */
8169 int* ndelconss, /**< pointer to store the amount of deleted constraints */
8170 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8171 int* nchgsides, /**< pointer to store the amount of changed sides */
8172 int* naddconss /**< pointer to count number of added constraints */
8173 )
8174{
8175 SCIP_CONSHDLRDATA* conshdlrdata;
8176 SCIP_CONSDATA* consdata;
8177 SCIP_VAR** vars;
8178 SCIP_Longint* weights;
8179 SCIP_Longint capacity;
8180 SCIP_Longint sum;
8181 int noldchgcoefs;
8182 int nvars;
8183 int v;
8184 int w;
8185
8186 assert(scip != NULL);
8187 assert(cons != NULL);
8188 assert(ndelconss != NULL);
8189 assert(nchgcoefs != NULL);
8190 assert(nchgsides != NULL);
8191 assert(naddconss != NULL);
8192
8193 consdata = SCIPconsGetData(cons);
8194 assert(consdata != NULL);
8195 assert(consdata->nvars >= 2);
8196 assert(consdata->weightsum > consdata->capacity);
8197
8198 noldchgcoefs = *nchgcoefs;
8199 vars = consdata->vars;
8200 weights = consdata->weights;
8201 nvars = consdata->nvars;
8202 capacity = consdata->capacity;
8203 sum = 0;
8204
8205 /* search for maximal fitting items */
8206 for( v = 0; v < nvars && sum + weights[v] <= capacity; ++v )
8207 sum += weights[v];
8208
8209 assert(v < nvars);
8210
8211 /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8212 if( v == nvars - 1 )
8213 {
8214 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8216
8217 return SCIP_OKAY;
8218 }
8219
8220 if( v < nvars - 1 )
8221 {
8222 /* try to delete variables */
8223 SCIP_CALL( deleteRedundantVars(scip, cons, sum, v, nchgcoefs, nchgsides, naddconss) );
8224 assert(consdata->nvars > 1);
8225
8226 /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8227 if( v == consdata->nvars - 1 )
8228 {
8229 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8231 }
8232
8233 return SCIP_OKAY;
8234 }
8235
8236 /* if we already found some redundant variables, stop here */
8237 if( *nchgcoefs > noldchgcoefs )
8238 return SCIP_OKAY;
8239
8240 assert(vars == consdata->vars);
8241 assert(weights == consdata->weights);
8242 assert(nvars == consdata->nvars);
8243 assert(capacity == consdata->capacity);
8244
8245 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
8246 assert(conshdlrdata != NULL);
8247 /* calculate clique partition */
8248 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
8249
8250 /* check for real existing cliques */
8251 if( consdata->cliquepartition[v] < v )
8252 {
8253 SCIP_Longint sumfront;
8254 SCIP_Longint maxactduetoclqfront;
8255 int* clqpart;
8256 int cliquenum;
8257
8258 sumfront = 0;
8260
8261 clqpart = consdata->cliquepartition;
8262 cliquenum = 0;
8263
8264 /* calculate maximal activity due to cliques */
8265 for( w = 0; w < nvars; ++w )
8266 {
8267 assert(clqpart[w] >= 0 && clqpart[w] <= w);
8268 if( clqpart[w] == cliquenum )
8269 {
8270 if( maxactduetoclqfront + weights[w] <= capacity )
8271 {
8272 maxactduetoclqfront += weights[w];
8273 ++cliquenum;
8274 }
8275 else
8276 break;
8277 }
8278 sumfront += weights[w];
8279 }
8280 assert(w >= v);
8281
8282 /* if all items fit, then delete the whole constraint but create clique constraints which led to this
8283 * information
8284 */
8285 if( conshdlrdata->disaggregation && w == nvars )
8286 {
8287 SCIP_VAR** clqvars;
8288 int nclqvars;
8289 int c;
8290 int ncliques;
8291
8292 assert(maxactduetoclqfront <= capacity);
8293
8294 SCIPdebugMsg(scip, "Found redundant constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8295
8296 ncliques = consdata->ncliques;
8297
8298 /* allocate temporary memory */
8299 SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, nvars - ncliques + 1) );
8300
8301 for( c = 0; c < ncliques; ++c )
8302 {
8303 nclqvars = 0;
8304 for( w = 0; w < nvars; ++w )
8305 {
8306 if( clqpart[w] == c )
8307 {
8308 clqvars[nclqvars] = vars[w];
8309 ++nclqvars;
8310 }
8311 }
8312
8313 /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8314 if( nclqvars > 1 )
8315 {
8317 char name[SCIP_MAXSTRLEN];
8318
8319 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8324 SCIPconsIsStickingAtNode(cons)) );
8325 SCIPdebugMsg(scip, " -> adding clique constraint: ");
8329 ++(*naddconss);
8330 }
8331 }
8332
8333 /* delete old constraint */
8335 ++(*ndelconss);
8336
8338
8339 return SCIP_OKAY;
8340 }
8341
8342 if( w > v && w < nvars - 1 )
8343 {
8344 /* try to delete variables */
8345 SCIP_CALL( deleteRedundantVars(scip, cons, sumfront, w, nchgcoefs, nchgsides, naddconss) );
8346 }
8347 }
8348
8349 return SCIP_OKAY;
8350}
8351
8352/** divides weights by their greatest common divisor and divides capacity by the same value, rounding down the result */
8353static
8355 SCIP_CONS* cons, /**< knapsack constraint */
8356 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
8357 int* nchgsides /**< pointer to count number of side changes */
8358 )
8359{
8360 SCIP_CONSDATA* consdata;
8361 SCIP_Longint gcd;
8362 int i;
8363
8364 assert(nchgcoefs != NULL);
8365 assert(nchgsides != NULL);
8367
8368 consdata = SCIPconsGetData(cons);
8369 assert(consdata != NULL);
8370 assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
8371 assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
8372 assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
8373 assert(consdata->nvars >= 1);
8374
8375 /* sort items, because we can stop earlier if the smaller weights are evaluated first */
8376 sortItems(consdata);
8377
8378 gcd = consdata->weights[consdata->nvars-1];
8379 for( i = consdata->nvars-2; i >= 0 && gcd >= 2; --i )
8380 {
8381 assert(SCIPvarGetLbLocal(consdata->vars[i]) < 0.5);
8382 assert(SCIPvarGetUbLocal(consdata->vars[i]) > 0.5); /* all fixed variables should have been removed */
8383
8384 gcd = SCIPcalcGreComDiv(gcd, consdata->weights[i]);
8385 }
8386
8387 if( gcd >= 2 )
8388 {
8389 SCIPdebugMessage("knapsack constraint <%s>: dividing weights by %" SCIP_LONGINT_FORMAT "\n", SCIPconsGetName(cons), gcd);
8390
8391 for( i = 0; i < consdata->nvars; ++i )
8392 {
8393 consdataChgWeight(consdata, i, consdata->weights[i]/gcd);
8394 }
8395 consdata->capacity /= gcd;
8396 (*nchgcoefs) += consdata->nvars;
8397 (*nchgsides)++;
8398
8399 /* weight should still be sorted, because the reduction preserves this */
8400#ifndef NDEBUG
8401 for( i = consdata->nvars - 1; i > 0; --i )
8402 assert(consdata->weights[i] <= consdata->weights[i - 1]);
8403#endif
8404 consdata->sorted = TRUE;
8405 }
8406}
8407
8408/** dual weights tightening for knapsack constraints
8409 *
8410 * 1. a) check if all two pairs exceed the capacity, then we can upgrade this constraint to a set-packing constraint
8411 * b) check if all but the smallest weight fit into the knapsack, then we can upgrade this constraint to a logicor
8412 * constraint
8413 *
8414 * 2. check if besides big coefficients, that fit only by itself, for a certain amount of variables all combination of
8415 * these are a minimal cover, then might reduce the weights and the capacity, e.g.
8416 *
8417 * +219y1 + 180y2 + 74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8418 *
8419 * 3. use the duality between a^Tx <= capacity <=> a^T~x >= weightsum - capacity to tighten weights, e.g.
8420 *
8421 * 11x1 + 10x2 + 7x3 + 7x4 + 5x5 <= 27 <=> 11~x1 + 10~x2 + 7~x3 + 7~x4 + 5~x5 >= 13
8422 *
8423 * the above constraint can be changed to 8~x1 + 8~x2 + 6.5~x3 + 6.5~x4 + 5~x5 >= 13
8424 *
8425 * 16~x1 + 16~x2 + 13~x3 + 13~x4 + 10~x5 >= 26 <=> 16x1 + 16x2 + 13x3 + 13x4 + 10x5 <= 42
8426 */
8427static
8429 SCIP* scip, /**< SCIP data structure */
8430 SCIP_CONS* cons, /**< knapsack constraint */
8431 int* ndelconss, /**< pointer to store the amount of deleted constraints */
8432 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8433 int* nchgsides, /**< pointer to store the amount of changed sides */
8434 int* naddconss /**< pointer to count number of added constraints */
8435 )
8436{
8437 SCIP_CONSDATA* consdata;
8438 SCIP_Longint* weights;
8439 SCIP_Longint dualcapacity;
8440 SCIP_Longint reductionsum;
8441 SCIP_Longint capacity;
8442 SCIP_Longint exceedsum;
8443 int oldnchgcoefs;
8444 int nvars;
8445 int vbig;
8446 int v;
8447 int w;
8448#ifndef NDEBUG
8449 int oldnchgsides;
8450#endif
8451
8452 assert(scip != NULL);
8453 assert(cons != NULL);
8454 assert(ndelconss != NULL);
8455 assert(nchgcoefs != NULL);
8456 assert(nchgsides != NULL);
8457 assert(naddconss != NULL);
8458
8459#ifndef NDEBUG
8460 oldnchgsides = *nchgsides;
8461#endif
8462
8463 consdata = SCIPconsGetData(cons);
8464 assert(consdata != NULL);
8465 assert(consdata->weightsum > consdata->capacity);
8466 assert(consdata->nvars >= 2);
8467 assert(consdata->sorted);
8468
8469 /* constraint should be merged */
8470 assert(consdata->merged);
8471
8472 nvars = consdata->nvars;
8473 weights = consdata->weights;
8474 capacity = consdata->capacity;
8475
8476 oldnchgcoefs = *nchgcoefs;
8477
8478 /* case 1. */
8479 if( weights[nvars - 1] + weights[nvars - 2] > capacity )
8480 {
8482
8483 /* two variable are enough to exceed the constraint, so we can update it to a set-packing
8484 *
8485 * e.g. 5x1 + 4x2 + 3x3 <= 5 <=> x1 + x2 + x3 <= 1
8486 */
8487 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
8488
8489 SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
8493 SCIPconsIsStickingAtNode(cons)) );
8494
8497 ++(*naddconss);
8498
8499 SCIP_CALL( SCIPdelCons(scip, cons) );
8500 ++(*ndelconss);
8501
8502 return SCIP_OKAY;
8503 }
8504
8505 /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8506 if( consdata->weightsum - weights[nvars - 1] <= consdata->capacity )
8507 {
8508 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8510
8511 return SCIP_OKAY;
8512 }
8513
8514 /* early termination, if the pair with biggest coeffcients together does not exceed the dualcapacity */
8515 /* @todo might be changed/removed when improving the coeffcients tightening */
8516 if( consdata->weightsum - capacity > weights[0] + weights[1] )
8517 return SCIP_OKAY;
8518
8519 /* case 2. */
8520
8521 v = 0;
8522
8523 /* @todo generalize the following algorithm for several parts of the knapsack
8524 *
8525 * the following is done without looking at the dualcapacity; it is enough to check whether for a certain amount of
8526 * variables each combination is a minimal cover, some examples
8527 *
8528 * +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 74~x1 + 70~x2 + 63~x3 + 62~x4 + 53~x5 >= 103
8529 * <=> ~x1 + ~x2 + ~x3 + ~x4 + ~x5 >= 2
8530 * <=> x1 + x2 + x3 + x4 + x5 <= 3
8531 *
8532 * +219y1 + 180y_2 +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8533 *
8534 */
8535
8536 /* determine big weights that fit only by itself */
8537 while( v < nvars && weights[v] + weights[nvars - 1] > capacity )
8538 ++v;
8539
8540 vbig = v;
8541 assert(vbig < nvars - 1);
8542 exceedsum = 0;
8543
8544 /* determine the amount needed to exceed the capacity */
8545 while( v < nvars && exceedsum <= capacity )
8546 {
8547 exceedsum += weights[v];
8548 ++v;
8549 }
8550
8551 /* if we exceeded the capacity we might reduce the weights */
8552 if( exceedsum > capacity )
8553 {
8554 assert(vbig > 0 || v < nvars);
8555
8556 /* all small weights were needed to exceed the capacity */
8557 if( v == nvars )
8558 {
8559 SCIP_Longint newweight = (SCIP_Longint)nvars - vbig - 1;
8560 assert(newweight > 0);
8561
8562 /* reduce big weights */
8563 for( v = 0; v < vbig; ++v )
8564 {
8565 if( weights[v] > newweight )
8566 {
8567 consdataChgWeight(consdata, v, newweight);
8568 ++(*nchgcoefs);
8569 }
8570 }
8571
8572 /* reduce small weights */
8573 for( ; v < nvars; ++v )
8574 {
8575 if( weights[v] > 1 )
8576 {
8577 consdataChgWeight(consdata, v, 1LL);
8578 ++(*nchgcoefs);
8579 }
8580 }
8581
8582 consdata->capacity = newweight;
8583
8584 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8585 * weight must not be sorted by their index
8586 */
8587#ifndef NDEBUG
8588 for( v = nvars - 1; v > 0; --v )
8589 assert(weights[v] <= weights[v-1]);
8590#endif
8591
8592 return SCIP_OKAY;
8593 }
8594 /* a certain amount of small variables exceed the capacity, so check if this holds for all combinations of the
8595 * small weights
8596 */
8597 else
8598 {
8599 SCIP_Longint exceedsumback = 0;
8600 int nexceed = v - vbig;
8601
8602 assert(nexceed > 1);
8603
8604 /* determine weightsum of the same amount as before but of the smallest weight */
8605 for( w = nvars - 1; w >= nvars - nexceed; --w )
8606 exceedsumback += weights[w];
8607
8608 assert(w >= 0);
8609
8610 /* if the same amount but with the smallest possible weights also exceed the capacity, it holds for all
8611 * combinations of all small weights
8612 */
8613 if( exceedsumback > capacity )
8614 {
8615 SCIP_Longint newweight = nexceed - 1;
8616
8617 /* taking out the smallest element needs to fit */
8618 assert(exceedsumback - weights[nvars - 1] <= capacity);
8619
8620 /* reduce big weights */
8621 for( v = 0; v < vbig; ++v )
8622 {
8623 if( weights[v] > newweight )
8624 {
8625 consdataChgWeight(consdata, v, newweight);
8626 ++(*nchgcoefs);
8627 }
8628 }
8629
8630 /* reduce small weights */
8631 for( ; v < nvars; ++v )
8632 {
8633 if( weights[v] > 1 )
8634 {
8635 consdataChgWeight(consdata, v, 1LL);
8636 ++(*nchgcoefs);
8637 }
8638 }
8639
8640 consdata->capacity = newweight;
8641
8642 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8643 * weight must not be sorted by their index
8644 */
8645#ifndef NDEBUG
8646 for( v = nvars - 1; v > 0; --v )
8647 assert(weights[v] <= weights[v-1]);
8648#endif
8649 return SCIP_OKAY;
8650 }
8651 }
8652 }
8653 else
8654 {
8655 /* if the following assert fails we have either a redundant constraint or a set-packing constraint, this should
8656 * not happen here
8657 */
8658 assert(vbig > 0 && vbig < nvars);
8659
8660 /* either choose a big coefficients or all other variables
8661 *
8662 * 973x1 + 189x2 + 189x3 + 145x4 + 110x5 + 104x6 + 93x7 + 71x8 + 68x9 + 10x10 <= 979
8663 *
8664 * either choose x1, or all other variables (weightsum of x2 to x10 is 979 above), so we can tighten this
8665 * constraint to
8666 *
8667 * 9x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 <= 9
8668 */
8669
8670 if( weights[vbig - 1] > (SCIP_Longint)nvars - vbig || weights[vbig] > 1 )
8671 {
8672 SCIP_Longint newweight = (SCIP_Longint)nvars - vbig;
8673#ifndef NDEBUG
8674 SCIP_Longint resweightsum = consdata->weightsum;
8675
8676 for( v = 0; v < vbig; ++v )
8677 resweightsum -= weights[v];
8678
8680#endif
8681 assert(newweight > 0);
8682
8683 /* reduce big weights */
8684 for( v = 0; v < vbig; ++v )
8685 {
8686 if( weights[v] > newweight )
8687 {
8688 consdataChgWeight(consdata, v, newweight);
8689 ++(*nchgcoefs);
8690 }
8691 }
8692
8693 /* reduce small weights */
8694 for( ; v < nvars; ++v )
8695 {
8696 if( weights[v] > 1 )
8697 {
8698 consdataChgWeight(consdata, v, 1LL);
8699 ++(*nchgcoefs);
8700 }
8701 }
8702
8703 consdata->capacity = newweight;
8704
8705 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8706 * weight must not be sorted by their index
8707 */
8708#ifndef NDEBUG
8709 for( v = nvars - 1; v > 0; --v )
8710 assert(weights[v] <= weights[v-1]);
8711#endif
8712 return SCIP_OKAY;
8713 }
8714 }
8715
8716 /* case 3. */
8717
8718 dualcapacity = consdata->weightsum - capacity;
8719 reductionsum = 0;
8720 v = 0;
8721
8722 /* reduce big weights
8723 *
8724 * e.g. 11x0 + 11x1 + 10x2 + 10x3 <= 32 <=> 11~x0 + 11~x1 + 10~x2 + 10~x3 >= 10
8725 * <=> 10~x0 + 10~x1 + 10~x2 + 10~x3 >= 10
8726 * <=> x0 + x1 + x2 + x3 <= 3
8727 */
8728 while( weights[v] > dualcapacity )
8729 {
8730 reductionsum += (weights[v] - dualcapacity);
8731 consdataChgWeight(consdata, v, dualcapacity);
8732 ++v;
8733 assert(v < nvars);
8734 }
8735 (*nchgcoefs) += v;
8736
8737 /* skip weights equal to the dualcapacity, because we cannot change them */
8738 while( v < nvars && weights[v] == dualcapacity )
8739 ++v;
8740
8741 /* any negated variable out of the first n - 1 items is enough to fulfill the constraint, so we can update it to a logicor
8742 * after a possible removal of the last, redundant item
8743 *
8744 * e.g. 10x1 + 10x2 + 10x3 <= 20 <=> 10~x1 + 10~x2 + 10~x3 >= 10 <=> ~x1 + ~x2 + ~x3 >= 1
8745 */
8746 if( v >= nvars - 1 )
8747 {
8748 /* the last weight is not enough to satisfy the dual capacity -> remove this redundant item */
8749 if( v == nvars - 1 )
8750 {
8751 SCIP_CALL( delCoefPos(scip, cons, nvars - 1) );
8752 }
8753 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8755
8756 return SCIP_OKAY;
8757 }
8758 else /* v < nvars - 1 <=> at least two items with weight smaller than the dual capacity */
8759 {
8760 /* @todo generalize the following algorithm for more than two variables */
8761
8762 if( weights[nvars - 1] + weights[nvars - 2] >= dualcapacity )
8763 {
8764 /* we have a dual-knapsack constraint where we either need to choose one variable out of a subset (big
8765 * coefficients) of all or two variables of the rest
8766 *
8767 * e.g. 9x1 + 9x2 + 6x3 + 4x4 <= 19 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 >= 9
8768 * <=> 2~x1 + 2~x2 + ~x3 + ~x4 >= 2
8769 * <=> 2x1 + 2x2 + x3 + x4 <= 4
8770 *
8771 * 3x1 + 3x2 + 2x3 + 2x4 + 2x5 + 2x6 + x7 <= 12 <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + 2~x5 + 2~x6 + ~x7 >= 3
8772 * <=> 2~x1 + 2~x2 + ~x3 + ~x4 + ~x5 + ~x6 + ~x7 >= 2
8773 * <=> 2 x1 + 2 x2 + x3 + x4 + x5 + x6 + x7 <= 7
8774 *
8775 */
8776 if( v > 0 && weights[nvars - 2] > 1 )
8777 {
8778 int ncoefchg = 0;
8779
8780 /* reduce all bigger weights */
8781 for( w = 0; w < v; ++w )
8782 {
8783 if( weights[w] > 2 )
8784 {
8785 consdataChgWeight(consdata, w, 2LL);
8786 ++ncoefchg;
8787 }
8788 else
8789 {
8790 assert(weights[0] == 2);
8791 assert(weights[v - 1] == 2);
8792 break;
8793 }
8794 }
8795
8796 /* reduce all smaller weights */
8797 for( w = v; w < nvars; ++w )
8798 {
8799 if( weights[w] > 1 )
8800 {
8801 consdataChgWeight(consdata, w, 1LL);
8802 ++ncoefchg;
8803 }
8804 }
8805 assert(ncoefchg > 0);
8806
8807 (*nchgcoefs) += ncoefchg;
8808
8809 /* correct the capacity */
8810 consdata->capacity = (-2 + v * 2 + nvars - v); /*lint !e647*/
8811 assert(consdata->capacity > 0);
8812 assert(weights[0] <= consdata->capacity);
8813 assert(consdata->weightsum > consdata->capacity);
8814 /* reset the reductionsum */
8815 reductionsum = 0;
8816 }
8817 else if( v == 0 )
8818 {
8819 assert(weights[nvars - 2] == 1);
8820 }
8821 }
8822 else
8823 {
8824 SCIP_Longint minweight = weights[nvars - 1];
8825 SCIP_Longint newweight = dualcapacity - minweight;
8826 SCIP_Longint restsumweights = 0;
8827 SCIP_Longint sumcoef;
8828 SCIP_Bool sumcoefcase = FALSE;
8829 int startv = v;
8830 int end;
8831 int k;
8832
8833 assert(weights[nvars - 1] + weights[nvars - 2] <= capacity);
8834
8835 /* reduce big weights of pairs that exceed the dualcapacity
8836 *
8837 * e.g. 9x1 + 9x2 + 6x3 + 4x4 + 4x5 + 4x6 <= 27 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8838 * <=> 9~x1 + 9~x2 + 5~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8839 * <=> 9x1 + 9x2 + 5x3 + 4x4 + 4x5 + 4x6 <= 27
8840 */
8841 while( weights[v] > newweight )
8842 {
8843 reductionsum += (weights[v] - newweight);
8844 consdataChgWeight(consdata, v, newweight);
8845 ++v;
8846 assert(v < nvars);
8847 }
8848 (*nchgcoefs) += (v - startv);
8849
8850 /* skip equal weights */
8851 while( weights[v] == newweight )
8852 ++v;
8853
8854 if( v > 0 )
8855 {
8856 for( w = v; w < nvars; ++w )
8857 restsumweights += weights[w];
8858 }
8859 else
8860 restsumweights = consdata->weightsum;
8861
8863 {
8864 /* we found redundant variables, which does not influence the feasibility of any integral solution, e.g.
8865 *
8866 * +61x1 + 61x2 + 61x3 + 61x4 + 61x5 + 61x6 + 35x7 + 10x8 <= 350 <=>
8867 * +61~x1 + 61~x2 + 61~x3 + 61~x4 + 61~x5 + 61~x6 + 35~x7 + 10~x8 >= 61
8868 */
8869 if( startv == v )
8870 {
8871 /* remove redundant variables */
8872 for( w = nvars - 1; w >= v; --w )
8873 {
8874 SCIP_CALL( delCoefPos(scip, cons, v) );
8875 ++(*nchgcoefs);
8876 }
8877
8878#ifndef NDEBUG
8879 /* each coefficients should exceed the dualcapacity by itself */
8880 for( ; w >= 0; --w )
8881 assert(weights[w] == dualcapacity);
8882#endif
8883 /* for performance reasons we do not update the capacity(, i.e. reduce it by reductionsum) and directly
8884 * upgrade this constraint
8885 */
8886 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8888
8889 return SCIP_OKAY;
8890 }
8891
8892 /* special case where we have three different coefficient types
8893 *
8894 * e.g. 9x1 + 9x2 + 6x3 + 6x4 + 4x5 + 4x6 <= 29 <=> 9~x1 + 9~x2 + 6~x3 + 6~x4 + 4~x5 + 4~x6 >= 9
8895 * <=> 9~x1 + 9~x2 + 5~x3 + 5~x4 + 4~x5 + 4~x6 >= 9
8896 * <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + ~x5 + ~x6 >= 3
8897 * <=> 3x1 + 3x2 + 2x3 + 2x4 + x5 + x6 <= 9
8898 */
8899 if( weights[v] > 1 || (weights[startv] > (SCIP_Longint)nvars - v) || (startv > 0 && weights[0] == (SCIP_Longint)nvars - v + 1) )
8900 {
8901 SCIP_Longint newcap;
8902
8903 /* adjust smallest coefficients, which all together do not exceed the dualcapacity */
8904 for( w = nvars - 1; w >= v; --w )
8905 {
8906 if( weights[w] > 1 )
8907 {
8908 consdataChgWeight(consdata, w, 1LL);
8909 ++(*nchgcoefs);
8910 }
8911 }
8912
8913 /* adjust middle sized coefficients, which when choosing also one small coefficients exceed the
8914 * dualcapacity
8915 */
8917 assert(newweight > 1);
8918 for( ; w >= startv; --w )
8919 {
8920 if( weights[w] > newweight )
8921 {
8922 consdataChgWeight(consdata, w, newweight);
8923 ++(*nchgcoefs);
8924 }
8925 else
8926 assert(weights[w] == newweight);
8927 }
8928
8929 /* adjust big sized coefficients, where each of them exceeds the dualcapacity by itself */
8930 ++newweight;
8931 assert(newweight > 2);
8932 for( ; w >= 0; --w )
8933 {
8934 if( weights[w] > newweight )
8935 {
8936 consdataChgWeight(consdata, w, newweight);
8937 ++(*nchgcoefs);
8938 }
8939 else
8940 assert(weights[w] == newweight);
8941 }
8942
8943 /* update the capacity */
8944 newcap = ((SCIP_Longint)startv - 1) * newweight + ((SCIP_Longint)v - startv) * (newweight - 1) + ((SCIP_Longint)nvars - v);
8945 if( consdata->capacity > newcap )
8946 {
8947 consdata->capacity = newcap;
8948 ++(*nchgsides);
8949 }
8950 else
8951 assert(consdata->capacity == newcap);
8952 }
8953 assert(weights[v] == 1 && (weights[startv] == (SCIP_Longint)nvars - v) && (startv == 0 || weights[0] == (SCIP_Longint)nvars - v + 1));
8954
8955 /* the new dualcapacity should still be equal to the (nvars - v + 1) */
8956 assert(consdata->weightsum - consdata->capacity == (SCIP_Longint)nvars - v + 1);
8957
8958 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8959 * weight must not be sorted by their index
8960 */
8961#ifndef NDEBUG
8962 for( w = nvars - 1; w > 0; --w )
8963 assert(weights[w] <= weights[w - 1]);
8964#endif
8965 return SCIP_OKAY;
8966 }
8967
8968 /* check if all rear items have the same weight as the last one, so we cannot tighten the constraint further */
8969 end = nvars - 2;
8970 while( end >= 0 && weights[end] == weights[end + 1] )
8971 {
8972 assert(end >= v);
8973 --end;
8974 }
8975
8976 if( v >= end )
8977 goto TERMINATE;
8978
8979 end = nvars - 2;
8980
8981 /* can we stop early, another special reduction case might exist */
8982 if( 2 * weights[end] > dualcapacity )
8983 {
8984 restsumweights = 0;
8985
8986 /* determine capacity of the small items */
8987 for( w = end + 1; w < nvars; ++w )
8988 restsumweights += weights[w];
8989
8990 if( restsumweights * 2 <= dualcapacity )
8991 {
8992 /* check for further posssible reductions in the middle */
8993 while( v < end && restsumweights + weights[v] >= dualcapacity )
8994 ++v;
8995
8996 if( v >= end )
8997 goto TERMINATE;
8998
8999 /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
9000 if( (dualcapacity & 1) == 0 )
9001 {
9002 newweight = dualcapacity / 2;
9003
9004 /* set all middle coefficients */
9005 for( ; v <= end; ++v )
9006 {
9007 if( weights[v] > newweight )
9008 {
9009 reductionsum += (weights[v] - newweight);
9010 consdataChgWeight(consdata, v, newweight);
9011 ++(*nchgcoefs);
9012 }
9013 }
9014 }
9015 /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
9016 * other coefficients by 2
9017 */
9018 else
9019 {
9020 /* correct the reductionsum */
9021 reductionsum *= 2;
9022
9023 /* multiply big coefficients by 2 */
9024 for( w = 0; w < v; ++w )
9025 {
9026 consdataChgWeight(consdata, w, weights[w] * 2);
9027 }
9028
9030 /* set all middle coefficients */
9031 for( ; v <= end; ++v )
9032 {
9033 reductionsum += (2 * weights[v] - newweight);
9034 consdataChgWeight(consdata, v, newweight);
9035 }
9036
9037 /* multiply small coefficients by 2 */
9038 for( w = end + 1; w < nvars; ++w )
9039 {
9040 consdataChgWeight(consdata, w, weights[w] * 2);
9041 }
9042 (*nchgcoefs) += nvars;
9043
9044 dualcapacity *= 2;
9045 consdata->capacity *= 2;
9046 ++(*nchgsides);
9047 }
9048 }
9049
9050 goto TERMINATE;
9051 }
9052
9053 /* further reductions using the next possible coefficient sum
9054 *
9055 * e.g. 9x1 + 8x2 + 7x3 + 3x4 + x5 <= 19 <=> 9~x1 + 8~x2 + 7~x3 + 3~x4 + ~x5 >= 9
9056 * <=> 9~x1 + 8~x2 + 6~x3 + 3~x4 + ~x5 >= 9
9057 * <=> 9x1 + 8x2 + 6x3 + 3x4 + x5 <= 18
9058 */
9059 /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
9060 for( k = 0; k < 4; ++k )
9061 {
9062 /* determine next minimal coefficient sum */
9063 switch( k )
9064 {
9065 case 0:
9066 sumcoef = weights[nvars - 1] + weights[nvars - 2];
9067 break;
9068 case 1:
9069 assert(nvars >= 3);
9070 sumcoef = weights[nvars - 1] + weights[nvars - 3];
9071 break;
9072 case 2:
9073 assert(nvars >= 4);
9074 if( weights[nvars - 1] + weights[nvars - 4] < weights[nvars - 2] + weights[nvars - 3] )
9075 {
9076 sumcoefcase = TRUE;
9077 sumcoef = weights[nvars - 1] + weights[nvars - 4];
9078 }
9079 else
9080 {
9082 sumcoef = weights[nvars - 2] + weights[nvars - 3];
9083 }
9084 break;
9085 case 3:
9086 assert(nvars >= 5);
9087 if( sumcoefcase )
9088 {
9089 sumcoef = MIN(weights[nvars - 1] + weights[nvars - 5], weights[nvars - 2] + weights[nvars - 3]);
9090 }
9091 else
9092 {
9093 sumcoef = MIN(weights[nvars - 1] + weights[nvars - 4], weights[nvars - 1] + weights[nvars - 2] + weights[nvars - 3]);
9094 }
9095 break;
9096 default:
9097 return SCIP_ERROR;
9098 }
9099
9100 /* tighten next coefficients that, pair with the current small coefficient, exceed the dualcapacity */
9101 minweight = weights[end];
9102 while( minweight <= sumcoef )
9103 {
9104 newweight = dualcapacity - minweight;
9105 startv = v;
9106 assert(v < nvars);
9107
9108 /* @todo check for further reductions, when two times the minweight exceeds the dualcapacity */
9109 /* shrink big coefficients */
9110 while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9111 {
9112 reductionsum += (weights[v] - newweight);
9113 consdataChgWeight(consdata, v, newweight);
9114 ++v;
9115 assert(v < nvars);
9116 }
9117 (*nchgcoefs) += (v - startv);
9118
9119 /* skip unchangable weights */
9120 while( weights[v] + minweight == dualcapacity )
9121 {
9122 assert(v < nvars);
9123 ++v;
9124 }
9125
9126 --end;
9127 /* skip same end weights */
9128 while( end >= 0 && weights[end] == weights[end + 1] )
9129 --end;
9130
9131 if( v >= end )
9132 goto TERMINATE;
9133
9134 minweight = weights[end];
9135 }
9136
9137 if( v >= end )
9138 goto TERMINATE;
9139
9140 /* now check if a combination of small coefficients allows us to tighten big coefficients further */
9141 if( sumcoef < minweight )
9142 {
9143 minweight = sumcoef;
9144 newweight = dualcapacity - minweight;
9145 startv = v;
9146 assert(v < nvars);
9147
9148 /* shrink big coefficients */
9149 while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9150 {
9151 reductionsum += (weights[v] - newweight);
9152 consdataChgWeight(consdata, v, newweight);
9153 ++v;
9154 assert(v < nvars);
9155 }
9156 (*nchgcoefs) += (v - startv);
9157
9158 /* skip unchangable weights */
9159 while( weights[v] + minweight == dualcapacity )
9160 {
9161 assert(v < nvars);
9162 ++v;
9163 }
9164 }
9165
9166 if( v >= end )
9167 goto TERMINATE;
9168
9169 /* can we stop early, another special reduction case might exist */
9170 if( 2 * weights[end] > dualcapacity )
9171 {
9172 restsumweights = 0;
9173
9174 /* determine capacity of the small items */
9175 for( w = end + 1; w < nvars; ++w )
9176 restsumweights += weights[w];
9177
9178 if( restsumweights * 2 <= dualcapacity )
9179 {
9180 /* check for further posssible reductions in the middle */
9181 while( v < end && restsumweights + weights[v] >= dualcapacity )
9182 ++v;
9183
9184 if( v >= end )
9185 goto TERMINATE;
9186
9187 /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
9188 if( (dualcapacity & 1) == 0 )
9189 {
9190 newweight = dualcapacity / 2;
9191
9192 /* set all middle coefficients */
9193 for( ; v <= end; ++v )
9194 {
9195 if( weights[v] > newweight )
9196 {
9197 reductionsum += (weights[v] - newweight);
9198 consdataChgWeight(consdata, v, newweight);
9199 ++(*nchgcoefs);
9200 }
9201 }
9202 }
9203 /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
9204 * other coefficients by 2
9205 */
9206 else
9207 {
9208 /* correct the reductionsum */
9209 reductionsum *= 2;
9210
9211 /* multiply big coefficients by 2 */
9212 for( w = 0; w < v; ++w )
9213 {
9214 consdataChgWeight(consdata, w, weights[w] * 2);
9215 }
9216
9218 /* set all middle coefficients */
9219 for( ; v <= end; ++v )
9220 {
9221 reductionsum += (2 * weights[v] - newweight);
9222 consdataChgWeight(consdata, v, newweight);
9223 }
9224
9225 /* multiply small coefficients by 2 */
9226 for( w = end + 1; w < nvars; ++w )
9227 {
9228 consdataChgWeight(consdata, w, weights[w] * 2);
9229 }
9230 (*nchgcoefs) += nvars;
9231
9232 dualcapacity *= 2;
9233 consdata->capacity *= 2;
9234 ++(*nchgsides);
9235 }
9236 }
9237
9238 goto TERMINATE;
9239 }
9240
9241 /* cannot tighten any further */
9242 if( 2 * sumcoef > dualcapacity )
9243 goto TERMINATE;
9244 }
9245 }
9246 }
9247
9248 TERMINATE:
9249 /* correct capacity */
9250 if( reductionsum > 0 )
9251 {
9252 assert(v > 0);
9253
9254 consdata->capacity -= reductionsum;
9255 ++(*nchgsides);
9256
9257 assert(consdata->weightsum - dualcapacity == consdata->capacity);
9258 }
9259 assert(weights[0] <= consdata->capacity);
9260
9261 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
9262 * weight must not be sorted by their index
9263 */
9264#ifndef NDEBUG
9265 for( w = nvars - 1; w > 0; --w )
9266 assert(weights[w] <= weights[w - 1]);
9267#endif
9268
9269 if( oldnchgcoefs < *nchgcoefs )
9270 {
9271 assert(!SCIPconsIsDeleted(cons));
9272
9273 /* it might be that we can divide the weights by their greatest common divisor */
9274 normalizeWeights(cons, nchgcoefs, nchgsides);
9275 }
9276 else
9277 {
9278 assert(oldnchgcoefs == *nchgcoefs);
9279 assert(oldnchgsides == *nchgsides);
9280 }
9281
9282 return SCIP_OKAY;
9283}
9284
9285
9286/** fixes variables with weights bigger than the capacity and delete redundant constraints, also sort weights */
9287static
9289 SCIP* scip, /**< SCIP data structure */
9290 SCIP_CONS* cons, /**< knapsack constraint */
9291 int* nfixedvars, /**< pointer to store the amount of fixed variables */
9292 int* ndelconss, /**< pointer to store the amount of deleted constraints */
9293 int* nchgcoefs /**< pointer to store the amount of changed coefficients */
9294 )
9295{
9296 SCIP_VAR** vars;
9297 SCIP_CONSDATA* consdata;
9298 SCIP_Longint* weights;
9299 SCIP_Longint capacity;
9300 SCIP_Bool infeasible;
9301 SCIP_Bool fixed;
9302 int nvars;
9303 int v;
9304
9305 assert(scip != NULL);
9306 assert(cons != NULL);
9307 assert(nfixedvars != NULL);
9308 assert(ndelconss != NULL);
9309 assert(nchgcoefs != NULL);
9310
9311 consdata = SCIPconsGetData(cons);
9312 assert(consdata != NULL);
9313
9314 nvars = consdata->nvars;
9315
9316 /* no variables left, then delete constraint */
9317 if( nvars == 0 )
9318 {
9319 assert(consdata->capacity >= 0);
9320
9321 SCIP_CALL( SCIPdelCons(scip, cons) );
9322 ++(*ndelconss);
9323
9324 return SCIP_OKAY;
9325 }
9326
9327 /* sort items */
9328 sortItems(consdata);
9329
9330 vars = consdata->vars;
9331 weights = consdata->weights;
9332 capacity = consdata->capacity;
9333 v = 0;
9334
9335 /* check for weights bigger than the capacity */
9336 while( v < nvars && weights[v] > capacity )
9337 {
9338 SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, &infeasible, &fixed) );
9339 assert(!infeasible);
9340
9341 if( fixed )
9342 ++(*nfixedvars);
9343
9344 ++v;
9345 }
9346
9347 /* if we fixed at least one variable we need to delete them from the constraint */
9348 if( v > 0 )
9349 {
9350 if( v == nvars )
9351 {
9352 SCIP_CALL( SCIPdelCons(scip, cons) );
9353 ++(*ndelconss);
9354
9355 return SCIP_OKAY;
9356 }
9357
9358 /* delete all position from back to front */
9359 for( --v; v >= 0; --v )
9360 {
9361 SCIP_CALL( delCoefPos(scip, cons, v) );
9362 ++(*nchgcoefs);
9363 }
9364
9365 /* sort items again because of deletion */
9366 sortItems(consdata);
9367 assert(vars == consdata->vars);
9368 assert(weights == consdata->weights);
9369 }
9370 assert(consdata->sorted);
9371 assert(weights[0] <= capacity);
9372
9373 if( !SCIPisHugeValue(scip, (SCIP_Real) capacity) && consdata->weightsum <= capacity )
9374 {
9375 SCIP_CALL( SCIPdelCons(scip, cons) );
9376 ++(*ndelconss);
9377 }
9378
9379 return SCIP_OKAY;
9380}
9381
9382
9383/** tries to simplify weights and delete redundant variables in knapsack a^Tx <= capacity
9384 *
9385 * 1. use the duality between a^Tx <= capacity <=> -a^T~x <= capacity - weightsum to tighten weights, e.g.
9386 *
9387 * 11x1 + 10x2 + 7x3 + 5x4 + 5x5 <= 25 <=> -10~x1 - 10~x2 - 7~x3 - 5~x4 - 5~x5 <= -13
9388 *
9389 * the above constraint can be changed to
9390 *
9391 * -8~x1 - 8~x2 - 7~x3 - 5~x4 - 5~x5 <= -12 <=> 8x1 + 8x2 + 7x3 + 5x4 + 5x5 <= 20
9392 *
9393 * 2. if variables in a constraint do not affect the (in-)feasibility of the constraint, we can delete them, e.g.
9394 *
9395 * 7x1 + 6x2 + 5x3 + 5x4 + x5 + x6 <= 20 => x5 and x6 are redundant and can be removed
9396 *
9397 * 3. Tries to use gcd information an all but one weight to change this not-included weight and normalize the
9398 * constraint further, e.g.
9399 *
9400 * 9x1 + 6x2 + 6x3 + 5x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => 3x1 + 2x2 + 2x3 + 2x4 <= 4 => 4x1 + 2x2 + 2x3 + 2x4 <= 4
9401 * => 2x1 + x2 + x3 + x4 <= 2
9402 * 9x1 + 6x2 + 6x3 + 7x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => see above
9403 */
9404static
9406 SCIP* scip, /**< SCIP data structure */
9407 SCIP_CONS* cons, /**< knapsack constraint */
9408 int* nfixedvars, /**< pointer to store the amount of fixed variables */
9409 int* ndelconss, /**< pointer to store the amount of deleted constraints */
9410 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
9411 int* nchgsides, /**< pointer to store the amount of changed sides */
9412 int* naddconss, /**< pointer to count number of added constraints */
9413 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9414 )
9415{
9416 SCIP_VAR** vars;
9417 SCIP_CONSDATA* consdata;
9418 SCIP_Longint* weights;
9419 SCIP_Longint restweight;
9420 SCIP_Longint newweight;
9421 SCIP_Longint weight;
9422 SCIP_Longint oldgcd;
9423 SCIP_Longint rest;
9424 SCIP_Longint gcd;
9425 int oldnchgcoefs;
9426 int oldnchgsides;
9427 int candpos;
9428 int candpos2;
9429 int offsetv;
9430 int nvars;
9431 int v;
9432
9433 assert(scip != NULL);
9434 assert(cons != NULL);
9435 assert(nfixedvars != NULL);
9436 assert(ndelconss != NULL);
9437 assert(nchgcoefs != NULL);
9438 assert(nchgsides != NULL);
9439 assert(naddconss != NULL);
9440 assert(cutoff != NULL);
9442
9443 consdata = SCIPconsGetData(cons);
9444 assert( consdata != NULL );
9445
9446 *cutoff = FALSE;
9447
9448 /* remove double enties and also combinations of active and negated variables */
9450 assert(consdata->merged);
9451 if( *cutoff )
9452 return SCIP_OKAY;
9453
9454 assert(consdata->capacity >= 0);
9455
9456 /* fix variables with big coefficients and remove redundant constraints, sort weights */
9457 SCIP_CALL( prepareCons(scip, cons, nfixedvars, ndelconss, nchgcoefs) );
9458
9459 if( SCIPconsIsDeleted(cons) )
9460 return SCIP_OKAY;
9461
9462 if( !SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
9463 {
9464 /* 1. dual weights tightening */
9465 SCIP_CALL( dualWeightsTightening(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9466
9467 if( SCIPconsIsDeleted(cons) )
9468 return SCIP_OKAY;
9469 /* 2. delete redundant variables */
9470 SCIP_CALL( detectRedundantVars(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9471
9472 if( SCIPconsIsDeleted(cons) )
9473 return SCIP_OKAY;
9474 }
9475
9476 weights = consdata->weights;
9477 nvars = consdata->nvars;
9478
9479#ifndef NDEBUG
9480 /* constraint might not be sorted, but the weights are already sorted */
9481 for( v = nvars - 1; v > 0; --v )
9482 assert(weights[v] <= weights[v-1]);
9483#endif
9484
9485 /* determine greatest common divisor */
9486 gcd = weights[nvars - 1];
9487 for( v = nvars - 2; v >= 0 && gcd > 1; --v )
9488 {
9489 gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9490 }
9491
9492 /* divide the constraint by their greatest common divisor */
9493 if( gcd >= 2 )
9494 {
9495 for( v = nvars - 1; v >= 0; --v )
9496 {
9497 consdataChgWeight(consdata, v, weights[v]/gcd);
9498 }
9499 (*nchgcoefs) += nvars;
9500
9501 consdata->capacity /= gcd;
9502 (*nchgsides)++;
9503 }
9504 assert(consdata->nvars == nvars);
9505
9506 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal weight
9507 * must not be sorted by their index
9508 */
9509#ifndef NDEBUG
9510 for( v = nvars - 1; v > 0; --v )
9511 assert(weights[v] <= weights[v-1]);
9512#endif
9513
9514 /* 3. start gcd procedure for all variables */
9515 do
9516 {
9517 SCIPdebug( oldnchgcoefs = *nchgcoefs; )
9518 SCIPdebug( oldnchgsides = *nchgsides; )
9519
9520 vars = consdata->vars;
9521 weights = consdata->weights;
9522 nvars = consdata->nvars;
9523
9524 /* stop if we have two coefficients which are one in absolute value */
9525 if( weights[nvars - 1] == 1 && weights[nvars - 2] == 1 )
9526 return SCIP_OKAY;
9527
9528 v = 0;
9529 /* determine coefficients as big as the capacity, these we do not need to take into account when calculating the
9530 * gcd
9531 */
9532 while( weights[v] == consdata->capacity )
9533 {
9534 ++v;
9535 assert(v < nvars);
9536 }
9537
9538 /* all but one variable are as big as the capacity, this is handled elsewhere */
9539 if( v == nvars - 1 )
9540 return SCIP_OKAY;
9541
9542 offsetv = v;
9543
9544 gcd = -1;
9545 candpos = -1;
9546 candpos2 = -1;
9547
9548 /* calculate greatest common divisor over all integer and binary variables and determine the candidate where we might
9549 * change the coefficient
9550 */
9551 for( v = nvars - 1; v >= offsetv; --v )
9552 {
9553 weight = weights[v];
9554 assert(weight >= 1);
9555
9556 oldgcd = gcd;
9557
9558 if( gcd == -1 )
9559 {
9560 gcd = weights[v];
9561 assert(gcd >= 1);
9562 }
9563 else
9564 {
9565 /* calculate greatest common divisor for all variables */
9566 gcd = SCIPcalcGreComDiv(gcd, weight);
9567 }
9568
9569 /* if the greatest commmon divisor has become 1, we might have found the possible coefficient to change or we
9570 * can terminate
9571 */
9572 if( gcd == 1 )
9573 {
9574 /* found candidate */
9575 if( candpos == -1 )
9576 {
9577 gcd = oldgcd;
9578 candpos = v;
9579
9580 /* if both first coefficients have a gcd of 1, both are candidates for the coefficient change */
9581 if( v == nvars - 2 )
9582 candpos2 = v + 1;
9583 }
9584 /* two different variables lead to a gcd of one, so we cannot change a coefficient */
9585 else
9586 {
9587 if( candpos == v + 1 && candpos2 == v + 2 )
9588 {
9589 assert(candpos2 == nvars - 1);
9590
9591 /* take new candidates */
9592 candpos = candpos2;
9593
9594 /* recalculate gcd from scratch */
9595 gcd = weights[v+1];
9596 assert(gcd >= 1);
9597
9598 /* calculate greatest common divisor for variables */
9599 gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9600 if( gcd == 1 )
9601 return SCIP_OKAY;
9602 }
9603 else
9604 /* cannot determine a possible coefficient for reduction */
9605 return SCIP_OKAY;
9606 }
9607 }
9608 }
9609 assert(gcd >= 2);
9610
9611 /* we should have found one coefficient, that led to a gcd of 1, otherwise we could normalize the constraint
9612 * further
9613 */
9614 assert(((candpos >= offsetv) || (candpos == -1 && offsetv > 0)) && candpos < nvars);
9615
9616 /* determine the remainder of the capacity and the gcd */
9617 rest = consdata->capacity % gcd;
9618 assert(rest >= 0);
9619 assert(rest < gcd);
9620
9621 if( candpos == -1 )
9622 {
9623 /* we assume that the constraint was normalized */
9624 assert(rest > 0);
9625
9626 /* replace old with new capacity */
9627 consdata->capacity -= rest;
9628 ++(*nchgsides);
9629
9630 /* replace old big coefficients with new capacity */
9631 for( v = 0; v < offsetv; ++v )
9632 {
9633 consdataChgWeight(consdata, v, consdata->capacity);
9634 }
9635
9636 *nchgcoefs += offsetv;
9637 goto CONTINUE;
9638 }
9639
9640 /* determine the remainder of the coefficient candidate and the gcd */
9641 restweight = weights[candpos] % gcd;
9642 assert(restweight >= 1);
9644
9645 /* calculate new coefficient */
9646 if( restweight > rest )
9647 newweight = weights[candpos] - restweight + gcd;
9648 else
9649 newweight = weights[candpos] - restweight;
9650
9652
9653 SCIPdebugMsg(scip, "gcd = %" SCIP_LONGINT_FORMAT ", rest = %" SCIP_LONGINT_FORMAT ", restweight = %" SCIP_LONGINT_FORMAT "; possible new weight of variable <%s> %" SCIP_LONGINT_FORMAT ", possible new capacity %" SCIP_LONGINT_FORMAT ", offset of coefficients as big as capacity %d\n", gcd, rest, restweight, SCIPvarGetName(vars[candpos]), newweight, consdata->capacity - rest, offsetv);
9654
9655 /* must not change weights and capacity if one variable would be removed and we have a big coefficient,
9656 * e.g., 11x1 + 6x2 + 6x3 + 5x4 <= 11 => gcd = 6, offsetv = 1 => newweight = 0, but we would lose x1 = 1 => x4 = 0
9657 */
9658 if( newweight == 0 && offsetv > 0 )
9659 return SCIP_OKAY;
9660
9661 if( rest > 0 )
9662 {
9663 /* replace old with new capacity */
9664 consdata->capacity -= rest;
9665 ++(*nchgsides);
9666
9667 /* replace old big coefficients with new capacity */
9668 for( v = 0; v < offsetv; ++v )
9669 {
9670 consdataChgWeight(consdata, v, consdata->capacity);
9671 }
9672
9673 *nchgcoefs += offsetv;
9674 }
9675
9676 if( newweight == 0 )
9677 {
9678 /* delete redundant coefficient */
9679 SCIP_CALL( delCoefPos(scip, cons, candpos) );
9680 assert(consdata->nvars == nvars - 1);
9681 --nvars;
9682 }
9683 else
9684 {
9685 /* replace old with new coefficient */
9687 }
9688 ++(*nchgcoefs);
9689
9690 assert(consdata->vars == vars);
9691 assert(consdata->nvars == nvars);
9692 assert(consdata->weights == weights);
9693
9694 CONTINUE:
9695 /* now constraint can be normalized, dividing it by the gcd */
9696 for( v = nvars - 1; v >= 0; --v )
9697 {
9698 consdataChgWeight(consdata, v, weights[v]/gcd);
9699 }
9700 (*nchgcoefs) += nvars;
9701
9702 consdata->capacity /= gcd;
9703 ++(*nchgsides);
9704
9706
9707 SCIPdebugMsg(scip, "we did %d coefficient changes and %d side changes on constraint %s when applying one round of the gcd algorithm\n", *nchgcoefs - oldnchgcoefs, *nchgsides - oldnchgsides, SCIPconsGetName(cons));
9708 }
9709 while( nvars >= 2 );
9710
9711 return SCIP_OKAY;
9712}
9713
9714
9715/** inserts an element into the list of binary zero implications */
9716static
9718 SCIP* scip, /**< SCIP data structure */
9719 int** liftcands, /**< array of the lifting candidates */
9720 int* nliftcands, /**< number of lifting candidates */
9721 int** firstidxs, /**< array of first zeroitems indices */
9722 SCIP_Longint** zeroweightsums, /**< array of sums of weights of the implied-to-zero items */
9723 int** zeroitems, /**< pointer to zero items array */
9724 int** nextidxs, /**< pointer to array of next zeroitems indeces */
9725 int* zeroitemssize, /**< pointer to size of zero items array */
9726 int* nzeroitems, /**< pointer to length of zero items array */
9727 int probindex, /**< problem index of variable y in implication y == v -> x == 0 */
9728 SCIP_Bool value, /**< value v of variable y in implication */
9729 int knapsackidx, /**< index of variable x in knapsack */
9730 SCIP_Longint knapsackweight, /**< weight of variable x in knapsack */
9731 SCIP_Bool* memlimitreached /**< pointer to store whether the memory limit was reached */
9732 )
9733{
9734 int nzeros;
9735
9736 assert(liftcands != NULL);
9737 assert(liftcands[value] != NULL);
9739 assert(firstidxs != NULL);
9740 assert(firstidxs[value] != NULL);
9742 assert(zeroweightsums[value] != NULL);
9743 assert(zeroitems != NULL);
9744 assert(nextidxs != NULL);
9748 assert(0 <= probindex && probindex < SCIPgetNVars(scip) - SCIPgetNContVars(scip));
9750
9751 nzeros = *nzeroitems;
9752
9753 /* allocate enough memory */
9754 if( nzeros == *zeroitemssize )
9755 {
9756 /* we explicitly construct the complete implication graph where the knapsack variables are involved;
9757 * this can be too huge - abort on memory limit
9758 */
9760 {
9761 SCIPdebugMsg(scip, "memory limit of %d bytes reached in knapsack preprocessing - abort collecting zero items\n",
9762 *zeroitemssize);
9764 return SCIP_OKAY;
9765 }
9766 *zeroitemssize *= 2;
9770 }
9772
9773 if( *memlimitreached )
9775
9776 /* insert element */
9777 (*zeroitems)[nzeros] = knapsackidx;
9778 (*nextidxs)[nzeros] = firstidxs[value][probindex];
9779 if( firstidxs[value][probindex] == 0 )
9780 {
9781 liftcands[value][nliftcands[value]] = probindex;
9782 ++nliftcands[value];
9783 }
9784 firstidxs[value][probindex] = nzeros;
9785 ++(*nzeroitems);
9786 zeroweightsums[value][probindex] += knapsackweight;
9787
9788 return SCIP_OKAY;
9789}
9790
9791#define MAX_CLIQUELENGTH 50
9792/** applies rule (3) of the weight tightening procedure, which can lift other variables into the knapsack:
9793 * (3) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
9794 * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
9795 * if cliqueweightsum(xi == v) < capacity:
9796 * - fixing variable xi to v would make the knapsack constraint redundant
9797 * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
9798 * redundancy effect:
9799 * wi' := capacity - cliqueweightsum(xi == v)
9800 * this rule can also be applied to binary variables not in the knapsack!
9801 */
9802static
9804 SCIP* scip, /**< SCIP data structure */
9805 SCIP_CONS* cons, /**< knapsack constraint */
9806 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9807 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9808 )
9809{
9810 SCIP_CONSDATA* consdata;
9811 SCIP_VAR** binvars;
9812 int nbinvars;
9813 int* liftcands[2]; /* binary variables that have at least one entry in zeroitems */
9814 int* firstidxs[2]; /* first index in zeroitems for each binary variable/value pair, or zero for empty list */
9815 SCIP_Longint* zeroweightsums[2]; /* sums of weights of the implied-to-zero items */
9816 int* zeroitems; /* item number in knapsack that is implied to zero */
9817 int* nextidxs; /* next index in zeroitems for the same binary variable, or zero for end of list */
9818 int zeroitemssize;
9819 int nzeroitems;
9820 SCIP_Bool* zeroiteminserted[2];
9821 SCIP_Bool memlimitreached;
9822 int nliftcands[2];
9823 SCIP_Bool* cliqueused;
9824 SCIP_Bool* itemremoved;
9825 SCIP_Longint maxcliqueweightsum;
9826 SCIP_VAR** addvars;
9827 SCIP_Longint* addweights;
9828 SCIP_Longint addweightsum;
9829 int nvars;
9830 int cliquenum;
9831 int naddvars;
9832 int val;
9833 int i;
9834
9835 int* tmpindices;
9836 SCIP_Bool* tmpboolindices;
9837 int* tmpindices2;
9838 SCIP_Bool* tmpboolindices2;
9839 int* tmpindices3;
9840 SCIP_Bool* tmpboolindices3;
9841 int tmp;
9842 int tmp2;
9843 int tmp3;
9844 SCIP_CONSHDLR* conshdlr;
9845 SCIP_CONSHDLRDATA* conshdlrdata;
9846
9847 assert(nchgcoefs != NULL);
9849
9850 consdata = SCIPconsGetData(cons);
9851 assert(consdata != NULL);
9852 assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
9853 assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
9854 assert(consdata->nvars > 0);
9855 assert(consdata->merged);
9856
9857 nvars = consdata->nvars;
9858
9859 /* check if the knapsack has too many items/cliques for applying this costly method */
9860 if( (!consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE) || consdata->ncliques > MAX_USECLIQUES_SIZE )
9861 return SCIP_OKAY;
9862
9863 /* sort items, s.t. the heaviest one is in the first position */
9864 sortItems(consdata);
9865
9866 if( !consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE )
9867 return SCIP_OKAY;
9868
9869 /* we have to consider all integral variables since even integer and implicit integer variables can have binary bounds */
9871 assert(nbinvars > 0);
9872 binvars = SCIPgetVars(scip);
9873
9874 /* get conshdlrdata to use cleared memory */
9875 conshdlr = SCIPconsGetHdlr(cons);
9876 assert(conshdlr != NULL);
9877 conshdlrdata = SCIPconshdlrGetData(conshdlr);
9878 assert(conshdlrdata != NULL);
9879
9880 /* allocate temporary memory for the list of implied to zero variables */
9881 zeroitemssize = MIN(nbinvars, MAX_ZEROITEMS_SIZE); /* initial size of zeroitems buffer */
9884
9885 assert(conshdlrdata->ints1size > 0);
9886 assert(conshdlrdata->ints2size > 0);
9887 assert(conshdlrdata->longints1size > 0);
9888 assert(conshdlrdata->longints2size > 0);
9889
9890 /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9891 * than binary + integer variables existed at the presolving initialization method, but for example if you would
9892 * transform all integers into their binary representation then it maybe happens
9893 */
9894 if( conshdlrdata->ints1size < nbinvars )
9895 {
9896 int oldsize = conshdlrdata->ints1size;
9897
9898 conshdlrdata->ints1size = nbinvars;
9899 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints1, oldsize, conshdlrdata->ints1size) );
9900 BMSclearMemoryArray(&(conshdlrdata->ints1[oldsize]), conshdlrdata->ints1size - oldsize); /*lint !e866*/
9901 }
9902 if( conshdlrdata->ints2size < nbinvars )
9903 {
9904 int oldsize = conshdlrdata->ints2size;
9905
9906 conshdlrdata->ints2size = nbinvars;
9907 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints2, oldsize, conshdlrdata->ints2size) );
9908 BMSclearMemoryArray(&(conshdlrdata->ints2[oldsize]), conshdlrdata->ints2size - oldsize); /*lint !e866*/
9909 }
9910 if( conshdlrdata->longints1size < nbinvars )
9911 {
9912 int oldsize = conshdlrdata->longints1size;
9913
9914 conshdlrdata->longints1size = nbinvars;
9915 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints1, oldsize, conshdlrdata->longints1size) );
9916 BMSclearMemoryArray(&(conshdlrdata->longints1[oldsize]), conshdlrdata->longints1size - oldsize); /*lint !e866*/
9917 }
9918 if( conshdlrdata->longints2size < nbinvars )
9919 {
9920 int oldsize = conshdlrdata->longints2size;
9921
9922 conshdlrdata->longints2size = nbinvars;
9923 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints2, oldsize, conshdlrdata->longints2size) );
9924 BMSclearMemoryArray(&(conshdlrdata->longints2[oldsize]), conshdlrdata->longints2size - oldsize); /*lint !e866*/
9925 }
9926
9927 firstidxs[0] = conshdlrdata->ints1;
9928 firstidxs[1] = conshdlrdata->ints2;
9929 zeroweightsums[0] = conshdlrdata->longints1;
9930 zeroweightsums[1] = conshdlrdata->longints2;
9931
9932 /* check for cleared arrays, all entries are zero */
9933#ifndef NDEBUG
9934 for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9935 {
9936 assert(firstidxs[0][tmp] == 0);
9937 assert(firstidxs[1][tmp] == 0);
9938 assert(zeroweightsums[0][tmp] == 0);
9939 assert(zeroweightsums[1][tmp] == 0);
9940 }
9941#endif
9942
9945
9946 zeroitems[0] = -1; /* dummy element */
9947 nextidxs[0] = -1;
9948 nzeroitems = 1;
9949 nliftcands[0] = 0;
9950 nliftcands[1] = 0;
9951
9952 assert(conshdlrdata->bools1size > 0);
9953 assert(conshdlrdata->bools2size > 0);
9954
9955 /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9956 * than binary + integer variables existed at the presolving initialization method, but for example if you would
9957 * transform all integers into their binary representation then it maybe happens
9958 */
9959 if( conshdlrdata->bools1size < nbinvars )
9960 {
9961 int oldsize = conshdlrdata->bools1size;
9962
9963 conshdlrdata->bools1size = nbinvars;
9964 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools1, oldsize, conshdlrdata->bools1size) );
9965 BMSclearMemoryArray(&(conshdlrdata->bools1[oldsize]), conshdlrdata->bools1size - oldsize); /*lint !e866*/
9966 }
9967 if( conshdlrdata->bools2size < nbinvars )
9968 {
9969 int oldsize = conshdlrdata->bools2size;
9970
9971 conshdlrdata->bools2size = nbinvars;
9972 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools2, oldsize, conshdlrdata->bools2size) );
9973 BMSclearMemoryArray(&(conshdlrdata->bools2[oldsize]), conshdlrdata->bools2size - oldsize); /*lint !e866*/
9974 }
9975
9976 zeroiteminserted[0] = conshdlrdata->bools1;
9977 zeroiteminserted[1] = conshdlrdata->bools2;
9978
9979 /* check for cleared arrays, all entries are zero */
9980#ifndef NDEBUG
9981 for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9982 {
9983 assert(zeroiteminserted[0][tmp] == 0);
9984 assert(zeroiteminserted[1][tmp] == 0);
9985 }
9986#endif
9987
9988 SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices3, consdata->nvars) );
9990 SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices3, consdata->nvars) );
9994
9995 tmp2 = 0;
9996 tmp3 = 0;
9997
9999 for( i = 0; i < consdata->nvars && !memlimitreached; ++i )
10000 {
10001 SCIP_CLIQUE** cliques;
10002 SCIP_VAR* var;
10003 SCIP_Longint weight;
10004 SCIP_Bool value;
10005 int varprobindex;
10006 int ncliques;
10007 int j;
10008
10009 tmp = 0;
10010
10011 /* get corresponding active problem variable */
10012 var = consdata->vars[i];
10013 weight = consdata->weights[i];
10014 value = TRUE;
10018
10019 /* update the zeroweightsum */
10020 zeroweightsums[!value][varprobindex] += weight; /*lint !e514*/
10021 tmpboolindices3[tmp3] = !value;
10023 ++tmp3;
10024
10025 /* initialize the arrays of inserted zero items */
10026 /* first add the implications (~x == 1 -> x == 0) */
10027 {
10028 SCIP_Bool implvalue;
10029 int probindex;
10030
10031 probindex = SCIPvarGetProbindex(var);
10032 assert(0 <= probindex && probindex < nbinvars);
10033
10034 implvalue = !value;
10035
10036 /* insert the item into the list of the implied variable/value */
10037 assert( !zeroiteminserted[implvalue][probindex] );
10038
10039 if( firstidxs[implvalue][probindex] == 0 )
10040 {
10042 tmpindices2[tmp2] = probindex;
10043 ++tmp2;
10044 }
10046 &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
10047 &memlimitreached) );
10048 zeroiteminserted[implvalue][probindex] = TRUE;
10050 tmpindices[tmp] = probindex;
10051 ++tmp;
10052 }
10053
10054 /* get the cliques where the knapsack item is member of with value 1 */
10055 ncliques = SCIPvarGetNCliques(var, value);
10056 cliques = SCIPvarGetCliques(var, value);
10057 for( j = 0; j < ncliques && !memlimitreached; ++j )
10058 {
10060 SCIP_Bool* cliquevalues;
10061 int ncliquevars;
10062 int k;
10063
10064 ncliquevars = SCIPcliqueGetNVars(cliques[j]);
10065
10066 /* discard big cliques */
10068 continue;
10069
10070 cliquevars = SCIPcliqueGetVars(cliques[j]);
10072
10073 for( k = ncliquevars - 1; k >= 0; --k )
10074 {
10075 SCIP_Bool implvalue;
10076 int probindex;
10077
10078 if( var == cliquevars[k] )
10079 continue;
10080
10081 probindex = SCIPvarGetProbindex(cliquevars[k]);
10082 if( probindex == -1 )
10083 continue;
10084
10085 assert(0 <= probindex && probindex < nbinvars);
10087
10088 /* insert the item into the list of the clique variable/value */
10089 if( !zeroiteminserted[implvalue][probindex] )
10090 {
10091 if( firstidxs[implvalue][probindex] == 0 )
10092 {
10094 tmpindices2[tmp2] = probindex;
10095 ++tmp2;
10096 }
10097
10099 &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
10100 &memlimitreached) );
10101 zeroiteminserted[implvalue][probindex] = TRUE;
10103 tmpindices[tmp] = probindex;
10104 ++tmp;
10105
10106 if( memlimitreached )
10107 break;
10108 }
10109 }
10110 }
10111 /* clear zeroiteminserted */
10112 for( --tmp; tmp >= 0; --tmp)
10114 }
10116
10117 /* calculate the clique partition and the maximal sum of weights using the clique information */
10118 assert(consdata->sorted);
10119 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10120
10121 assert(conshdlrdata->bools3size > 0);
10122
10123 /* next if condition should normally not be true, because it means that presolving has created more binary variables
10124 * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10125 * method, but for example if you would transform all integers into their binary representation then it maybe happens
10126 */
10127 if( conshdlrdata->bools3size < consdata->nvars )
10128 {
10129 int oldsize = conshdlrdata->bools3size;
10130
10131 conshdlrdata->bools3size = consdata->nvars;;
10132 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools3, oldsize, conshdlrdata->bools3size) );
10133 BMSclearMemoryArray(&(conshdlrdata->bools3[oldsize]), conshdlrdata->bools3size - oldsize); /*lint !e866*/
10134 }
10135
10136 cliqueused = conshdlrdata->bools3;
10137
10138 /* check for cleared array, all entries are zero */
10139#ifndef NDEBUG
10140 for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10141 assert(cliqueused[tmp] == 0);
10142#endif
10143
10145 tmp = 0;
10146
10147 /* calculates maximal weight of cliques */
10148 for( i = 0; i < consdata->nvars; ++i )
10149 {
10150 cliquenum = consdata->cliquepartition[i];
10152
10153 if( !cliqueused[cliquenum] )
10154 {
10155 maxcliqueweightsum += consdata->weights[i];
10158 ++tmp;
10159 }
10160 }
10161 /* clear cliqueused */
10162 for( --tmp; tmp >= 0; --tmp)
10163 cliqueused[tmp] = FALSE;
10164
10165 assert(conshdlrdata->bools4size > 0);
10166
10167 /* next if condition should normally not be true, because it means that presolving has created more binary variables
10168 * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10169 * method, but for example if you would transform all integers into their binary representation then it maybe happens
10170 */
10171 if( conshdlrdata->bools4size < consdata->nvars )
10172 {
10173 int oldsize = conshdlrdata->bools4size;
10174
10175 conshdlrdata->bools4size = consdata->nvars;
10176 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools4, oldsize, conshdlrdata->bools4size) );
10177 BMSclearMemoryArray(&conshdlrdata->bools4[oldsize], conshdlrdata->bools4size - oldsize); /*lint !e866*/
10178 }
10179
10180 itemremoved = conshdlrdata->bools4;
10181
10182 /* check for cleared array, all entries are zero */
10183#ifndef NDEBUG
10184 for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10185 assert(itemremoved[tmp] == 0);
10186#endif
10187
10188 /* for each binary variable xi and each fixing v, calculate the cliqueweightsum and update the weight of the
10189 * variable in the knapsack (this is sequence-dependent because the new or modified weights have to be
10190 * included in subsequent cliqueweightsum calculations)
10191 */
10194 naddvars = 0;
10195 addweightsum = 0;
10196 for( val = 0; val < 2 && addweightsum < consdata->capacity; ++val )
10197 {
10198 for( i = 0; i < nliftcands[val] && addweightsum < consdata->capacity; ++i )
10199 {
10200 SCIP_Longint cliqueweightsum;
10201 int probindex;
10202 int idx;
10203 int j;
10204
10205 tmp = 0;
10206
10207 probindex = liftcands[val][i];
10208 assert(0 <= probindex && probindex < nbinvars);
10209
10210 /* ignore empty zero lists and variables that cannot be lifted anyways */
10211 if( firstidxs[val][probindex] == 0
10212 || maxcliqueweightsum - zeroweightsums[val][probindex] + addweightsum >= consdata->capacity )
10213 continue;
10214
10215 /* mark the items that are implied to zero by setting the current variable to the current value */
10216 for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10217 {
10218 assert(0 < idx && idx < nzeroitems);
10219 assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10220 itemremoved[zeroitems[idx]] = TRUE;
10221 }
10222
10223 /* calculate the residual cliqueweight sum */
10224 cliqueweightsum = addweightsum; /* the previously added items are single-element cliques */
10225 for( j = 0; j < consdata->nvars; ++j )
10226 {
10227 cliquenum = consdata->cliquepartition[j];
10229 if( !itemremoved[j] )
10230 {
10231 if( !cliqueused[cliquenum] )
10232 {
10233 cliqueweightsum += consdata->weights[j];
10236 ++tmp;
10237 }
10238
10239 if( cliqueweightsum >= consdata->capacity )
10240 break;
10241 }
10242 }
10243
10244 /* check if the weight of the variable/value can be increased */
10245 if( cliqueweightsum < consdata->capacity )
10246 {
10247 SCIP_VAR* var;
10248 SCIP_Longint weight;
10249
10250 /* insert the variable (with value TRUE) in the list of additional items */
10252 var = binvars[probindex];
10253 if( val == FALSE )
10254 {
10256 }
10257 weight = consdata->capacity - cliqueweightsum;
10258 addvars[naddvars] = var;
10259 addweights[naddvars] = weight;
10260 addweightsum += weight;
10261 naddvars++;
10262
10263 SCIPdebugMsg(scip, "knapsack constraint <%s>: adding lifted item %" SCIP_LONGINT_FORMAT "<%s>\n",
10264 SCIPconsGetName(cons), weight, SCIPvarGetName(var));
10265 }
10266
10267 /* clear itemremoved */
10268 for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10269 {
10270 assert(0 < idx && idx < nzeroitems);
10271 assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10272 itemremoved[zeroitems[idx]] = FALSE;
10273 }
10274 /* clear cliqueused */
10275 for( --tmp; tmp >= 0; --tmp)
10277 }
10278 }
10279
10280 /* clear part of zeroweightsums */
10281 for( --tmp3; tmp3 >= 0; --tmp3)
10283
10284 /* clear rest of zeroweightsums and firstidxs */
10285 for( --tmp2; tmp2 >= 0; --tmp2)
10286 {
10289 }
10290
10291 /* add all additional item weights */
10292 for( i = 0; i < naddvars; ++i )
10293 {
10294 SCIP_CALL( addCoef(scip, cons, addvars[i], addweights[i]) );
10295 }
10296 *nchgcoefs += naddvars;
10297
10298 if( naddvars > 0 )
10299 {
10300 /* if new items were added, multiple entries of the same variable are possible and we have to clean up the constraint */
10302 }
10303
10304 /* free temporary memory */
10316
10317 return SCIP_OKAY;
10318}
10319
10320/** tightens item weights and capacity in presolving:
10321 * given a knapsack sum(wi*xi) <= capacity
10322 * (1) let weightsum := sum(wi)
10323 * if weightsum - wi < capacity:
10324 * - not using item i would make the knapsack constraint redundant
10325 * - wi and capacity can be changed to have the same redundancy effect and the same results for
10326 * fixing xi to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10327 * - change coefficients:
10328 * wi' := weightsum - capacity
10329 * capacity' := capacity - (wi - wi')
10330 * (2) increase weights from front to back(sortation is necessary) if there is no space left for another weight
10331 * - determine the four(can be adjusted) minimal weightsums of the knapsack, i.e. in increasing order
10332 * weights[nvars - 1], weights[nvars - 2], MIN(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]),
10333 * MIN(MAX(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]), weights[nvars - 4]), note that there
10334 * can be multiple times the same weight, this can be improved
10335 * - check if summing up a minimal weightsum with a big weight exceeds the capacity, then we can increase the big
10336 * weight, to capacity - lastmininmalweightsum, e.g. :
10337 * 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19
10338 * -> minimal weightsums: 5, 5, 10, 10
10339 * -> 15 + 5 > 19 => increase 15 to 19 - 0 = 19
10340 * -> 10 + 10 > 19 => increase 10 to 19 - 5 = 14, resulting in
10341 * 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10342 * (3) let W(C) be the maximal weight of clique C,
10343 * cliqueweightsum := sum(W(C))
10344 * if cliqueweightsum - W(C) < capacity:
10345 * - not using any item of C would make the knapsack constraint redundant
10346 * - weights wi, i in C, and capacity can be changed to have the same redundancy effect and the same results for
10347 * fixing xi, i in C, to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10348 * - change coefficients:
10349 * delta := capacity - (cliqueweightsum - W(C))
10350 * wi' := max(wi - delta, 0)
10351 * capacity' := capacity - delta
10352 * This rule has to add the used cliques in order to ensure they are enforced - otherwise, the reduction might
10353 * introduce infeasible solutions.
10354 * (4) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
10355 * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
10356 * if cliqueweightsum(xi == v) < capacity:
10357 * - fixing variable xi to v would make the knapsack constraint redundant
10358 * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
10359 * redundancy effect:
10360 * wi' := capacity - cliqueweightsum(xi == v)
10361 * This rule can also be applied to binary variables not in the knapsack!
10362 * (5) if min{w} + wi > capacity:
10363 * - using item i would force to fix other items to zero
10364 * - wi can be increased to the capacity
10365 */
10366static
10368 SCIP* scip, /**< SCIP data structure */
10369 SCIP_CONS* cons, /**< knapsack constraint */
10370 SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
10371 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10372 int* nchgsides, /**< pointer to count number of side changes */
10373 int* naddconss, /**< pointer to count number of added constraints */
10374 int* ndelconss, /**< pointer to count number of deleted constraints */
10375 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
10376 )
10377{
10378 SCIP_CONSHDLRDATA* conshdlrdata;
10379 SCIP_CONSDATA* consdata;
10380 SCIP_Longint* weights;
10381 SCIP_Longint sumcoef;
10382 SCIP_Longint capacity;
10383 SCIP_Longint newweight;
10384 SCIP_Longint maxweight;
10385 SCIP_Longint minweight;
10386 SCIP_Bool sumcoefcase = FALSE;
10387 int startpos;
10388 int backpos;
10389 int nvars;
10390 int pos;
10391 int k;
10392 int i;
10393
10394 assert(nchgcoefs != NULL);
10395 assert(nchgsides != NULL);
10397
10398 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
10399 assert(conshdlrdata != NULL);
10400
10401 consdata = SCIPconsGetData(cons);
10402 assert(consdata != NULL);
10403 assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
10404 assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
10405 assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
10406 assert(consdata->nvars > 0);
10407
10409 if( *cutoff )
10410 return SCIP_OKAY;
10411
10412 /* apply rule (1) */
10413 if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10414 {
10415 do
10416 {
10417 assert(consdata->merged);
10418
10419 /* sort items, s.t. the heaviest one is in the first position */
10420 sortItems(consdata);
10421
10422 for( i = 0; i < consdata->nvars; ++i )
10423 {
10424 SCIP_Longint weight;
10425
10426 weight = consdata->weights[i];
10427 if( consdata->weightsum - weight < consdata->capacity )
10428 {
10429 newweight = consdata->weightsum - consdata->capacity;
10430 consdataChgWeight(consdata, i, newweight);
10431 consdata->capacity -= (weight - newweight);
10432 (*nchgcoefs)++;
10433 (*nchgsides)++;
10434 assert(!consdata->sorted);
10435 SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT ", capacity from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10436 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, newweight,
10437 consdata->capacity + (weight-newweight), consdata->capacity);
10438 }
10439 else
10440 break;
10441 }
10442 }
10443 while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10444 }
10445
10446 /* check for redundancy */
10447 if( consdata->weightsum <= consdata->capacity )
10448 return SCIP_OKAY;
10449
10450 pos = 0;
10451 while( pos < consdata->nvars && consdata->weights[pos] == consdata->capacity )
10452 ++pos;
10453
10454 sumcoef = 0;
10455 weights = consdata->weights;
10456 nvars = consdata->nvars;
10457 capacity = consdata->capacity;
10458
10459 if( (presoltiming & (SCIP_PRESOLTIMING_FAST | SCIP_PRESOLTIMING_MEDIUM)) != 0 &&
10460 pos < nvars && weights[pos] + weights[pos + 1] > capacity )
10461 {
10462 /* further reductions using the next possible coefficient sum
10463 *
10464 * e.g. 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19 <=> 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10465 */
10466 /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
10467 for( k = 0; k < 4; ++k )
10468 {
10469 newweight = capacity - sumcoef;
10470
10471 /* determine next minimal coefficient sum */
10472 switch( k )
10473 {
10474 case 0:
10475 sumcoef = weights[nvars - 1];
10476 backpos = nvars - 1;
10477 break;
10478 case 1:
10479 sumcoef = weights[nvars - 2];
10480 backpos = nvars - 2;
10481 break;
10482 case 2:
10483 if( weights[nvars - 3] < weights[nvars - 1] + weights[nvars - 2] )
10484 {
10485 sumcoefcase = TRUE;
10486 sumcoef = weights[nvars - 3];
10487 backpos = nvars - 3;
10488 }
10489 else
10490 {
10492 sumcoef = weights[nvars - 1] + weights[nvars - 2];
10493 backpos = nvars - 2;
10494 }
10495 break;
10496 default:
10497 assert(k == 3);
10498 if( sumcoefcase )
10499 {
10500 if( weights[nvars - 4] < weights[nvars - 1] + weights[nvars - 2] )
10501 {
10502 sumcoef = weights[nvars - 4];
10503 backpos = nvars - 4;
10504 }
10505 else
10506 {
10507 sumcoef = weights[nvars - 1] + weights[nvars - 2];
10508 backpos = nvars - 2;
10509 }
10510 }
10511 else
10512 {
10513 sumcoef = weights[nvars - 3];
10514 backpos = nvars - 3;
10515 }
10516 break;
10517 }
10518
10519 if( backpos <= pos )
10520 break;
10521
10522 /* tighten next coefficients that, paired with the current small coefficient, exceed the capacity */
10523 maxweight = weights[pos];
10524 startpos = pos;
10525 while( 2 * maxweight > capacity && maxweight + sumcoef > capacity )
10526 {
10527 assert(newweight > weights[pos]);
10528
10529 SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10530 SCIPconsGetName(cons), maxweight, newweight);
10531
10532 consdataChgWeight(consdata, pos, newweight);
10533
10534 ++pos;
10535 assert(pos < nvars);
10536
10537 maxweight = weights[pos];
10538
10539 if( backpos <= pos )
10540 break;
10541 }
10542 (*nchgcoefs) += (pos - startpos);
10543
10544 /* skip unchangable weights */
10545 while( pos < nvars && weights[pos] + sumcoef == capacity )
10546 ++pos;
10547
10548 /* check special case were there is only one weight left to tighten
10549 *
10550 * e.g. 95x1 + 59x2 + 37x3 + 36x4 <= 95 (37 > 36)
10551 *
10552 * => 95x1 + 59x2 + 59x3 + 36x4 <= 95
10553 *
10554 * 197x1 + 120x2 + 77x3 + 10x4 <= 207 (here we cannot tighten the coefficient further)
10555 */
10556 if( pos + 1 == backpos && weights[pos] > sumcoef &&
10557 ((k == 0) || (k == 1 && weights[nvars - 1] + sumcoef + weights[pos] > capacity)) )
10558 {
10559 newweight = capacity - sumcoef;
10560 assert(newweight > weights[pos]);
10561
10562 SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10563 SCIPconsGetName(cons), maxweight, newweight);
10564
10565 consdataChgWeight(consdata, pos, newweight);
10566
10567 break;
10568 }
10569
10570 if( backpos <= pos )
10571 break;
10572 }
10573 }
10574
10575 /* apply rule (2) (don't apply, if the knapsack has too many items for applying this costly method) */
10576 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
10577 {
10578 if( conshdlrdata->disaggregation && consdata->nvars - pos <= MAX_USECLIQUES_SIZE && consdata->nvars >= 2 &&
10579 pos > 0 && (SCIP_Longint)consdata->nvars - pos <= consdata->capacity &&
10580 consdata->weights[pos - 1] == consdata->capacity && (pos == consdata->nvars || consdata->weights[pos] == 1) )
10581 {
10582 SCIP_VAR** clqvars;
10584 char name[SCIP_MAXSTRLEN];
10585 int* clqpart;
10586 int nclqvars;
10587 int nclq;
10588 int len;
10589 int c;
10590 int w;
10591
10592 assert(!SCIPconsIsDeleted(cons));
10593
10594 if( pos == consdata->nvars )
10595 {
10596 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
10597
10598 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, SCIPconsGetName(cons), pos, consdata->vars,
10602 SCIPconsIsStickingAtNode(cons)) );
10603
10606 ++(*naddconss);
10607
10608 /* delete old constraint */
10609 SCIP_CALL( SCIPdelCons(scip, cons) );
10610 ++(*ndelconss);
10611
10612 return SCIP_OKAY;
10613 }
10614
10615 len = consdata->nvars - pos;
10616
10617 /* allocate temporary memory */
10619
10620 /* calculate clique partition */
10621 SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[pos]), len, clqpart, &nclq) );
10622 assert(nclq <= len);
10623
10624#ifndef NDEBUG
10625 /* clique numbers must be at least as high as the index */
10626 for( w = 0; w < nclq; ++w )
10627 assert(clqpart[w] <= w);
10628#endif
10629
10630 SCIPdebugMsg(scip, "Disaggregating knapsack constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
10631
10632 /* allocate temporary memory */
10633 SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, pos + len - nclq + 1) );
10634
10635 /* copy corresponding variables with big coefficients */
10636 for( w = pos - 1; w >= 0; --w )
10637 clqvars[w] = consdata->vars[w];
10638
10639 /* create for each clique a set-packing constraint */
10640 for( c = 0; c < nclq; ++c )
10641 {
10642 nclqvars = pos;
10643
10644 for( w = c; w < len; ++w )
10645 {
10646 if( clqpart[w] == c )
10647 {
10648 assert(nclqvars < pos + len - nclq + 1);
10649 clqvars[nclqvars] = consdata->vars[w + pos];
10650 ++nclqvars;
10651 }
10652 }
10653
10654 assert(nclqvars > 1);
10655
10656 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, c);
10661 SCIPconsIsStickingAtNode(cons)) );
10662 SCIPdebugMsg(scip, " -> adding clique constraint: ");
10666 ++(*naddconss);
10667 }
10668
10669 /* delete old constraint */
10670 SCIP_CALL( SCIPdelCons(scip, cons) );
10671 ++(*ndelconss);
10672
10675
10676 return SCIP_OKAY;
10677 }
10678 else if( consdata->nvars <= MAX_USECLIQUES_SIZE || (consdata->cliquepartitioned && consdata->ncliques <= MAX_USECLIQUES_SIZE) )
10679 {
10680 SCIP_Longint* maxcliqueweights;
10681 SCIP_Longint* newweightvals;
10682 int* newweightidxs;
10683 SCIP_Longint cliqueweightsum;
10684
10685 SCIP_CALL( SCIPallocBufferArray(scip, &maxcliqueweights, consdata->nvars) );
10686 SCIP_CALL( SCIPallocBufferArray(scip, &newweightvals, consdata->nvars) );
10687 SCIP_CALL( SCIPallocBufferArray(scip, &newweightidxs, consdata->nvars) );
10688
10689 /* repeat as long as changes have been applied */
10690 do
10691 {
10692 int ncliques;
10693 int cliquenum;
10694 SCIP_Bool zeroweights;
10695
10696 assert(consdata->merged);
10697
10698 /* sort items, s.t. the heaviest one is in the first position */
10699 sortItems(consdata);
10700
10701 /* calculate a clique partition */
10702 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10703
10704 /* if there are only single element cliques, rule (2) is equivalent to rule (1) */
10705 if( consdata->cliquepartition[consdata->nvars - 1] == consdata->nvars - 1 )
10706 break;
10707
10708 /* calculate the maximal weight of the cliques and store the clique type */
10709 cliqueweightsum = 0;
10710 ncliques = 0;
10711
10712 for( i = 0; i < consdata->nvars; ++i )
10713 {
10714 SCIP_Longint weight;
10715
10716 cliquenum = consdata->cliquepartition[i];
10717 assert(0 <= cliquenum && cliquenum <= ncliques);
10718
10719 weight = consdata->weights[i];
10720 assert(weight > 0);
10721
10722 if( cliquenum == ncliques )
10723 {
10724 maxcliqueweights[ncliques] = weight;
10725 cliqueweightsum += weight;
10726 ++ncliques;
10727 }
10728
10729 assert(maxcliqueweights[cliquenum] >= weight);
10730 }
10731
10732 /* apply rule on every clique */
10734 for( i = 0; i < ncliques; ++i )
10735 {
10736 SCIP_Longint delta;
10737
10738 delta = consdata->capacity - (cliqueweightsum - maxcliqueweights[i]);
10739 if( delta > 0 )
10740 {
10741 SCIP_Longint newcapacity;
10742#ifndef NDEBUG
10743 SCIP_Longint newmincliqueweight;
10744#endif
10745 SCIP_Longint newminweightsuminclique;
10746 SCIP_Bool forceclique;
10747 int nnewweights;
10748 int j;
10749
10750 SCIPdebugMsg(scip, "knapsack constraint <%s>: weights of clique %d (maxweight: %" SCIP_LONGINT_FORMAT ") can be tightened: cliqueweightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT " -> delta: %" SCIP_LONGINT_FORMAT "\n",
10751 SCIPconsGetName(cons), i, maxcliqueweights[i], cliqueweightsum, consdata->capacity, delta);
10752 newcapacity = consdata->capacity - delta;
10754 nnewweights = 0;
10755#ifndef NDEBUG
10757 for( j = 0; j < i; ++j )
10758 assert(consdata->cliquepartition[j] < i); /* no element j < i can be in clique i */
10759#endif
10760 for( j = i; j < consdata->nvars; ++j )
10761 {
10762 if( consdata->cliquepartition[j] == i )
10763 {
10764 newweight = consdata->weights[j] - delta;
10765 newweight = MAX(newweight, 0);
10766
10767 /* cache the new weight */
10771 nnewweights++;
10772
10773#ifndef NDEBUG
10774 assert(newweight <= newmincliqueweight); /* items are sorted by non-increasing weight! */
10776#endif
10777 }
10778 }
10779
10780 /* check if our clique information results out of this knapsack constraint and if so check if we would loose the clique information */
10781 if( nnewweights > 1 )
10782 {
10783#ifndef NDEBUG
10785 assert(0 <= j && j < consdata->nvars);
10786 assert(consdata->cliquepartition[j] == i);
10788 assert(0 <= j && j < consdata->nvars);
10789 assert(consdata->cliquepartition[j] == i);
10790#endif
10791
10794
10795 /* check if these new two minimal weights both fit into the knapsack;
10796 * if this is true, we have to add a clique constraint in order to enforce the clique
10797 * (otherwise, the knapsack might have been one of the reasons for the clique, and the weight
10798 * reduction might be infeasible, i.e., allows additional solutions)
10799 */
10801 forceclique = TRUE;
10802 }
10803
10804 /* check if we really want to apply the change */
10805 if( conshdlrdata->disaggregation || !forceclique )
10806 {
10807 SCIPdebugMsg(scip, " -> change capacity from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT " (forceclique:%u)\n",
10808 consdata->capacity, newcapacity, forceclique);
10809 consdata->capacity = newcapacity;
10810 (*nchgsides)++;
10811
10812 for( k = 0; k < nnewweights; ++k )
10813 {
10814 j = newweightidxs[k];
10815 assert(0 <= j && j < consdata->nvars);
10816 assert(consdata->cliquepartition[j] == i);
10817
10818 /* apply the weight change */
10819 SCIPdebugMsg(scip, " -> change weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10820 SCIPvarGetName(consdata->vars[j]), consdata->weights[j], newweightvals[k]);
10821 consdataChgWeight(consdata, j, newweightvals[k]);
10822 (*nchgcoefs)++;
10823 assert(!consdata->sorted);
10825 }
10826 /* if before the weight update at least one pair of weights did not fit into the knapsack and now fits,
10827 * we have to make sure, the clique is enforced - the clique might have been constructed partially from
10828 * this constraint, and by reducing the weights, this clique information is not contained anymore in the
10829 * knapsack constraint
10830 */
10831 if( forceclique )
10832 {
10834 char name[SCIP_MAXSTRLEN];
10836
10838 for( k = 0; k < nnewweights; ++k )
10839 cliquevars[k] = consdata->vars[newweightidxs[k]];
10840
10841 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, i);
10846 SCIPconsIsStickingAtNode(cons)) );
10847 SCIPdebugMsg(scip, " -> adding clique constraint: ");
10852 (*naddconss)++;
10853 }
10854 }
10855 }
10856 }
10857 if( zeroweights )
10858 {
10860 }
10861 }
10862 while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10863
10864 /* free temporary memory */
10868
10869 /* check for redundancy */
10870 if( consdata->weightsum <= consdata->capacity )
10871 return SCIP_OKAY;
10872 }
10873 }
10874
10875 /* apply rule (3) */
10876 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
10877 {
10878 SCIP_CALL( tightenWeightsLift(scip, cons, nchgcoefs, cutoff) );
10879 }
10880
10881 /* check for redundancy */
10882 if( consdata->weightsum <= consdata->capacity )
10883 return SCIP_OKAY;
10884
10885 if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10886 {
10887 /* apply rule (4) (all but smallest weight) */
10888 assert(consdata->merged);
10889 sortItems(consdata);
10890 minweight = consdata->weights[consdata->nvars-1];
10891 for( i = 0; i < consdata->nvars-1; ++i )
10892 {
10893 SCIP_Longint weight;
10894
10895 weight = consdata->weights[i];
10896 assert(weight >= minweight);
10897 if( minweight + weight > consdata->capacity )
10898 {
10899 if( weight < consdata->capacity )
10900 {
10901 SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10902 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, consdata->capacity);
10903 assert(consdata->sorted);
10904 consdataChgWeight(consdata, i, consdata->capacity); /* this does not destroy the weight order! */
10905 assert(i == 0 || consdata->weights[i-1] >= consdata->weights[i]);
10906 consdata->sorted = TRUE;
10907 (*nchgcoefs)++;
10908 }
10909 }
10910 else
10911 break;
10912 }
10913
10914 /* apply rule (5) (smallest weight) */
10915 if( consdata->nvars >= 2 )
10916 {
10917 SCIP_Longint weight;
10918
10919 minweight = consdata->weights[consdata->nvars-2];
10920 weight = consdata->weights[consdata->nvars-1];
10921 assert(minweight >= weight);
10922 if( minweight + weight > consdata->capacity && weight < consdata->capacity )
10923 {
10924 SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10925 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[consdata->nvars-1]), weight, consdata->capacity);
10926 assert(consdata->sorted);
10927 consdataChgWeight(consdata, consdata->nvars-1, consdata->capacity); /* this does not destroy the weight order! */
10928 assert(minweight >= consdata->weights[consdata->nvars-1]);
10929 consdata->sorted = TRUE;
10930 (*nchgcoefs)++;
10931 }
10932 }
10933 }
10934
10935 return SCIP_OKAY;
10936}
10937
10938
10939#ifdef SCIP_DEBUG
10940static
10941void printClique(
10943 int ncliquevars
10944 )
10945{
10946 int b;
10947 SCIPdebugMessage("adding new Clique: ");
10948 for( b = 0; b < ncliquevars; ++b )
10950 SCIPdebugPrintf("\n");
10951}
10952#endif
10953
10954/** adds negated cliques of the knapsack constraint to the global clique table */
10955static
10957 SCIP*const scip, /**< SCIP data structure */
10958 SCIP_CONS*const cons, /**< knapsack constraint */
10959 SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
10960 int*const nbdchgs /**< pointer to count the number of performed bound changes */
10961 )
10962{
10963 SCIP_CONSDATA* consdata;
10964 SCIP_CONSHDLRDATA* conshdlrdata;
10967 SCIP_Longint* maxweights;
10968 SCIP_Longint* gainweights;
10970 SCIP_Bool* cliqueused;
10971 SCIP_Longint minactduetonegcliques;
10972 SCIP_Longint freecapacity;
10973 SCIP_Longint lastweight;
10974 SCIP_Longint beforelastweight;
10975 int nposcliquevars;
10976 int ncliquevars;
10977 int nvars;
10978 int nnegcliques;
10979 int lastcliqueused;
10980 int thisnbdchgs;
10981 int v;
10982 int w;
10983
10984 assert(scip != NULL);
10985 assert(cons != NULL);
10986 assert(cutoff != NULL);
10987 assert(nbdchgs != NULL);
10988
10989 *cutoff = FALSE;
10990
10991 consdata = SCIPconsGetData(cons);
10992 assert(consdata != NULL);
10993
10994 nvars = consdata->nvars;
10995
10996 /* check whether the cliques have already been added */
10997 if( consdata->cliquesadded || nvars == 0 )
10998 return SCIP_OKAY;
10999
11000 /* make sure, the items are merged */
11002 if( *cutoff )
11003 return SCIP_OKAY;
11004
11005 /* make sure, items are sorted by non-increasing weight */
11006 sortItems(consdata);
11007
11008 assert(consdata->merged);
11009
11010 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11011 assert(conshdlrdata != NULL);
11012
11013 /* calculate a clique partition */
11014 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
11015 nnegcliques = consdata->nnegcliques;
11016
11017 /* if we have no negated cliques, stop */
11018 if( nnegcliques == nvars )
11019 return SCIP_OKAY;
11020
11021 /* get temporary memory */
11026 SCIP_CALL( SCIPallocBufferArray(scip, &maxweights, nnegcliques) );
11028
11029 nnegcliques = 0;
11031
11032 /* determine maximal weights for all negated cliques and calculate minimal weightsum due to negated cliques */
11033 for( v = 0; v < nvars; ++v )
11034 {
11035 assert(0 <= consdata->negcliquepartition[v] && consdata->negcliquepartition[v] <= nnegcliques);
11036 assert(consdata->weights[v] > 0);
11037
11038 if( consdata->negcliquepartition[v] == nnegcliques )
11039 {
11040 nnegcliques++;
11041 maxweights[consdata->negcliquepartition[v]] = consdata->weights[v];
11042 }
11043 else
11044 minactduetonegcliques += consdata->weights[v];
11045 }
11046
11047 nposcliquevars = 0;
11048
11049 /* add cliques, using negated cliques information */
11050 if( minactduetonegcliques > 0 )
11051 {
11052 /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11053 freecapacity = consdata->capacity - minactduetonegcliques;
11054
11056 SCIPdebugMsg(scip, "Try to add negated cliques in knapsack constraint handler for constraint %s; capacity = %" SCIP_LONGINT_FORMAT ", minactivity(due to neg. cliques) = %" SCIP_LONGINT_FORMAT ", freecapacity = %" SCIP_LONGINT_FORMAT ".\n",
11057 SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11058
11059 /* calculate possible gain by switching chosen items in negated cliques */
11060 for( v = 0; v < nvars; ++v )
11061 {
11062 if( !cliqueused[consdata->negcliquepartition[v]] )
11063 {
11064 cliqueused[consdata->negcliquepartition[v]] = TRUE;
11065 for( w = v + 1; w < nvars; ++w )
11066 {
11067 /* if we would take the biggest weight instead of another what would we gain, take weight[v] instead of
11068 * weight[w] (which are both in a negated clique) */
11069 if( consdata->negcliquepartition[v] == consdata->negcliquepartition[w]
11070 && consdata->weights[v] > consdata->weights[w] )
11071 {
11072 poscliquevars[nposcliquevars] = consdata->vars[w];
11073 gainweights[nposcliquevars] = maxweights[consdata->negcliquepartition[v]] - consdata->weights[w];
11074 gaincliquepartition[nposcliquevars] = consdata->negcliquepartition[v];
11076 }
11077 }
11078 }
11079 }
11080
11081 /* try to create negated cliques */
11082 if( nposcliquevars > 0 )
11083 {
11084 /* sort possible gain per substitution of the clique members */
11086
11087 for( v = 0; v < nposcliquevars; ++v )
11088 {
11090 ncliquevars = 1;
11092 beforelastweight = -1;
11094 /* clear cliqueused to get an unused array */
11095 BMSclearMemoryArray(cliqueused, nnegcliques);
11097
11098 /* taking bigger weights make the knapsack redundant so we will create cliques, only take items which are not
11099 * in the same negated clique and by taking two of them would exceed the free capacity */
11101 {
11107 ++ncliquevars;
11108 }
11109
11110 if( ncliquevars > 1 )
11111 {
11114 /* add the clique to the clique table */
11115 /* this really happens, e.g., on enigma.mps from the short test set */
11117 if( *cutoff )
11118 goto TERMINATE;
11119 *nbdchgs += thisnbdchgs;
11120
11121 /* reset last used clique to get slightly different cliques */
11123
11124 /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11126 {
11130 if( *cutoff )
11131 goto TERMINATE;
11132 *nbdchgs += thisnbdchgs;
11133 }
11134 }
11135 }
11136 }
11137 }
11138
11139 TERMINATE:
11140 /* free temporary memory */
11147
11148 return SCIP_OKAY;
11149}
11150
11151/** greedy clique detection by considering weights and capacity
11152 *
11153 * greedily detects cliques by first sorting the items by decreasing weights (optional) and then collecting greedily
11154 * 1) neighboring items which exceed the capacity together => one clique
11155 * 2) looping through the remaining items and finding the largest set of preceding items to build a clique => possibly many more cliques
11156 */
11157static
11159 SCIP*const scip, /**< SCIP data structure */
11160 SCIP_VAR** items, /**< array of variable items */
11161 SCIP_Longint* weights, /**< weights of the items */
11162 int nitems, /**< the number of items */
11163 SCIP_Longint capacity, /**< maximum free capacity of the knapsack */
11164 SCIP_Bool sorteditems, /**< are the items sorted by their weights nonincreasing? */
11165 SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11166 SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11167 int*const nbdchgs /**< pointer to count the number of performed bound changes */
11168 )
11169{
11170 SCIP_Longint lastweight;
11171 int ncliquevars;
11172 int i;
11173 int thisnbdchgs;
11174
11175 if( nitems <= 1 )
11176 return SCIP_OKAY;
11177
11178 /* sort possible gain per substitution of the clique members */
11179 if( ! sorteditems )
11180 SCIPsortDownLongPtr(weights,(void**) items, nitems);
11181
11182 ncliquevars = 1;
11183 lastweight = weights[0];
11184
11185 /* taking these two weights together violates the knapsack => include into clique */
11186 for( i = 1; i < nitems && weights[i] + lastweight > capacity; ++i )
11187 {
11188 lastweight = weights[i];
11189 ++ncliquevars;
11190 }
11191
11192 if( ncliquevars > 1 )
11193 {
11194 SCIP_Longint compareweight;
11196 int compareweightidx;
11197 int minclqsize;
11198 int nnzadded;
11199
11200 /* add the clique to the clique table */
11203
11204 if( *cutoff )
11205 return SCIP_OKAY;
11206
11207 *nbdchgs += thisnbdchgs;
11209
11210 /* no more cliques to be found (don't know if this can actually happen, since the knapsack could be replaced by a set-packing constraint)*/
11211 if( ncliquevars == nitems )
11212 return SCIP_OKAY;
11213
11214 /* copy items in order into buffer array and deduce more cliques */
11216
11217 /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11218 /* loop over remaining, smaller items and compare each item backwards against larger weights, starting with the second smallest weight */
11220 assert(i == nitems || weights[i] + weights[ncliquevars - 1] <= capacity);
11221
11222 /* determine minimum clique size for the following loop */
11223 minclqsize = (int)(cliqueextractfactor * ncliquevars);
11225
11226 /* loop over the remaining variables and the larger items of the first clique until we
11227 * find another clique or reach the size limit */
11228 while( compareweightidx >= 0 && i < nitems && ! (*cutoff)
11229 && ncliquevars >= minclqsize /* stop at a given minimum clique size */
11230 && nnzadded <= 2 * nitems /* stop if enough nonzeros were added to the cliquetable */
11231 )
11232 {
11234 assert(compareweight > 0);
11235
11236 /* include this item together with all items that have a weight at least as large as the compare weight in a clique */
11237 if( compareweight + weights[i] > capacity )
11238 {
11240 cliquevars[ncliquevars - 1] = items[i];
11243
11245
11246 /* stop when there is a cutoff */
11247 if( ! (*cutoff) )
11248 *nbdchgs += thisnbdchgs;
11249
11250 /* go to next smaller item */
11251 ++i;
11252 }
11253 else
11254 {
11255 /* choose a preceding, larger weight to compare small items against. Clique size is reduced by 1 simultaneously */
11257 ncliquevars --;
11258 }
11259 }
11260
11262 }
11263
11264 return SCIP_OKAY;
11265}
11266
11267/** adds cliques of the knapsack constraint to the global clique table */
11268static
11270 SCIP*const scip, /**< SCIP data structure */
11271 SCIP_CONS*const cons, /**< knapsack constraint */
11272 SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11273 SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11274 int*const nbdchgs /**< pointer to count the number of performed bound changes */
11275 )
11276{
11277 SCIP_CONSDATA* consdata;
11278 SCIP_CONSHDLRDATA* conshdlrdata;
11279 int i;
11280 SCIP_Longint minactduetonegcliques;
11281 SCIP_Longint freecapacity;
11282 int nnegcliques;
11283 int cliquenum;
11285 SCIP_Longint* gainweights;
11286 int nposcliquevars;
11287 SCIP_Longint* secondmaxweights;
11288 int nvars;
11289
11290 assert(scip != NULL);
11291 assert(cons != NULL);
11292 assert(cutoff != NULL);
11293 assert(nbdchgs != NULL);
11294
11295 *cutoff = FALSE;
11296
11297 consdata = SCIPconsGetData(cons);
11298 assert(consdata != NULL);
11299
11300 nvars = consdata->nvars;
11301
11302 /* check whether the cliques have already been added */
11303 if( consdata->cliquesadded || nvars == 0 )
11304 return SCIP_OKAY;
11305
11306 /* make sure, the items are merged */
11308 if( *cutoff )
11309 return SCIP_OKAY;
11310
11311 /* make sure, the items are sorted by non-increasing weight */
11312 sortItems(consdata);
11313
11314 assert(consdata->merged);
11315
11316 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11317 assert(conshdlrdata != NULL);
11318
11319 /* calculate a clique partition */
11320 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
11321 nnegcliques = consdata->nnegcliques;
11322 assert(nnegcliques <= nvars);
11323
11324 /* get temporary memory */
11330
11332
11333 /* calculate minimal activity due to negated cliques, and determine second maximal weight in each clique */
11334 if( nnegcliques < nvars )
11335 {
11336 nnegcliques = 0;
11337
11338 for( i = 0; i < nvars; ++i )
11339 {
11340 SCIP_Longint weight;
11341
11342 cliquenum = consdata->negcliquepartition[i];
11343 assert(0 <= cliquenum && cliquenum <= nnegcliques);
11344
11345 weight = consdata->weights[i];
11346 assert(weight > 0);
11347
11348 if( cliquenum == nnegcliques )
11349 nnegcliques++;
11350 else
11351 {
11352 minactduetonegcliques += weight;
11353 if( secondmaxweights[cliquenum] == 0 )
11354 secondmaxweights[cliquenum] = weight;
11355 }
11356 }
11357 }
11358
11359 /* add cliques, using negated cliques information */
11360 if( minactduetonegcliques > 0 )
11361 {
11362 /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11363 freecapacity = consdata->capacity - minactduetonegcliques;
11364
11366 SCIPdebugMsg(scip, "Try to add cliques in knapsack constraint handler for constraint %s; capacity = %" SCIP_LONGINT_FORMAT ", minactivity(due to neg. cliques) = %" SCIP_LONGINT_FORMAT ", freecapacity = %" SCIP_LONGINT_FORMAT ".\n",
11367 SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11368
11369 /* create negated cliques out of negated cliques, if we do not take the smallest weight of a cliques ... */
11370 SCIP_CALL( addNegatedCliques(scip, cons, cutoff, nbdchgs ) );
11371
11372 if( *cutoff )
11373 goto TERMINATE;
11374
11375 nposcliquevars = 0;
11376
11377 for( i = nvars - 1; i >= 0; --i )
11378 {
11379 /* if we would take the biggest weight instead of the second biggest */
11380 cliquenum = consdata->negcliquepartition[i];
11381 if( consdata->weights[i] > secondmaxweights[cliquenum] )
11382 {
11383 poscliquevars[nposcliquevars] = consdata->vars[i];
11384 gainweights[nposcliquevars] = consdata->weights[i] - secondmaxweights[cliquenum];
11386 }
11387 }
11388
11389 /* use the gain weights and free capacity to derive greedily cliques */
11390 if( nposcliquevars > 1 )
11391 {
11393
11394 if( *cutoff )
11395 goto TERMINATE;
11396 }
11397 }
11398
11399 /* build cliques by using the items with the maximal weights */
11400 SCIP_CALL( greedyCliqueAlgorithm(scip, consdata->vars, consdata->weights, nvars, consdata->capacity, TRUE, cliqueextractfactor, cutoff, nbdchgs) );
11401
11402 TERMINATE:
11403 /* free temporary memory and mark the constraint */
11407 consdata->cliquesadded = TRUE;
11408
11409 return SCIP_OKAY;
11410}
11411
11412
11413/** gets the key of the given element */
11414static
11416{ /*lint --e{715}*/
11417 /* the key is the element itself */
11418 return elem;
11419}
11420
11421/** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables and the
11422 * same coefficients
11423 */
11424static
11426{
11427#ifndef NDEBUG
11428 SCIP* scip;
11429#endif
11432 int i;
11433
11436 assert(consdata1->sorted);
11437 assert(consdata2->sorted);
11438#ifndef NDEBUG
11439 scip = (SCIP*)userptr;
11440 assert(scip != NULL);
11441#endif
11442
11443 /* checks trivial case */
11444 if( consdata1->nvars != consdata2->nvars )
11445 return FALSE;
11446
11447 for( i = consdata1->nvars - 1; i >= 0; --i )
11448 {
11449 /* tests if variables are equal */
11450 if( consdata1->vars[i] != consdata2->vars[i] )
11451 {
11452 assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 ||
11453 SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1);
11454 return FALSE;
11455 }
11456 assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 0);
11457
11458 /* tests if weights are equal too */
11459 if( consdata1->weights[i] != consdata2->weights[i] )
11460 return FALSE;
11461 }
11462
11463 return TRUE;
11464}
11465
11466/** returns the hash value of the key */
11467static
11469{
11470#ifndef NDEBUG
11471 SCIP* scip;
11472#endif
11473 SCIP_CONSDATA* consdata;
11474 uint64_t firstweight;
11475 int minidx;
11476 int mididx;
11477 int maxidx;
11478
11479 consdata = SCIPconsGetData((SCIP_CONS*)key);
11480 assert(consdata != NULL);
11481 assert(consdata->nvars > 0);
11482
11483#ifndef NDEBUG
11484 scip = (SCIP*)userptr;
11485 assert(scip != NULL);
11486#endif
11487
11488 /* sorts the constraints */
11489 sortItems(consdata);
11490
11491 minidx = SCIPvarGetIndex(consdata->vars[0]);
11492 mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]);
11493 maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]);
11494 assert(minidx >= 0 && mididx >= 0 && maxidx >= 0);
11495
11496 /* hash value depends on vectors of variable indices */
11497 firstweight = (uint64_t)consdata->weights[0];
11498 return SCIPhashSix(consdata->nvars, minidx, mididx, maxidx, firstweight>>32, firstweight);
11499}
11500
11501/** compares each constraint with all other constraints for possible redundancy and removes or changes constraint
11502 * accordingly; in contrast to preprocessConstraintPairs(), it uses a hash table
11503 */
11504static
11506 SCIP* scip, /**< SCIP data structure */
11507 BMS_BLKMEM* blkmem, /**< block memory */
11508 SCIP_CONS** conss, /**< constraint set */
11509 int nconss, /**< number of constraints in constraint set */
11510 SCIP_Bool* cutoff, /**< pointer to store whether the problem is infeasible */
11511 int* ndelconss /**< pointer to count number of deleted constraints */
11512 )
11513{
11514 SCIP_HASHTABLE* hashtable;
11515 int hashtablesize;
11516 int c;
11517
11518 assert(scip != NULL);
11519 assert(blkmem != NULL);
11520 assert(conss != NULL);
11521 assert(ndelconss != NULL);
11522
11523 /* create a hash table for the constraint set */
11524 hashtablesize = nconss;
11525 hashtablesize = MAX(hashtablesize, HASHSIZE_KNAPSACKCONS);
11526 SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize,
11528
11529 /* check all constraints in the given set for redundancy */
11530 for( c = nconss - 1; c >= 0; --c )
11531 {
11535
11536 cons0 = conss[c];
11537
11539 continue;
11540
11542 assert(consdata0 != NULL);
11543 if( consdata0->nvars == 0 )
11544 {
11545 if( consdata0->capacity < 0 )
11546 {
11547 *cutoff = TRUE;
11548 goto TERMINATE;
11549 }
11550 else
11551 {
11553 ++(*ndelconss);
11554 continue;
11555 }
11556 }
11557
11558 /* get constraint from current hash table with same variables and same weights as cons0 */
11559 cons1 = (SCIP_CONS*)(SCIPhashtableRetrieve(hashtable, (void*)cons0));
11560
11561 if( cons1 != NULL )
11562 {
11566
11569
11570 /* constraint found: create a new constraint with same coefficients and best left and right hand side;
11571 * delete old constraints afterwards
11572 */
11574
11575 assert(consdata1 != NULL);
11576 assert(consdata0->nvars > 0 && consdata0->nvars == consdata1->nvars);
11577
11578 assert(consdata0->sorted && consdata1->sorted);
11579 assert(consdata0->vars[0] == consdata1->vars[0]);
11580 assert(consdata0->weights[0] == consdata1->weights[0]);
11581
11582 SCIPdebugMsg(scip, "knapsack constraints <%s> and <%s> with equal coefficients\n",
11584
11585 /* check which constraint has to stay; */
11586 if( consdata0->capacity < consdata1->capacity )
11587 {
11588 consstay = cons0;
11589 consdel = cons1;
11590
11591 /* exchange consdel with consstay in hashtable */
11592 SCIP_CALL( SCIPhashtableRemove(hashtable, (void*) consdel) );
11593 SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) consstay) );
11594 }
11595 else
11596 {
11597 consstay = cons1;
11598 consdel = cons0;
11599 }
11600
11601 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11603
11604 /* delete consdel */
11606 ++(*ndelconss);
11607
11609 }
11610 else
11611 {
11612 /* no such constraint in current hash table: insert cons0 into hash table */
11613 SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) cons0) );
11614 }
11615 }
11616
11617 TERMINATE:
11618 /* free hash table */
11619 SCIPhashtableFree(&hashtable);
11620
11621 return SCIP_OKAY;
11622}
11623
11624
11625/** compares constraint with all prior constraints for possible redundancy or aggregation,
11626 * and removes or changes constraint accordingly
11627 */
11628static
11630 SCIP* scip, /**< SCIP data structure */
11631 SCIP_CONS** conss, /**< constraint set */
11632 int firstchange, /**< first constraint that changed since last pair preprocessing round */
11633 int chkind, /**< index of constraint to check against all prior indices upto startind */
11634 int* ndelconss /**< pointer to count number of deleted constraints */
11635 )
11636{
11639 int c;
11640
11641 assert(scip != NULL);
11642 assert(conss != NULL);
11644 assert(ndelconss != NULL);
11645
11646 /* get the constraint to be checked against all prior constraints */
11647 cons0 = conss[chkind];
11648 assert(cons0 != NULL);
11651
11653 assert(consdata0 != NULL);
11654 assert(consdata0->nvars >= 1);
11655 assert(consdata0->merged);
11656
11657 /* sort the constraint */
11659
11660 /* see #2970 */
11661 if( consdata0->capacity == 0 )
11662 return SCIP_OKAY;
11663
11664 /* check constraint against all prior constraints */
11665 for( c = (consdata0->presolvedtiming == SCIP_PRESOLTIMING_EXHAUSTIVE ? firstchange : 0); c < chkind; ++c )
11666 {
11669 SCIP_Bool iscons0incons1contained;
11670 SCIP_Bool iscons1incons0contained;
11671 SCIP_Real quotient;
11672 int v;
11673 int v0;
11674 int v1;
11675
11676 cons1 = conss[c];
11677 assert(cons1 != NULL);
11679 continue;
11680
11682 assert(consdata1 != NULL);
11683
11684 /* if both constraints didn't change since last pair processing, we can ignore the pair */
11685 if( consdata0->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE && consdata1->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE ) /*lint !e574*/
11686 continue;
11687
11688 assert(consdata1->nvars >= 1);
11689 assert(consdata1->merged);
11690
11691 /* sort the constraint */
11693
11694 /* see #2970 */
11695 if( consdata1->capacity == 0 )
11696 continue;
11697
11698 quotient = ((SCIP_Real) consdata0->capacity) / ((SCIP_Real) consdata1->capacity);
11699
11700 if( consdata0->nvars > consdata1->nvars )
11701 {
11704 v = consdata1->nvars - 1;
11705 }
11706 else if( consdata0->nvars < consdata1->nvars )
11707 {
11710 v = consdata0->nvars - 1;
11711 }
11712 else
11713 {
11716 v = consdata0->nvars - 1;
11717 }
11718
11719 SCIPdebugMsg(scip, "preprocess knapsack constraint pair <%s> and <%s>\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11720
11721 /* check consdata0 against consdata1:
11722 * 1. if all variables var_i of cons1 are in cons0 and for each of these variables
11723 * (consdata0->weights[i] / quotient) >= consdata1->weights[i] cons1 is redundant
11724 * 2. if all variables var_i of cons0 are in cons1 and for each of these variables
11725 * (consdata0->weights[i] / quotient) <= consdata1->weights[i] cons0 is redundant
11726 */
11727 v0 = consdata0->nvars - 1;
11728 v1 = consdata1->nvars - 1;
11729
11730 while( v >= 0 )
11731 {
11733
11734 /* now there are more variables in cons1 left */
11735 if( v1 > v0 )
11736 {
11739 break;
11740 }
11741 /* now there are more variables in cons0 left */
11742 else if( v1 < v0 )
11743 {
11746 break;
11747 }
11748
11749 assert(v == v0 || v == v1);
11750 assert(v0 >= 0);
11751 assert(v1 >= 0);
11752
11753 /* both variables are the same */
11754 if( consdata0->vars[v0] == consdata1->vars[v1] )
11755 {
11756 /* if cons1 is possible contained in cons0 (consdata0->weights[v0] / quotient) must be greater equals consdata1->weights[v1] */
11757 if( iscons1incons0contained && SCIPisLT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11758 {
11761 break;
11762 }
11763 /* if cons0 is possible contained in cons1 (consdata0->weight[v0] / quotient) must be less equals consdata1->weight[v1] */
11764 else if( iscons0incons1contained && SCIPisGT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11765 {
11768 break;
11769 }
11770 --v0;
11771 --v1;
11772 --v;
11773 }
11774 else
11775 {
11776 /* both constraints have a variables which is not part of the other constraint, so stop */
11778 {
11781 break;
11782 }
11785 /* continue to the next variable */
11787 --v1;
11788 else
11789 --v0;
11790 }
11791 }
11792 /* neither one constraint was contained in another or we checked all variables of one constraint against the
11793 * other
11794 */
11796
11798 {
11799 SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons1));
11801
11802 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11804
11806 ++(*ndelconss);
11807 }
11808 else if( iscons0incons1contained )
11809 {
11810 SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons0));
11812
11813 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11815
11817 ++(*ndelconss);
11818 break;
11819 }
11820 }
11821
11822 return SCIP_OKAY;
11823}
11824
11825/** helper function to enforce constraints */
11826static
11828 SCIP* scip, /**< SCIP data structure */
11829 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11830 SCIP_CONS** conss, /**< constraints to process */
11831 int nconss, /**< number of constraints */
11832 int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
11833 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
11834 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
11835 )
11836{
11837 SCIP_CONSHDLRDATA* conshdlrdata;
11838 SCIP_Bool violated;
11839 SCIP_Bool cutoff = FALSE;
11840 int maxncuts;
11841 int ncuts = 0;
11842 int i;
11843
11845
11846 SCIPdebugMsg(scip, "knapsack enforcement of %d/%d constraints for %s solution\n", nusefulconss, nconss,
11847 sol == NULL ? "LP" : "relaxation");
11848
11849 /* get maximal number of cuts per round */
11850 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11851 assert(conshdlrdata != NULL);
11852 maxncuts = (SCIPgetDepth(scip) == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
11853
11854 /* search for violated useful knapsack constraints */
11855 for( i = 0; i < nusefulconss && ncuts < maxncuts && ! cutoff; i++ )
11856 {
11857 SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11858 if( violated )
11859 {
11860 /* add knapsack constraint as LP row to the relaxation */
11861 SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11862 ncuts++;
11863 }
11864 }
11865
11866 /* as long as no violations were found, search for violated obsolete knapsack constraints */
11867 for( i = nusefulconss; i < nconss && ncuts == 0 && ! cutoff; i++ )
11868 {
11869 SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11870 if( violated )
11871 {
11872 /* add knapsack constraint as LP row to the relaxation */
11873 SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11874 ncuts++;
11875 }
11876 }
11877
11878 /* adjust the result code */
11879 if ( cutoff )
11881 else if ( ncuts > 0 )
11883
11884 return SCIP_OKAY;
11885}
11886
11887/*
11888 * Linear constraint upgrading
11889 */
11890
11891/** creates and captures a knapsack constraint out of a linear inequality */
11892static
11894 SCIP* scip, /**< SCIP data structure */
11895 SCIP_CONS** cons, /**< pointer to hold the created constraint */
11896 const char* name, /**< name of constraint */
11897 int nvars, /**< number of variables in the constraint */
11898 SCIP_VAR** vars, /**< array with variables of constraint entries */
11899 SCIP_Real* vals, /**< array with inequality coefficients */
11900 SCIP_Real lhs, /**< left hand side of inequality */
11901 SCIP_Real rhs, /**< right hand side of inequality */
11902 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11903 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11904 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11905 * Usually set to TRUE. */
11906 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11907 * TRUE for model constraints, FALSE for additional, redundant constraints. */
11908 SCIP_Bool check, /**< should the constraint be checked for feasibility?
11909 * TRUE for model constraints, FALSE for additional, redundant constraints. */
11910 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11911 * Usually set to TRUE. */
11912 SCIP_Bool local, /**< is constraint only valid locally?
11913 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11914 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11915 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11916 * adds coefficients to this constraint. */
11917 SCIP_Bool dynamic, /**< is constraint subject to aging?
11918 * Usually set to FALSE. Set to TRUE for own cuts which
11919 * are separated as constraints. */
11920 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
11921 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11922 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
11923 * if it may be moved to a more global node?
11924 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
11925 )
11926{
11928 SCIP_Longint* weights;
11929 SCIP_Longint capacity;
11930 SCIP_Longint weight;
11931 int mult;
11932 int v;
11933
11934 assert(nvars == 0 || vars != NULL);
11935 assert(nvars == 0 || vals != NULL);
11936 assert(SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11937
11938 /* get temporary memory */
11941
11942 /* if the right hand side is non-infinite, we have to negate all variables with negative coefficient;
11943 * otherwise, we have to negate all variables with positive coefficient and multiply the row with -1
11944 */
11945 if( SCIPisInfinity(scip, rhs) )
11946 {
11947 mult = -1;
11948 capacity = (SCIP_Longint)SCIPfeasFloor(scip, -lhs);
11949 }
11950 else
11951 {
11952 mult = +1;
11953 capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
11954 }
11955
11956 /* negate positive or negative variables */
11957 for( v = 0; v < nvars; ++v )
11958 {
11959 assert(SCIPisFeasIntegral(scip, vals[v]));
11960 weight = mult * (SCIP_Longint)SCIPfeasFloor(scip, vals[v]);
11961 if( weight > 0 )
11962 {
11963 transvars[v] = vars[v];
11964 weights[v] = weight;
11965 }
11966 else
11967 {
11969 weights[v] = -weight; /*lint !e2704*/
11970 capacity -= weight;
11971 }
11972 assert(transvars[v] != NULL);
11973 }
11974
11975 /* create the constraint */
11976 SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, transvars, weights, capacity,
11977 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
11978
11979 /* free temporary memory */
11980 SCIPfreeBufferArray(scip, &weights);
11982
11983 return SCIP_OKAY;
11984}
11985
11986/** tries to upgrade a linear constraint into a knapsack constraint */
11987static
11989{ /*lint --e{715}*/
11990 SCIP_Bool upgrade;
11991
11992 assert(upgdcons != NULL);
11993
11994 /* check, if linear constraint can be upgraded to a knapsack constraint
11995 * - all variables must be binary
11996 * - all coefficients must be integral
11997 * - exactly one of the sides must be infinite
11998 * note that this includes the case of negative capacity, which has been
11999 * observed to occur, e.g., when upgrading a conflict constraint
12000 */
12003 && (SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
12004
12005 if( upgrade )
12006 {
12007 SCIPdebugMsg(scip, "upgrading constraint <%s> to knapsack constraint\n", SCIPconsGetName(cons));
12008
12009 /* create the knapsack constraint (an automatically upgraded constraint is always unmodifiable) */
12016 }
12017
12018 return SCIP_OKAY;
12019}
12020
12021/** adds symmetry information of constraint to a symmetry detection graph */
12022static
12024 SCIP* scip, /**< SCIP pointer */
12025 SYM_SYMTYPE symtype, /**< type of symmetries that need to be added */
12026 SCIP_CONS* cons, /**< constraint */
12027 SYM_GRAPH* graph, /**< symmetry detection graph */
12028 SCIP_Bool* success /**< pointer to store whether symmetry information could be added */
12029 )
12030{
12031 SCIP_CONSDATA* consdata;
12032 SCIP_VAR** vars;
12033 SCIP_Real* vals;
12034 SCIP_Real constant = 0.0;
12035 SCIP_Real rhs;
12036 int nlocvars;
12037 int nvars;
12038 int i;
12039
12040 assert(scip != NULL);
12041 assert(cons != NULL);
12042 assert(graph != NULL);
12043 assert(success != NULL);
12044
12045 consdata = SCIPconsGetData(cons);
12046 assert(consdata != NULL);
12047 assert(graph != NULL);
12048
12049 /* get active variables of the constraint */
12051 nlocvars = consdata->nvars;
12052
12055
12056 for( i = 0; i < consdata->nvars; ++i )
12057 {
12058 vars[i] = consdata->vars[i];
12059 vals[i] = (SCIP_Real) consdata->weights[i];
12060 }
12061
12062 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &vars, &vals, &nlocvars, &constant, SCIPisTransformed(scip)) );
12063 rhs = (SCIP_Real) SCIPgetCapacityKnapsack(scip, cons) - constant;
12064
12066 cons, -SCIPinfinity(scip), rhs, success) );
12067
12068 SCIPfreeBufferArray(scip, &vals);
12070
12071 return SCIP_OKAY;
12072}
12073
12074/*
12075 * Callback methods of constraint handler
12076 */
12077
12078/** copy method for constraint handler plugins (called when SCIP copies plugins) */
12079/**! [SnippetConsCopyKnapsack] */
12080static
12082{ /*lint --e{715}*/
12083 assert(scip != NULL);
12084 assert(conshdlr != NULL);
12086
12087 /* call inclusion method of constraint handler */
12089
12090 *valid = TRUE;
12091
12092 return SCIP_OKAY;
12093}
12094/**! [SnippetConsCopyKnapsack] */
12095
12096/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12097/**! [SnippetConsFreeKnapsack] */
12098static
12100{ /*lint --e{715}*/
12101 SCIP_CONSHDLRDATA* conshdlrdata;
12102
12103 /* free constraint handler data */
12104 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12105 assert(conshdlrdata != NULL);
12106
12107 SCIPfreeBlockMemory(scip, &conshdlrdata);
12108
12109 SCIPconshdlrSetData(conshdlr, NULL);
12110
12111 return SCIP_OKAY;
12112}
12113/**! [SnippetConsFreeKnapsack] */
12114
12115
12116/** initialization method of constraint handler (called after problem was transformed) */
12117static
12119{ /*lint --e{715}*/
12120 SCIP_CONSHDLRDATA* conshdlrdata;
12121 int nvars;
12122
12123 assert( scip != NULL );
12124 assert( conshdlr != NULL );
12125
12126 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12127 assert(conshdlrdata != NULL);
12128
12129 /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12131
12132 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->reals1, nvars) );
12133 conshdlrdata->reals1size = nvars;
12134
12135 return SCIP_OKAY;
12136}
12137
12138/** deinitialization method of constraint handler (called before transformed problem is freed) */
12139static
12141{ /*lint --e{715}*/
12142 SCIP_CONSHDLRDATA* conshdlrdata;
12143
12144 assert( scip != NULL );
12145 assert( conshdlr != NULL );
12146
12147 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12148 assert(conshdlrdata != NULL);
12149
12150 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->reals1, conshdlrdata->reals1size);
12151 conshdlrdata->reals1size = 0;
12152
12153 return SCIP_OKAY;
12154}
12155
12156
12157/** presolving initialization method of constraint handler (called when presolving is about to begin) */
12158static
12160{ /*lint --e{715}*/
12161 SCIP_CONSHDLRDATA* conshdlrdata;
12162 int nvars;
12163
12164 assert(scip != NULL);
12165 assert(conshdlr != NULL);
12166 assert(nconss == 0 || conss != NULL);
12167
12168 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12169 assert(conshdlrdata != NULL);
12170
12171 /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12173
12174 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints1, nvars) );
12175 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints2, nvars) );
12176 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints1, nvars) );
12177 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints2, nvars) );
12178 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools1, nvars) );
12179 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools2, nvars) );
12180 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools3, nvars) );
12181 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools4, nvars) );
12182
12183 conshdlrdata->ints1size = nvars;
12184 conshdlrdata->ints2size = nvars;
12185 conshdlrdata->longints1size = nvars;
12186 conshdlrdata->longints2size = nvars;
12187 conshdlrdata->bools1size = nvars;
12188 conshdlrdata->bools2size = nvars;
12189 conshdlrdata->bools3size = nvars;
12190 conshdlrdata->bools4size = nvars;
12191
12192#ifdef WITH_CARDINALITY_UPGRADE
12193 conshdlrdata->upgradedcard = FALSE;
12194#endif
12195
12196 return SCIP_OKAY;
12197}
12198
12199
12200/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12201static
12203{ /*lint --e{715}*/
12204 SCIP_CONSHDLRDATA* conshdlrdata;
12205 int c;
12206
12207 assert(scip != NULL);
12208 assert(conshdlr != NULL);
12209
12210 for( c = 0; c < nconss; ++c )
12211 {
12212 if( !SCIPconsIsDeleted(conss[c]) )
12213 {
12214 /* since we are not allowed to detect infeasibility in the exitpre stage, we dont give an infeasible pointer */
12215 SCIP_CALL( applyFixings(scip, conss[c], NULL) );
12216 }
12217 }
12218
12219 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12220 assert(conshdlrdata != NULL);
12221
12222 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints1, conshdlrdata->ints1size);
12223 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints2, conshdlrdata->ints2size);
12224 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints1, conshdlrdata->longints1size);
12225 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints2, conshdlrdata->longints2size);
12226 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools1, conshdlrdata->bools1size);
12227 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools2, conshdlrdata->bools2size);
12228 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools3, conshdlrdata->bools3size);
12229 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools4, conshdlrdata->bools4size);
12230
12231 conshdlrdata->ints1size = 0;
12232 conshdlrdata->ints2size = 0;
12233 conshdlrdata->longints1size = 0;
12234 conshdlrdata->longints2size = 0;
12235 conshdlrdata->bools1size = 0;
12236 conshdlrdata->bools2size = 0;
12237 conshdlrdata->bools3size = 0;
12238 conshdlrdata->bools4size = 0;
12239
12240 return SCIP_OKAY;
12241}
12242
12243/** solving process initialization method of constraint handler */
12244static
12246{ /*lint --e{715}*/
12247 /* add nlrow representation to NLP, if NLP had been constructed */
12249 {
12250 int c;
12251 for( c = 0; c < nconss; ++c )
12252 {
12253 SCIP_CALL( addNlrow(scip, conss[c]) );
12254 }
12255 }
12256
12257 return SCIP_OKAY;
12258}
12259
12260/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12261static
12263{ /*lint --e{715}*/
12264 SCIP_CONSDATA* consdata;
12265 int c;
12266
12267 assert( scip != NULL );
12268
12269 /* release the rows and nlrows of all constraints */
12270 for( c = 0; c < nconss; ++c )
12271 {
12272 consdata = SCIPconsGetData(conss[c]);
12273 assert(consdata != NULL);
12274
12275 if( consdata->row != NULL )
12276 {
12277 SCIP_CALL( SCIPreleaseRow(scip, &consdata->row) );
12278 }
12279
12280 if( consdata->nlrow != NULL )
12281 {
12282 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
12283 }
12284 }
12285
12286 return SCIP_OKAY;
12287}
12288
12289/** frees specific constraint data */
12290static
12292{ /*lint --e{715}*/
12293 SCIP_CONSHDLRDATA* conshdlrdata;
12294
12295 assert(conshdlr != NULL);
12297
12298 /* get event handler */
12299 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12300 assert(conshdlrdata != NULL);
12301 assert(conshdlrdata->eventhdlr != NULL);
12302
12303 /* free knapsack constraint */
12304 SCIP_CALL( consdataFree(scip, consdata, conshdlrdata->eventhdlr) );
12305
12306 return SCIP_OKAY;
12307}
12308
12309/** transforms constraint data into data belonging to the transformed problem */
12310/**! [SnippetConsTransKnapsack]*/
12311static
12313{ /*lint --e{715}*/
12314 SCIP_CONSHDLRDATA* conshdlrdata;
12317
12318 assert(conshdlr != NULL);
12323
12326 assert(sourcedata->row == NULL); /* in original problem, there cannot be LP rows */
12327
12328 /* get event handler */
12329 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12330 assert(conshdlrdata != NULL);
12331 assert(conshdlrdata->eventhdlr != NULL);
12332
12333 /* create target constraint data */
12335 sourcedata->nvars, sourcedata->vars, sourcedata->weights, sourcedata->capacity) );
12336
12337 /* create target constraint */
12343
12344 /* catch events for variables */
12345 SCIP_CALL( catchEvents(scip, *targetcons, targetdata, conshdlrdata->eventhdlr) );
12346
12347 return SCIP_OKAY;
12348}
12349/**! [SnippetConsTransKnapsack]*/
12350
12351/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
12352static
12354{ /*lint --e{715}*/
12355 int i;
12356
12357 *infeasible = FALSE;
12358
12359 for( i = 0; i < nconss && !(*infeasible); i++ )
12360 {
12361 assert(SCIPconsIsInitial(conss[i]));
12362 SCIP_CALL( addRelaxation(scip, conss[i], infeasible) );
12363 }
12364
12365 return SCIP_OKAY;
12366}
12367
12368/** separation method of constraint handler for LP solutions */
12369static
12371{ /*lint --e{715}*/
12372 SCIP_CONSHDLRDATA* conshdlrdata;
12373 SCIP_Bool sepacardinality;
12374 SCIP_Bool cutoff;
12375
12376 SCIP_Real loclowerbound;
12377 SCIP_Real glblowerbound;
12378 SCIP_Real cutoffbound;
12379 SCIP_Real maxbound;
12380
12381 int depth;
12382 int nrounds;
12383 int sepafreq;
12384 int sepacardfreq;
12385 int ncuts;
12386 int maxsepacuts;
12387 int i;
12388
12390
12391 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12392 assert(conshdlrdata != NULL);
12393
12396
12397 SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12398 nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12399
12400 /* only call the separator a given number of times at each node */
12401 if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12402 || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12403 return SCIP_OKAY;
12404
12405 /* check, if we should additionally separate knapsack cuts */
12406 sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12407 sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12408 sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12409 && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12410
12411 /* check dual bound to see if we want to produce knapsack cuts at this node */
12414 cutoffbound = SCIPgetCutoffbound(scip);
12415 maxbound = glblowerbound + conshdlrdata->maxcardbounddist * (cutoffbound - glblowerbound);
12418
12419 /* get the maximal number of cuts allowed in a separation round */
12420 maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12421
12423 ncuts = 0;
12424 cutoff = FALSE;
12425
12426 /* separate useful constraints */
12427 for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12428 {
12429 SCIP_CALL( separateCons(scip, conss[i], NULL, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12430 }
12431
12432 /* adjust return value */
12433 if ( cutoff )
12435 else if ( ncuts > 0 )
12437
12438 return SCIP_OKAY;
12439}
12440
12441
12442/** separation method of constraint handler for arbitrary primal solutions */
12443static
12445{ /*lint --e{715}*/
12446 SCIP_CONSHDLRDATA* conshdlrdata;
12447 SCIP_Bool sepacardinality;
12448 SCIP_Bool cutoff;
12449
12450 int depth;
12451 int nrounds;
12452 int sepafreq;
12453 int sepacardfreq;
12454 int ncuts;
12455 int maxsepacuts;
12456 int i;
12457
12459
12460 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12461 assert(conshdlrdata != NULL);
12462
12465
12466 SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12467 nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12468
12469 /* only call the separator a given number of times at each node */
12470 if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12471 || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12472 return SCIP_OKAY;
12473
12474 /* check, if we should additionally separate knapsack cuts */
12475 sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12476 sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12477 sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12478 && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12479
12480 /* get the maximal number of cuts allowed in a separation round */
12481 maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12482
12484 ncuts = 0;
12485 cutoff = FALSE;
12486
12487 /* separate useful constraints */
12488 for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12489 {
12490 SCIP_CALL( separateCons(scip, conss[i], sol, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12491 }
12492
12493 /* adjust return value */
12494 if ( cutoff )
12496 else if( ncuts > 0 )
12498
12499 return SCIP_OKAY;
12500}
12501
12502/** constraint enforcing method of constraint handler for LP solutions */
12503static
12505{ /*lint --e{715}*/
12506 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, result) );
12507
12508 return SCIP_OKAY;
12509}
12510
12511/** constraint enforcing method of constraint handler for relaxation solutions */
12512static
12514{ /*lint --e{715}*/
12515 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, result) );
12516
12517 return SCIP_OKAY;
12518}
12519
12520/** constraint enforcing method of constraint handler for pseudo solutions */
12521static
12523{ /*lint --e{715}*/
12524 SCIP_Bool violated;
12525 int i;
12526
12527 for( i = 0; i < nconss; i++ )
12528 {
12529 SCIP_CALL( checkCons(scip, conss[i], NULL, TRUE, FALSE, &violated) );
12530 if( violated )
12531 {
12533 return SCIP_OKAY;
12534 }
12535 }
12537
12538 return SCIP_OKAY;
12539}
12540
12541/** feasibility check method of constraint handler for integral solutions */
12542static
12544{ /*lint --e{715}*/
12545 SCIP_Bool violated;
12546 int i;
12547
12549
12550 for( i = 0; i < nconss && (*result == SCIP_FEASIBLE || completely); i++ )
12551 {
12552 SCIP_CALL( checkCons(scip, conss[i], sol, checklprows, printreason, &violated) );
12553 if( violated )
12555 }
12556
12557 return SCIP_OKAY;
12558}
12559
12560/** domain propagation method of constraint handler */
12561static
12563{ /*lint --e{715}*/
12564 SCIP_CONSHDLRDATA* conshdlrdata;
12565 SCIP_Bool cutoff;
12566 SCIP_Bool redundant;
12567 SCIP_Bool inpresolve;
12568 int nfixedvars;
12569 int i;
12570
12571 cutoff = FALSE;
12572 nfixedvars = 0;
12573
12574 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12575 assert(conshdlrdata != NULL);
12576
12579
12580 /* process useful constraints */
12581 for( i = 0; i < nmarkedconss && !cutoff; i++ )
12582 {
12583 /* do not propagate constraints with multi-aggregated variables, which should only happen in probing mode,
12584 * otherwise the multi-aggregation should be resolved
12585 */
12586 if( inpresolve && SCIPconsGetData(conss[i])->existmultaggr )
12587 continue;
12588#ifndef NDEBUG
12589 else
12590 assert(!(SCIPconsGetData(conss[i])->existmultaggr));
12591#endif
12592
12593 SCIP_CALL( propagateCons(scip, conss[i], &cutoff, &redundant, &nfixedvars, conshdlrdata->negatedclique) );
12594
12595 /* unmark the constraint to be propagated */
12597 }
12598
12599 /* adjust result code */
12600 if( cutoff )
12602 else if( nfixedvars > 0 )
12604 else
12606
12607 return SCIP_OKAY; /*lint !e438*/
12608}
12609
12610/** presolving method of constraint handler */
12611static
12613{ /*lint --e{574,715}*/
12614 SCIP_CONSHDLRDATA* conshdlrdata;
12615 SCIP_CONSDATA* consdata;
12616 SCIP_CONS* cons;
12617 SCIP_Bool cutoff;
12618 SCIP_Bool redundant;
12619 SCIP_Bool success;
12620 int oldnfixedvars;
12621 int oldnchgbds;
12622 int oldndelconss;
12623 int oldnaddconss;
12624 int oldnchgcoefs;
12625 int oldnchgsides;
12626 int firstchange;
12627 int c;
12628 SCIP_Bool newchanges;
12629
12630 /* remember old preprocessing counters */
12631 cutoff = FALSE;
12632 oldnfixedvars = *nfixedvars;
12633 oldnchgbds = *nchgbds;
12634 oldndelconss = *ndelconss;
12635 oldnaddconss = *naddconss;
12636 oldnchgcoefs = *nchgcoefs;
12637 oldnchgsides = *nchgsides;
12639
12640 newchanges = (nrounds == 0 || nnewfixedvars > 0 || nnewaggrvars > 0 || nnewchgbds > 0 || nnewupgdconss > 0);
12641
12642 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12643 assert(conshdlrdata != NULL);
12644
12645 for( c = 0; c < nconss && !SCIPisStopped(scip); c++ )
12646 {
12647 int thisnfixedvars;
12648 int thisnchgbds;
12649
12650 cons = conss[c];
12651 consdata = SCIPconsGetData(cons);
12652 assert(consdata != NULL);
12653
12654 /* update data structures */
12655 /* todo if UBTIGHTENED events were caught, we could move this block after the continue */
12656 if( newchanges || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12657 {
12658 SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12659 if( cutoff )
12660 break;
12661 }
12662
12663 /* force presolving the constraint in the initial round */
12664 if( nrounds == 0 )
12665 consdata->presolvedtiming = 0;
12666 else if( consdata->presolvedtiming >= presoltiming )
12667 continue;
12668
12669 SCIPdebugMsg(scip, "presolving knapsack constraint <%s>\n", SCIPconsGetName(cons));
12671 consdata->presolvedtiming = presoltiming;
12672
12673 thisnfixedvars = *nfixedvars;
12674 thisnchgbds = *nchgbds;
12675
12676 /* merge constraint, so propagation works better */
12677 SCIP_CALL( mergeMultiples(scip, cons, &cutoff) );
12678 if( cutoff )
12679 break;
12680
12681 /* add cliques in the knapsack to the clique table */
12682 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12683 {
12684 SCIP_CALL( addCliques(scip, cons, conshdlrdata->cliqueextractfactor, &cutoff, nchgbds) );
12685 if( cutoff )
12686 break;
12687 }
12688
12689 /* propagate constraint */
12690 if( presoltiming < SCIP_PRESOLTIMING_EXHAUSTIVE )
12691 {
12692 SCIP_CALL( propagateCons(scip, cons, &cutoff, &redundant, nfixedvars, (presoltiming & SCIP_PRESOLTIMING_MEDIUM)) );
12693
12694 if( cutoff )
12695 break;
12696 if( redundant )
12697 {
12698 (*ndelconss)++;
12699 continue;
12700 }
12701 }
12702
12703 /* remove again all fixed variables, if further fixings were found */
12704 if( *nfixedvars > thisnfixedvars || *nchgbds > thisnchgbds )
12705 {
12706 SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12707 if( cutoff )
12708 break;
12709
12710 thisnfixedvars = *nfixedvars;
12711 }
12712
12713 if( !SCIPconsIsModifiable(cons) )
12714 {
12715 /* check again for redundancy (applyFixings() might have decreased weightsum due to fixed-to-zero vars) */
12716 if( consdata->weightsum <= consdata->capacity )
12717 {
12718 SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
12719 SCIPconsGetName(cons), consdata->weightsum, consdata->capacity);
12721 continue;
12722 }
12723
12724 /* divide weights by their greatest common divisor */
12725 normalizeWeights(cons, nchgcoefs, nchgsides);
12726
12727 /* try to simplify inequalities */
12728 if( conshdlrdata->simplifyinequalities && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
12729 {
12730 SCIP_CALL( simplifyInequalities(scip, cons, nfixedvars, ndelconss, nchgcoefs, nchgsides, naddconss, &cutoff) );
12731 if( cutoff )
12732 break;
12733
12734 if( SCIPconsIsDeleted(cons) )
12735 continue;
12736
12737 /* remove again all fixed variables, if further fixings were found */
12738 if( *nfixedvars > thisnfixedvars )
12739 {
12741 if( cutoff )
12742 break;
12743 }
12744 }
12745
12746 /* tighten capacity and weights */
12747 SCIP_CALL( tightenWeights(scip, cons, presoltiming, nchgcoefs, nchgsides, naddconss, ndelconss, &cutoff) );
12748 if( cutoff )
12749 break;
12750
12751 if( SCIPconsIsActive(cons) )
12752 {
12753 if( conshdlrdata->dualpresolving && SCIPallowStrongDualReds(scip) && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12754 {
12755 /* in case the knapsack constraints is independent of everything else, solve the knapsack and apply the
12756 * dual reduction
12757 */
12758 SCIP_CALL( dualPresolving(scip, cons, nchgbds, ndelconss, &redundant) );
12759 if( redundant )
12760 continue;
12761 }
12762
12763 /* check if knapsack constraint is parallel to objective function */
12764 SCIP_CALL( checkParallelObjective(scip, cons, conshdlrdata) );
12765 }
12766 }
12767 /* remember the first changed constraint to begin the next aggregation round with */
12768 if( firstchange == INT_MAX && consdata->presolvedtiming != SCIP_PRESOLTIMING_EXHAUSTIVE )
12769 firstchange = c;
12770 }
12771
12772 /* preprocess pairs of knapsack constraints */
12773 if( !cutoff && conshdlrdata->presolusehashing && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12774 {
12775 /* detect redundant constraints; fast version with hash table instead of pairwise comparison */
12776 SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &cutoff, ndelconss) );
12777 }
12778
12779 if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) || (*naddconss != oldnaddconss) )
12780 success = TRUE;
12781 else
12782 success = FALSE;
12783
12784 if( !cutoff && firstchange < nconss && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
12785 {
12786 SCIP_Longint npaircomparisons;
12787
12788 npaircomparisons = 0;
12789 oldndelconss = *ndelconss;
12790 oldnchgsides = *nchgsides;
12791 oldnchgcoefs = *nchgcoefs;
12792
12793 for( c = firstchange; c < nconss && !cutoff && !SCIPisStopped(scip); ++c )
12794 {
12795 cons = conss[c];
12796 if( !SCIPconsIsActive(cons) || SCIPconsIsModifiable(cons) )
12797 continue;
12798
12799 npaircomparisons += ((SCIPconsGetData(cons)->presolvedtiming < SCIP_PRESOLTIMING_EXHAUSTIVE) ? (SCIP_Longint) c : ((SCIP_Longint) c - (SCIP_Longint) firstchange));
12800
12801 SCIP_CALL( preprocessConstraintPairs(scip, conss, firstchange, c, ndelconss) );
12802
12804 {
12805 if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) )
12806 success = TRUE;
12807 if( ((SCIP_Real) (*ndelconss - oldndelconss) + ((SCIP_Real) (*nchgsides - oldnchgsides))/2.0 +
12808 ((SCIP_Real) (*nchgcoefs - oldnchgcoefs))/10.0) / ((SCIP_Real) npaircomparisons) < MINGAINPERNMINCOMPARISONS )
12809 break;
12810 oldndelconss = *ndelconss;
12811 oldnchgsides = *nchgsides;
12812 oldnchgcoefs = *nchgcoefs;
12813 npaircomparisons = 0;
12814 }
12815 }
12816 }
12817#ifdef WITH_CARDINALITY_UPGRADE
12818 /* @todo upgrade to cardinality constraints: the code below relies on disabling the checking of the knapsack
12819 * constraint in the original problem, because the upgrade ensures that at most the given number of continuous
12820 * variables has a nonzero value, but not that the binary variables corresponding to the continuous variables with
12821 * value zero are set to zero as well. This can cause problems if the user accesses the values of the binary
12822 * variables (as the MIPLIB solution checker does), or the transformed problem is freed and the original problem
12823 * (possibly with some user modifications) is re-optimized. Until there is a way to force the binary variables to 0
12824 * as well, we better keep this code disabled. */
12825 /* upgrade to cardinality constraints - only try to upgrade towards the end of presolving, since the process below is quite expensive */
12826 if ( ! cutoff && conshdlrdata->upgdcardinality && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 && SCIPisPresolveFinished(scip) && ! conshdlrdata->upgradedcard )
12827 {
12828 SCIP_HASHMAP* varhash;
12830 SCIP_Real* cardweights;
12831 int noldupgdconss;
12832 int nscipvars;
12833 int makeupgrade;
12834
12835 noldupgdconss = *nupgdconss;
12839
12840 /* set up hash map */
12842
12843 /* We loop through all cardinality constraints twice:
12844 * - First, determine for each binary variable the number of cardinality constraints that can be upgraded to a
12845 * knapsack constraint and contain this variable; this number has to coincide with the number of variable up
12846 * locks; otherwise it would be infeasible to delete the knapsack constraints after the constraint update.
12847 * - Second, upgrade knapsack constraints to cardinality constraints. */
12848 for (makeupgrade = 0; makeupgrade < 2; ++makeupgrade)
12849 {
12850 for (c = nconss-1; c >= 0 && ! SCIPisStopped(scip); --c)
12851 {
12853 SCIP_VAR** vars;
12854 SCIP_Longint* weights;
12855 int nvars;
12856 int v;
12857
12858 cons = conss[c];
12859 assert( cons != NULL );
12860 consdata = SCIPconsGetData(cons);
12861 assert( consdata != NULL );
12862
12863 nvars = consdata->nvars;
12864 vars = consdata->vars;
12865 weights = consdata->weights;
12866
12867 /* Check, whether linear knapsack can be upgraded to a cardinality constraint:
12868 * - all variables must be binary (always true)
12869 * - all coefficients must be 1.0
12870 * - the right hand side must be smaller than nvars
12871 */
12872 if ( consdata->capacity >= nvars )
12873 continue;
12874
12875 /* the weights are sorted: check first and last weight */
12876 assert( consdata->sorted );
12877 if ( weights[0] != 1 || weights[nvars-1] != 1 )
12878 continue;
12879
12880 /* check whether all variables are of the form 0 <= x_v <= u_v y_v for y_v \in \{0,1\} and zero objective */
12881 for (v = 0; v < nvars; ++v)
12882 {
12884 SCIP_Real* implbounds;
12886 SCIP_VAR* var;
12887 int nimpls;
12888 int j;
12889
12890 var = consdata->vars[v];
12891 assert( var != NULL );
12893
12894 /* ignore non-active variables */
12895 if ( ! SCIPvarIsActive(var) )
12896 break;
12897
12898 /* be sure that implication variable has zero objective */
12899 if ( ! SCIPisZero(scip, SCIPvarGetObj(var)) )
12900 break;
12901
12902 nimpls = SCIPvarGetNImpls(var, FALSE);
12906
12907 for (j = 0; j < nimpls; ++j)
12908 {
12909 /* be sure that continuous variable is fixed to 0 */
12911 continue;
12912
12913 /* cannot currently deal with nonzero fixings */
12914 if ( ! SCIPisZero(scip, implbounds[j]) )
12915 continue;
12916
12917 /* number of down locks should be one */
12919 continue;
12920
12921 cardvars[v] = implvars[j];
12922 cardweights[v] = (SCIP_Real) v;
12923
12924 break;
12925 }
12926
12927 /* found no variable upper bound candidate -> exit */
12928 if ( j >= nimpls )
12929 break;
12930 }
12931
12932 /* did not find fitting variable upper bound for some variable -> exit */
12933 if ( v < nvars )
12934 break;
12935
12936 /* save number of knapsack constraints that can be upgraded to a cardinality constraint,
12937 * in which the binary variable is involved in */
12938 if ( makeupgrade == 0 )
12939 {
12940 for (v = 0; v < nvars; ++v)
12941 {
12942 if ( SCIPhashmapExists(varhash, vars[v]) )
12943 {
12944 int image;
12945
12946 image = SCIPhashmapGetImageInt(varhash, vars[v]);
12947 SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image + 1) );
12948 assert( image + 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12949 }
12950 else
12951 {
12952 SCIP_CALL( SCIPhashmapInsertInt(varhash, vars[v], 1) );
12953 assert( 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12954 assert( SCIPhashmapExists(varhash, vars[v]) );
12955 }
12956 }
12957 }
12958 else
12959 {
12960 SCIP_CONS* origcons;
12961
12962 /* for each variable: check whether the number of cardinality constraints that can be upgraded to a
12963 * knapsack constraint coincides with the number of variable up locks */
12964 for (v = 0; v < nvars; ++v)
12965 {
12966 assert( SCIPhashmapExists(varhash, vars[v]) );
12968 break;
12969 }
12970 if ( v < nvars )
12971 break;
12972
12973 /* store that we have upgraded */
12974 conshdlrdata->upgradedcard = TRUE;
12975
12976 /* at this point we found suitable variable upper bounds */
12977 SCIPdebugMessage("Upgrading knapsack constraint <%s> to cardinality constraint ...\n", SCIPconsGetName(cons));
12978
12979 /* create cardinality constraint */
12980 assert( ! SCIPconsIsModifiable(cons) );
12985#ifdef SCIP_DEBUG
12986 SCIPprintCons(scip, cons, NULL);
12987 SCIPinfoMessage(scip, NULL, "\n");
12989 SCIPinfoMessage(scip, NULL, "\n");
12990#endif
12993 ++(*nupgdconss);
12994
12995 /* delete oknapsack constraint */
12996 SCIP_CALL( SCIPdelCons(scip, cons) );
12997 ++(*ndelconss);
12998
12999 /* We need to disable the original knapsack constraint, since it might happen that the binary variables
13000 * are 1 although the continuous variables are 0. Thus, the knapsack constraint might be violated,
13001 * although the cardinality constraint is satisfied. */
13002 origcons = SCIPfindOrigCons(scip, SCIPconsGetName(cons));
13003 assert( origcons != NULL );
13004 SCIP_CALL( SCIPsetConsChecked(scip, origcons, FALSE) );
13005
13006 for (v = 0; v < nvars; ++v)
13007 {
13008 int image;
13009
13010 assert ( SCIPhashmapExists(varhash, vars[v]) );
13011 image = SCIPhashmapGetImageInt(varhash, vars[v]);
13012 SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image - 1) );
13013 assert( image - 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
13014 }
13015 }
13016 }
13017 }
13018 SCIPhashmapFree(&varhash);
13021
13022 if ( *nupgdconss > noldupgdconss )
13023 success = TRUE;
13024 }
13025#endif
13026
13027 if( cutoff )
13029 else if( success || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
13031 else
13033
13034 return SCIP_OKAY;
13035}
13036
13037/** propagation conflict resolving method of constraint handler */
13038static
13040{ /*lint --e{715}*/
13041 SCIP_CONSDATA* consdata;
13042 SCIP_Longint capsum;
13043 int i;
13044
13045 assert(result != NULL);
13046
13047 consdata = SCIPconsGetData(cons);
13048 assert(consdata != NULL);
13049
13050 /* check if we fixed a binary variable to one (due to negated clique) */
13051 if( inferinfo >= 0 && SCIPvarGetLbLocal(infervar) > 0.5 )
13052 {
13053 for( i = 0; i < consdata->nvars; ++i )
13054 {
13055 if( SCIPvarGetIndex(consdata->vars[i]) == inferinfo )
13056 {
13057 assert( SCIPgetVarUbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) < 0.5 );
13058 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
13059 break;
13060 }
13061 }
13063 }
13064 else
13065 {
13066 /* according to negated cliques the minweightsum and all variables which are fixed to one which led to a fixing of
13067 * another negated clique variable to one, the inferinfo was chosen to be the negative of the position in the
13068 * knapsack constraint, see one above call of SCIPinferBinvarCons
13069 */
13070 if( inferinfo < 0 )
13071 capsum = 0;
13072 else
13073 {
13074 /* locate the inference variable and calculate the capacity that has to be used up to conclude infervar == 0;
13075 * inferinfo stores the position of the inference variable (but maybe the variables were resorted)
13076 */
13077 if( inferinfo < consdata->nvars && consdata->vars[inferinfo] == infervar )
13078 capsum = consdata->weights[inferinfo];
13079 else
13080 {
13081 for( i = 0; i < consdata->nvars && consdata->vars[i] != infervar; ++i )
13082 {}
13084 capsum = consdata->weights[i];
13085 }
13086 }
13087
13088 /* add fixed-to-one variables up to the point, that their weight plus the weight of the conflict variable exceeds
13089 * the capacity
13090 */
13091 if( capsum <= consdata->capacity )
13092 {
13093 for( i = 0; i < consdata->nvars; i++ )
13094 {
13095 if( SCIPgetVarLbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) > 0.5 )
13096 {
13097 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
13098 capsum += consdata->weights[i];
13099 if( capsum > consdata->capacity )
13100 break;
13101 }
13102 }
13103 }
13104 }
13105
13106 /* NOTE: It might be the case that capsum < consdata->capacity. This is due the fact that the fixing of the variable
13107 * to zero can included negated clique information. A negated clique means, that at most one of the clique
13108 * variables can be zero. These information can be used to compute a minimum activity of the constraint and
13109 * used to fix variables to zero.
13110 *
13111 * Even if capsum < consdata->capacity we still reported a complete reason since the minimum activity is based
13112 * on global variable bounds. It might even be the case that we reported to many variables which are fixed to
13113 * one.
13114 */
13116
13117 return SCIP_OKAY;
13118}
13119
13120/** variable rounding lock method of constraint handler */
13121/**! [SnippetConsLockKnapsack] */
13122static
13124{ /*lint --e{715}*/
13125 SCIP_CONSDATA* consdata;
13126 int i;
13127
13128 consdata = SCIPconsGetData(cons);
13129 assert(consdata != NULL);
13130
13131 for( i = 0; i < consdata->nvars; i++)
13132 {
13133 SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlocksneg, nlockspos) );
13134 }
13135
13136 return SCIP_OKAY;
13137}
13138/**! [SnippetConsLockKnapsack] */
13139
13140/** constraint activation notification method of constraint handler */
13141static
13143{ /*lint --e{715}*/
13145 {
13146 SCIP_CALL( addNlrow(scip, cons) );
13147 }
13148
13149 return SCIP_OKAY;
13150}
13151
13152/** constraint deactivation notification method of constraint handler */
13153static
13155{ /*lint --e{715}*/
13156 SCIP_CONSDATA* consdata;
13157
13158 assert(cons != NULL);
13159
13160 consdata = SCIPconsGetData(cons);
13161 assert(consdata != NULL);
13162
13163 /* remove row from NLP, if still in solving
13164 * if we are in exitsolve, the whole NLP will be freed anyway
13165 */
13166 if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && consdata->nlrow != NULL )
13167 {
13168 SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
13169 }
13170
13171 return SCIP_OKAY;
13172}
13173
13174/** variable deletion method of constraint handler */
13175static
13177{
13178 assert(scip != NULL);
13179 assert(conshdlr != NULL);
13180 assert(conss != NULL || nconss == 0);
13181
13182 if( nconss > 0 )
13183 {
13184 SCIP_CALL( performVarDeletions(scip, conshdlr, conss, nconss) );
13185 }
13186
13187 return SCIP_OKAY;
13188}
13189
13190/** constraint display method of constraint handler */
13191static
13193{ /*lint --e{715}*/
13194 SCIP_CONSDATA* consdata;
13195 int i;
13196
13197 assert( scip != NULL );
13198 assert( conshdlr != NULL );
13199 assert( cons != NULL );
13200
13201 consdata = SCIPconsGetData(cons);
13202 assert(consdata != NULL);
13203
13204 for( i = 0; i < consdata->nvars; ++i )
13205 {
13206 if( i > 0 )
13207 SCIPinfoMessage(scip, file, " ");
13208 SCIPinfoMessage(scip, file, "%+" SCIP_LONGINT_FORMAT, consdata->weights[i]);
13209 SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[i], TRUE) );
13210 }
13211 SCIPinfoMessage(scip, file, " <= %" SCIP_LONGINT_FORMAT "", consdata->capacity);
13212
13213 return SCIP_OKAY;
13214}
13215
13216/** constraint copying method of constraint handler */
13217static
13219{ /*lint --e{715}*/
13221 SCIP_Longint* weights;
13222 SCIP_Real* coefs;
13223 const char* consname;
13224 int nvars;
13225 int v;
13226
13227 /* get variables and coefficients of the source constraint */
13229 nvars = SCIPgetNVarsKnapsack(sourcescip, sourcecons);
13230 weights = SCIPgetWeightsKnapsack(sourcescip, sourcecons);
13231
13233 for( v = 0; v < nvars; ++v )
13234 coefs[v] = (SCIP_Real) weights[v];
13235
13236 if( name != NULL )
13237 consname = name;
13238 else
13239 consname = SCIPconsGetName(sourcecons);
13240
13241 /* copy the logic using the linear constraint copy method */
13242 SCIP_CALL( SCIPcopyConsLinear(scip, cons, sourcescip, consname, nvars, sourcevars, coefs,
13243 -SCIPinfinity(scip), (SCIP_Real) SCIPgetCapacityKnapsack(sourcescip, sourcecons), varmap, consmap,
13244 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, global, valid) );
13245 assert(cons != NULL);
13246
13247 SCIPfreeBufferArray(scip, &coefs);
13248
13249 return SCIP_OKAY;
13250}
13251
13252/** constraint parsing method of constraint handler */
13253static
13255{ /*lint --e{715}*/
13256 SCIP_VAR* var;
13257 SCIP_Longint weight;
13258 SCIP_VAR** vars;
13259 SCIP_Longint* weights;
13260 SCIP_Longint capacity;
13261 char* endptr;
13262 int nread;
13263 int nvars;
13264 int varssize;
13265
13266 assert(scip != NULL);
13267 assert(success != NULL);
13268 assert(str != NULL);
13269 assert(name != NULL);
13270 assert(cons != NULL);
13271
13272 *success = TRUE;
13273
13274 nvars = 0;
13275 varssize = 5;
13276 SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13277 SCIP_CALL( SCIPallocBufferArray(scip, &weights, varssize) );
13278
13279 while( *str != '\0' )
13280 {
13281 /* try to parse coefficient, and use 1 if not successful */
13282 weight = 1;
13283 nread = 0;
13284 sscanf(str, "%" SCIP_LONGINT_FORMAT "%n", &weight, &nread);
13285 str += nread;
13286
13287 /* parse variable name */
13289
13290 if( var == NULL )
13291 {
13292 endptr = strchr(endptr, '<');
13293
13294 if( endptr == NULL )
13295 {
13296 SCIPerrorMessage("no capacity found\n");
13297 *success = FALSE;
13298 }
13299 else
13300 str = endptr;
13301
13302 break;
13303 }
13304
13305 str = endptr;
13306
13307 /* store weight and variable */
13308 if( varssize <= nvars )
13309 {
13310 varssize = SCIPcalcMemGrowSize(scip, varssize+1);
13311 SCIP_CALL( SCIPreallocBufferArray(scip, &vars, varssize) );
13312 SCIP_CALL( SCIPreallocBufferArray(scip, &weights, varssize) );
13313 }
13314
13315 vars[nvars] = var;
13316 weights[nvars] = weight;
13317 ++nvars;
13318
13319 /* skip whitespace */
13320 SCIP_CALL( SCIPskipSpace((char**)&str) );
13321 }
13322
13323 if( *success )
13324 {
13325 if( strncmp(str, "<=", 2) != 0 )
13326 {
13327 SCIPerrorMessage("expected '<=' at begin of '%s'\n", str);
13328 *success = FALSE;
13329 }
13330 else
13331 {
13332 str += 2;
13333 }
13334 }
13335
13336 if( *success )
13337 {
13338 /* skip whitespace */
13339 SCIP_CALL( SCIPskipSpace((char**)&str) );
13340
13341 /* coverity[secure_coding] */
13342 if( sscanf(str, "%" SCIP_LONGINT_FORMAT, &capacity) != 1 )
13343 {
13344 SCIPerrorMessage("error parsing capacity from '%s'\n", str);
13345 *success = FALSE;
13346 }
13347 else
13348 {
13349 SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13350 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13351 }
13352 }
13353
13355 SCIPfreeBufferArray(scip, &weights);
13356
13357 return SCIP_OKAY;
13358}
13359
13360/** constraint method of constraint handler which returns the variables (if possible) */
13361static
13363{ /*lint --e{715}*/
13364 SCIP_CONSDATA* consdata;
13365
13366 consdata = SCIPconsGetData(cons);
13367 assert(consdata != NULL);
13368
13370 (*success) = FALSE;
13371 else
13372 {
13373 assert(vars != NULL);
13374
13375 BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13376 (*success) = TRUE;
13377 }
13378
13379 return SCIP_OKAY;
13380}
13381
13382/** constraint method of constraint handler which returns the number of variables (if possible) */
13383static
13385{ /*lint --e{715}*/
13386 SCIP_CONSDATA* consdata;
13387
13388 consdata = SCIPconsGetData(cons);
13389 assert(consdata != NULL);
13390
13391 (*nvars) = consdata->nvars;
13392 (*success) = TRUE;
13393
13394 return SCIP_OKAY;
13395}
13396
13397/** constraint handler method which returns the permutation symmetry detection graph of a constraint */
13398static
13400{ /*lint --e{715}*/
13402
13403 return SCIP_OKAY;
13404}
13405
13406/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint */
13407static
13414
13415/*
13416 * Event handler
13417 */
13418
13419/** execution method of bound change event handler */
13420static
13422{ /*lint --e{715}*/
13423 SCIP_CONSDATA* consdata;
13424
13425 assert(eventdata != NULL);
13426 assert(eventdata->cons != NULL);
13427
13428 consdata = SCIPconsGetData(eventdata->cons);
13429 assert(consdata != NULL);
13430
13431 switch( SCIPeventGetType(event) )
13432 {
13434 consdata->onesweightsum += eventdata->weight;
13435 consdata->presolvedtiming = 0;
13436 SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13437 break;
13439 consdata->onesweightsum -= eventdata->weight;
13440 break;
13442 consdata->presolvedtiming = 0;
13443 SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13444 break;
13445 case SCIP_EVENTTYPE_VARFIXED: /* the variable should be removed from the constraint in presolving */
13446 if( !consdata->existmultaggr )
13447 {
13448 SCIP_VAR* var;
13450 assert(var != NULL);
13451
13452 /* if the variable was aggregated or multiaggregated, we must signal to propagation that we are no longer merged */
13454 {
13455 consdata->existmultaggr = TRUE;
13456 consdata->merged = FALSE;
13457 }
13460 consdata->merged = FALSE;
13461 }
13462 /*lint -fallthrough*/
13463 case SCIP_EVENTTYPE_IMPLADDED: /* further preprocessing might be possible due to additional implications */
13464 consdata->presolvedtiming = 0;
13465 break;
13467 consdata->varsdeleted = TRUE;
13468 break;
13469 default:
13470 SCIPerrorMessage("invalid event type %" SCIP_EVENTTYPE_FORMAT "\n", SCIPeventGetType(event));
13471 return SCIP_INVALIDDATA;
13472 }
13473
13474 return SCIP_OKAY;
13475}
13476
13477
13478/*
13479 * constraint specific interface methods
13480 */
13481
13482/** creates the handler for knapsack constraints and includes it in SCIP */
13484 SCIP* scip /**< SCIP data structure */
13485 )
13486{
13487 SCIP_EVENTHDLRDATA* eventhdlrdata;
13488 SCIP_CONSHDLRDATA* conshdlrdata;
13489 SCIP_CONSHDLR* conshdlr;
13490
13491 /* create knapsack constraint handler data */
13492 SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
13493
13494 /* include event handler for bound change events */
13495 eventhdlrdata = NULL;
13496 conshdlrdata->eventhdlr = NULL;
13498 eventExecKnapsack, eventhdlrdata) );
13499
13500 /* get event handler for bound change events */
13501 if( conshdlrdata->eventhdlr == NULL )
13502 {
13503 SCIPerrorMessage("event handler for knapsack constraints not found\n");
13504 return SCIP_PLUGINNOTFOUND;
13505 }
13506
13507 /* include constraint handler */
13511 conshdlrdata) );
13512
13513 assert(conshdlr != NULL);
13514
13515 /* set non-fundamental callbacks via specific setter functions */
13543
13544 if( SCIPfindConshdlr(scip,"linear") != NULL )
13545 {
13546 /* include the linear constraint to knapsack constraint upgrade in the linear constraint handler */
13548 }
13549
13550 /* add knapsack constraint handler parameters */
13552 "constraints/" CONSHDLR_NAME "/sepacardfreq",
13553 "multiplier on separation frequency, how often knapsack cuts are separated (-1: never, 0: only at root)",
13554 &conshdlrdata->sepacardfreq, TRUE, DEFAULT_SEPACARDFREQ, -1, SCIP_MAXTREEDEPTH, NULL, NULL) );
13556 "constraints/" CONSHDLR_NAME "/maxcardbounddist",
13557 "maximal relative distance from current node's dual bound to primal bound compared to best node's dual bound for separating knapsack cuts",
13558 &conshdlrdata->maxcardbounddist, TRUE, DEFAULT_MAXCARDBOUNDDIST, 0.0, 1.0, NULL, NULL) );
13560 "constraints/" CONSHDLR_NAME "/cliqueextractfactor",
13561 "lower clique size limit for greedy clique extraction algorithm (relative to largest clique)",
13562 &conshdlrdata->cliqueextractfactor, TRUE, DEFAULT_CLIQUEEXTRACTFACTOR, 0.0, 1.0, NULL, NULL) );
13564 "constraints/" CONSHDLR_NAME "/maxrounds",
13565 "maximal number of separation rounds per node (-1: unlimited)",
13566 &conshdlrdata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
13568 "constraints/" CONSHDLR_NAME "/maxroundsroot",
13569 "maximal number of separation rounds per node in the root node (-1: unlimited)",
13570 &conshdlrdata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
13572 "constraints/" CONSHDLR_NAME "/maxsepacuts",
13573 "maximal number of cuts separated per separation round",
13574 &conshdlrdata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
13576 "constraints/" CONSHDLR_NAME "/maxsepacutsroot",
13577 "maximal number of cuts separated per separation round in the root node",
13578 &conshdlrdata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
13580 "constraints/" CONSHDLR_NAME "/disaggregation",
13581 "should disaggregation of knapsack constraints be allowed in preprocessing?",
13582 &conshdlrdata->disaggregation, TRUE, DEFAULT_DISAGGREGATION, NULL, NULL) );
13584 "constraints/" CONSHDLR_NAME "/simplifyinequalities",
13585 "should presolving try to simplify knapsacks",
13586 &conshdlrdata->simplifyinequalities, TRUE, DEFAULT_SIMPLIFYINEQUALITIES, NULL, NULL) );
13588 "constraints/" CONSHDLR_NAME "/negatedclique",
13589 "should negated clique information be used in solving process",
13590 &conshdlrdata->negatedclique, TRUE, DEFAULT_NEGATEDCLIQUE, NULL, NULL) );
13592 "constraints/" CONSHDLR_NAME "/presolpairwise",
13593 "should pairwise constraint comparison be performed in presolving?",
13594 &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13596 "constraints/" CONSHDLR_NAME "/presolusehashing",
13597 "should hash table be used for detecting redundant constraints in advance",
13598 &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) );
13600 "constraints/" CONSHDLR_NAME "/dualpresolving",
13601 "should dual presolving steps be performed?",
13602 &conshdlrdata->dualpresolving, TRUE, DEFAULT_DUALPRESOLVING, NULL, NULL) );
13604 "constraints/" CONSHDLR_NAME "/usegubs",
13605 "should GUB information be used for separation?",
13606 &conshdlrdata->usegubs, TRUE, DEFAULT_USEGUBS, NULL, NULL) );
13608 "constraints/" CONSHDLR_NAME "/detectcutoffbound",
13609 "should presolving try to detect constraints parallel to the objective function defining an upper bound and prevent these constraints from entering the LP?",
13610 &conshdlrdata->detectcutoffbound, TRUE, DEFAULT_DETECTCUTOFFBOUND, NULL, NULL) );
13612 "constraints/" CONSHDLR_NAME "/detectlowerbound",
13613 "should presolving try to detect constraints parallel to the objective function defining a lower bound and prevent these constraints from entering the LP?",
13614 &conshdlrdata->detectlowerbound, TRUE, DEFAULT_DETECTLOWERBOUND, NULL, NULL) );
13616 "constraints/" CONSHDLR_NAME "/updatecliquepartitions",
13617 "should clique partition information be updated when old partition seems outdated?",
13618 &conshdlrdata->updatecliquepartitions, TRUE, DEFAULT_UPDATECLIQUEPARTITIONS, NULL, NULL) );
13620 "constraints/" CONSHDLR_NAME "/clqpartupdatefac",
13621 "factor on the growth of global cliques to decide when to update a previous "
13622 "(negated) clique partition (used only if updatecliquepartitions is set to TRUE)",
13623 &conshdlrdata->clqpartupdatefac, TRUE, DEFAULT_CLQPARTUPDATEFAC, 1.0, 10.0, NULL, NULL) );
13624#ifdef WITH_CARDINALITY_UPGRADE
13626 "constraints/" CONSHDLR_NAME "/upgdcardinality",
13627 "if TRUE then try to update knapsack constraints to cardinality constraints",
13628 &conshdlrdata->upgdcardinality, TRUE, DEFAULT_UPGDCARDINALITY, NULL, NULL) );
13629#endif
13630 return SCIP_OKAY;
13631}
13632
13633/** creates and captures a knapsack constraint
13634 *
13635 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13636 */
13637/**! [SnippetConsCreationKnapsack] */
13639 SCIP* scip, /**< SCIP data structure */
13640 SCIP_CONS** cons, /**< pointer to hold the created constraint */
13641 const char* name, /**< name of constraint */
13642 int nvars, /**< number of items in the knapsack */
13643 SCIP_VAR** vars, /**< array with item variables */
13644 SCIP_Longint* weights, /**< array with item weights */
13645 SCIP_Longint capacity, /**< capacity of knapsack (right hand side of inequality) */
13646 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13647 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13648 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13649 * Usually set to TRUE. */
13650 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13651 * TRUE for model constraints, FALSE for additional, redundant constraints. */
13652 SCIP_Bool check, /**< should the constraint be checked for feasibility?
13653 * TRUE for model constraints, FALSE for additional, redundant constraints. */
13654 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13655 * Usually set to TRUE. */
13656 SCIP_Bool local, /**< is constraint only valid locally?
13657 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13658 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13659 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13660 * adds coefficients to this constraint. */
13661 SCIP_Bool dynamic, /**< is constraint subject to aging?
13662 * Usually set to FALSE. Set to TRUE for own cuts which
13663 * are separated as constraints. */
13664 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13665 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13666 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13667 * if it may be moved to a more global node?
13668 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13669 )
13670{
13671 SCIP_CONSHDLRDATA* conshdlrdata;
13672 SCIP_CONSHDLR* conshdlr;
13673 SCIP_CONSDATA* consdata;
13674
13675 /* find the knapsack constraint handler */
13676 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13677 if( conshdlr == NULL )
13678 {
13679 SCIPerrorMessage("knapsack constraint handler not found\n");
13680 return SCIP_PLUGINNOTFOUND;
13681 }
13682
13683 /* get event handler */
13684 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13685 assert(conshdlrdata != NULL);
13686 assert(conshdlrdata->eventhdlr != NULL);
13687
13688 /* create constraint data */
13689 SCIP_CALL( consdataCreate(scip, &consdata, nvars, vars, weights, capacity) );
13690
13691 /* create constraint */
13692 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
13693 local, modifiable, dynamic, removable, stickingatnode) );
13694
13695 /* catch events for variables */
13696 if( SCIPisTransformed(scip) )
13697 {
13698 SCIP_CALL( catchEvents(scip, *cons, consdata, conshdlrdata->eventhdlr) );
13699 }
13700
13701 return SCIP_OKAY;
13702}
13703/**! [SnippetConsCreationKnapsack] */
13704
13705/** creates and captures a knapsack constraint
13706 * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13707 * method SCIPcreateConsKnapsack(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13708 *
13709 * @see SCIPcreateConsKnapsack() for information about the basic constraint flag configuration
13710 *
13711 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13712 */
13714 SCIP* scip, /**< SCIP data structure */
13715 SCIP_CONS** cons, /**< pointer to hold the created constraint */
13716 const char* name, /**< name of constraint */
13717 int nvars, /**< number of items in the knapsack */
13718 SCIP_VAR** vars, /**< array with item variables */
13719 SCIP_Longint* weights, /**< array with item weights */
13720 SCIP_Longint capacity /**< capacity of knapsack */
13721 )
13722{
13723 assert(scip != NULL);
13724
13725 SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13727
13728 return SCIP_OKAY;
13729}
13730
13731/** adds new item to knapsack constraint */
13733 SCIP* scip, /**< SCIP data structure */
13734 SCIP_CONS* cons, /**< constraint data */
13735 SCIP_VAR* var, /**< item variable */
13736 SCIP_Longint weight /**< item weight */
13737 )
13738{
13739 assert(var != NULL);
13740 assert(scip != NULL);
13741
13743 {
13744 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13745 return SCIP_INVALIDDATA;
13746 }
13747
13748 SCIP_CALL( addCoef(scip, cons, var, weight) );
13749
13750 return SCIP_OKAY;
13751}
13752
13753/** gets the capacity of the knapsack constraint */
13755 SCIP* scip, /**< SCIP data structure */
13756 SCIP_CONS* cons /**< constraint data */
13757 )
13758{
13759 SCIP_CONSDATA* consdata;
13760
13761 assert(scip != NULL);
13762
13764 {
13765 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13766 SCIPABORT();
13767 return 0; /*lint !e527*/
13768 }
13769
13770 consdata = SCIPconsGetData(cons);
13771 assert(consdata != NULL);
13772
13773 return consdata->capacity;
13774}
13775
13776/** changes capacity of the knapsack constraint
13777 *
13778 * @note This method can only be called during problem creation stage (SCIP_STAGE_PROBLEM)
13779 */
13781 SCIP* scip, /**< SCIP data structure */
13782 SCIP_CONS* cons, /**< constraint data */
13783 SCIP_Longint capacity /**< new capacity of knapsack */
13784 )
13785{
13786 SCIP_CONSDATA* consdata;
13787
13788 assert(scip != NULL);
13789
13791 {
13792 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13793 return SCIP_INVALIDDATA;
13794 }
13795
13797 {
13798 SCIPerrorMessage("method can only be called during problem creation stage\n");
13799 return SCIP_INVALIDDATA;
13800 }
13801
13802 consdata = SCIPconsGetData(cons);
13803 assert(consdata != NULL);
13804
13805 consdata->capacity = capacity;
13806
13807 return SCIP_OKAY;
13808}
13809
13810/** gets the number of items in the knapsack constraint */
13812 SCIP* scip, /**< SCIP data structure */
13813 SCIP_CONS* cons /**< constraint data */
13814 )
13815{
13816 SCIP_CONSDATA* consdata;
13817
13818 assert(scip != NULL);
13819
13821 {
13822 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13823 SCIPABORT();
13824 return -1; /*lint !e527*/
13825 }
13826
13827 consdata = SCIPconsGetData(cons);
13828 assert(consdata != NULL);
13829
13830 return consdata->nvars;
13831}
13832
13833/** gets the array of variables in the knapsack constraint; the user must not modify this array! */
13835 SCIP* scip, /**< SCIP data structure */
13836 SCIP_CONS* cons /**< constraint data */
13837 )
13838{
13839 SCIP_CONSDATA* consdata;
13840
13841 assert(scip != NULL);
13842
13844 {
13845 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13846 SCIPABORT();
13847 return NULL; /*lint !e527*/
13848 }
13849
13850 consdata = SCIPconsGetData(cons);
13851 assert(consdata != NULL);
13852
13853 return consdata->vars;
13854}
13855
13856/** gets the array of weights in the knapsack constraint; the user must not modify this array! */
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 constraint\n");
13869 SCIPABORT();
13870 return NULL; /*lint !e527*/
13871 }
13872
13873 consdata = SCIPconsGetData(cons);
13874 assert(consdata != NULL);
13875
13876 return consdata->weights;
13877}
13878
13879/** gets the dual solution of the knapsack constraint in the current LP */
13881 SCIP* scip, /**< SCIP data structure */
13882 SCIP_CONS* cons /**< constraint data */
13883 )
13884{
13885 SCIP_CONSDATA* consdata;
13886
13887 assert(scip != NULL);
13888
13890 {
13891 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13892 SCIPABORT();
13893 return SCIP_INVALID; /*lint !e527*/
13894 }
13895
13896 consdata = SCIPconsGetData(cons);
13897 assert(consdata != NULL);
13898
13899 if( consdata->row != NULL )
13900 return SCIProwGetDualsol(consdata->row);
13901 else
13902 return 0.0;
13903}
13904
13905/** gets the dual Farkas value of the knapsack constraint in the current infeasible LP */
13907 SCIP* scip, /**< SCIP data structure */
13908 SCIP_CONS* cons /**< constraint data */
13909 )
13910{
13911 SCIP_CONSDATA* consdata;
13912
13913 assert(scip != NULL);
13914
13916 {
13917 SCIPerrorMessage("constraint is not a knapsack constraint\n");
13918 SCIPABORT();
13919 return SCIP_INVALID; /*lint !e527*/
13920 }
13921
13922 consdata = SCIPconsGetData(cons);
13923 assert(consdata != NULL);
13924
13925 if( consdata->row != NULL )
13926 return SCIProwGetDualfarkas(consdata->row);
13927 else
13928 return 0.0;
13929}
13930
13931/** returns the linear relaxation of the given knapsack constraint; may return NULL if no LP row was yet created;
13932 * the user must not modify the row!
13933 */
13935 SCIP* scip, /**< SCIP data structure */
13936 SCIP_CONS* cons /**< constraint data */
13937 )
13938{
13939 SCIP_CONSDATA* consdata;
13940
13941 assert(scip != NULL);
13942
13944 {
13945 SCIPerrorMessage("constraint is not a knapsack\n");
13946 SCIPABORT();
13947 return NULL; /*lint !e527*/
13948 }
13949
13950 consdata = SCIPconsGetData(cons);
13951 assert(consdata != NULL);
13952
13953 return consdata->row;
13954}
13955
13956/** cleans up (multi-)aggregations and fixings from knapsack constraints */
13958 SCIP* scip, /**< SCIP data structure */
13959 SCIP_Bool onlychecked, /**< should only checked constraints be cleaned up? */
13960 SCIP_Bool* infeasible /**< pointer to return whether the problem was detected to be infeasible */
13961 )
13962{
13963 SCIP_CONSHDLR* conshdlr;
13964 SCIP_CONS** conss;
13965 int nconss;
13966 int i;
13967
13968 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13969 if( conshdlr == NULL )
13970 return SCIP_OKAY;
13971
13972 assert(infeasible != NULL);
13973 *infeasible = FALSE;
13974
13976 conss = onlychecked ? SCIPconshdlrGetCheckConss(conshdlr) : SCIPconshdlrGetConss(conshdlr);
13977
13978 for( i = 0; i < nconss; ++i )
13979 {
13980 SCIP_CALL( applyFixings(scip, conss[i], infeasible) );
13981
13982 if( *infeasible )
13983 break;
13984 }
13985
13986 return SCIP_OKAY;
13987}
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 addSymmetryInformation(SCIP *scip, SYM_SYMTYPE symtype, SCIP_CONS *cons, SYM_GRAPH *graph, SCIP_Bool *success)
static SCIP_RETCODE applyFixings(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff)
static SCIP_RETCODE lockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
static void computeMinweightsGUB(SCIP_Longint *minweights, SCIP_Longint *finished, SCIP_Longint *unfinished, int minweightslen)
static SCIP_RETCODE sequentialUpAndDownLiftingGUB(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, int ngubconscapexceed, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *gubconsGC1, int *gubconsGC2, int *gubconsGFC1, int *gubconsGR, int ngubconsGC1, int ngubconsGC2, int ngubconsGFC1, int ngubconsGR, int alpha0, int *liftcoefs, SCIP_Real *cutact, int *liftrhs, int maxgubvarssize)
#define HASHSIZE_KNAPSACKCONS
static SCIP_RETCODE GUBsetCalcCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques, SCIP_Real *solvals)
#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 NULL
Definition def.h:267
#define SCIP_MAXSTRLEN
Definition def.h:288
#define SCIP_Longint
Definition def.h:158
#define SCIP_MAXTREEDEPTH
Definition def.h:316
#define SCIP_INVALID
Definition def.h:193
#define MIN(x, y)
Definition def.h:243
#define SCIP_Real
Definition def.h:173
#define TRUE
Definition def.h:93
#define FALSE
Definition def.h:94
#define MAX(x, y)
Definition def.h:239
#define SCIP_LONGINT_FORMAT
Definition def.h:165
#define SCIPABORT()
Definition def.h:346
#define REALABS(x)
Definition def.h:197
#define SCIP_LONGINT_MAX
Definition def.h:159
#define SCIP_CALL(x)
Definition def.h:374
SCIP_RETCODE SCIPincludeLinconsUpgrade(SCIP *scip, SCIP_DECL_LINCONSUPGD((*linconsupgd)), int priority, const char *conshdlrname)
int SCIPgetNVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcreateConsCardinality(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, int cardval, SCIP_VAR **indvars, SCIP_Real *weights, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPaddCoefKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
SCIP_RETCODE SCIPsolveKnapsackApproximately(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval)
SCIP_RETCODE SCIPcleanupConssKnapsack(SCIP *scip, SCIP_Bool onlychecked, SCIP_Bool *infeasible)
SCIP_RETCODE SCIPseparateKnapsackCuts(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_SOL *sol, SCIP_Bool usegubs, SCIP_Bool *cutoff, int *ncuts)
SCIP_RETCODE SCIPcreateConsSetpack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
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:3108
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3281
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition misc.c:3074
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3423
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition misc.c:3192
SCIP_RETCODE SCIPhashmapSetImageInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition misc.c:3357
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition misc.c:2346
#define SCIPhashSix(a, b, c, d, e, f)
Definition pub_misc.h:563
SCIP_RETCODE SCIPhashtableCreate(SCIP_HASHTABLE **hashtable, BMS_BLKMEM *blkmem, int tablesize, SCIP_DECL_HASHGETKEY((*hashgetkey)), SCIP_DECL_HASHKEYEQ((*hashkeyeq)), SCIP_DECL_HASHKEYVAL((*hashkeyval)), void *userptr)
Definition misc.c:2296
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition misc.c:2608
SCIP_RETCODE SCIPhashtableRemove(SCIP_HASHTABLE *hashtable, void *element)
Definition misc.c:2677
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition misc.c:2547
SCIP_RETCODE SCIPupdateLocalLowerbound(SCIP *scip, SCIP_Real newbound)
Definition scip_prob.c:3696
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition scip_prob.c:3474
SCIP_Real SCIPgetLocalLowerbound(SCIP *scip)
Definition scip_prob.c:3585
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
#define SCIPdebugMsgPrint
#define SCIPdebugMsg
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition misc.c:9121
SCIP_RETCODE SCIPcalcIntegralScalar(SCIP_Real *vals, int nvals, SCIP_Real mindelta, SCIP_Real maxdelta, SCIP_Longint maxdnom, SCIP_Real maxscale, SCIP_Real *intscalar, SCIP_Bool *success)
Definition misc.c:9557
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition misc.c:11184
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:83
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:139
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:57
int SCIPgetNLPBranchCands(SCIP *scip)
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
SCIP_RETCODE SCIPaddConflictBinvar(SCIP *scip, SCIP_VAR *var)
SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
int SCIPconshdlrGetNCheckConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4656
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition cons.c:4227
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:372
SCIP_RETCODE SCIPsetConshdlrActive(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:670
SCIP_CONS ** SCIPconshdlrGetCheckConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4613
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition scip_cons.c:540
SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:492
SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
Definition scip_cons.c:235
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition scip_cons.c:281
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:323
SCIP_RETCODE SCIPincludeConshdlrBasic(SCIP *scip, SCIP_CONSHDLR **conshdlrptr, const char *name, const char *desc, int enfopriority, int chckpriority, int eagerfreq, SCIP_Bool needscons, SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition scip_cons.c:181
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:808
SCIP_Longint SCIPconshdlrGetNCutsFound(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4900
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:831
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:785
SCIP_RETCODE SCIPsetConshdlrGetSignedPermsymGraph(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:924
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4197
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)),)
Definition scip_cons.c:347
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition scip_cons.c:941
SCIP_RETCODE SCIPsetConshdlrInit(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:396
SCIP_RETCODE SCIPsetConshdlrGetPermsymGraph(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:900
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:578
SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:444
SCIP_RETCODE SCIPsetConshdlrDeactive(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:693
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4217
int SCIPconshdlrGetNActiveConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4670
int SCIPconshdlrGetSepaFreq(SCIP_CONSHDLR *conshdlr)
Definition cons.c:5130
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:601
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:647
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:516
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:468
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4593
SCIP_RETCODE SCIPsetConshdlrDelvars(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:762
SCIP_RETCODE SCIPsetConshdlrExit(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:420
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:624
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:854
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition cons.c:8244
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition cons.c:8473
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition cons.c:8234
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition cons.c:8383
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition scip_cons.c:2537
SCIP_RETCODE SCIPsetConsSeparated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool separate)
Definition scip_cons.c:1297
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition cons.c:8413
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition cons.c:8343
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition cons.c:8523
SCIP_RETCODE SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial)
Definition scip_cons.c:1272
SCIP_RETCODE SCIPsetConsEnforced(SCIP *scip, SCIP_CONS *cons, SCIP_Bool enforce)
Definition scip_cons.c:1322
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition cons.c:8403
SCIP_RETCODE SCIPunmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition scip_cons.c:2043
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition cons.c:8275
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition scip_cons.c:998
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition cons.c:8433
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition cons.c:8453
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition cons.c:8214
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition scip_cons.c:1813
SCIP_RETCODE SCIPmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition scip_cons.c:2015
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition cons.c:8463
SCIP_RETCODE SCIPupdateConsFlags(SCIP *scip, SCIP_CONS *cons0, SCIP_CONS *cons1)
Definition scip_cons.c:1525
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition cons.c:8493
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition scip_cons.c:1174
SCIP_RETCODE SCIPsetConsPropagated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool propagate)
Definition scip_cons.c:1372
SCIP_RETCODE SCIPsetConsChecked(SCIP *scip, SCIP_CONS *cons, SCIP_Bool check)
Definition scip_cons.c:1347
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition cons.c:8393
SCIP_RETCODE SCIPincConsAge(SCIP *scip, SCIP_CONS *cons)
Definition scip_cons.c:1785
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition cons.c:8483
SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition scip_cut.c:117
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition scip_cut.c:135
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition scip_cut.c:250
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition scip_event.c:104
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition event.c:1030
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition scip_event.c:354
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition scip_event.c:400
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition event.c:1053
#define SCIPfreeBuffer(scip, ptr)
Definition scip_mem.h:134
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition scip_mem.h:110
#define SCIPallocClearBlockMemoryArray(scip, ptr, num)
Definition scip_mem.h:97
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition scip_mem.h:126
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition scip_mem.c:139
#define SCIPallocBufferArray(scip, ptr, num)
Definition scip_mem.h:124
#define SCIPreallocBufferArray(scip, ptr, num)
Definition scip_mem.h:128
#define SCIPfreeBufferArray(scip, ptr)
Definition scip_mem.h:136
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition scip_mem.h:132
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition scip_mem.h:93
#define SCIPallocBuffer(scip, ptr)
Definition scip_mem.h:122
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition scip_mem.h:99
#define SCIPfreeBlockMemory(scip, ptr)
Definition scip_mem.h:108
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition scip_mem.h:111
#define SCIPallocBlockMemory(scip, ptr)
Definition scip_mem.h:89
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition scip_mem.h:105
SCIP_RETCODE SCIPdelNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition scip_nlp.c:424
SCIP_RETCODE SCIPaddNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition scip_nlp.c:396
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition scip_nlp.c:110
SCIP_RETCODE SCIPreleaseNlRow(SCIP *scip, SCIP_NLROW **nlrow)
Definition scip_nlp.c:1058
SCIP_Bool SCIPnlrowIsInNLP(SCIP_NLROW *nlrow)
Definition nlp.c:1956
SCIP_RETCODE SCIPcreateNlRow(SCIP *scip, SCIP_NLROW **nlrow, const char *name, SCIP_Real constant, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, SCIP_EXPR *expr, SCIP_Real lhs, SCIP_Real rhs, SCIP_EXPRCURV curvature)
Definition scip_nlp.c:954
SCIP_Bool SCIPinProbing(SCIP *scip)
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1635
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONS *cons, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition scip_lp.c:1422
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1658
SCIP_RETCODE SCIPcreateEmptyRowConshdlr(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition scip_lp.c:1391
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition scip_lp.c:1701
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition scip_lp.c:2212
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition scip_lp.c:1562
SCIP_RETCODE SCIPcreateEmptyRowSepa(SCIP *scip, SCIP_ROW **row, SCIP_SEPA *sepa, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition scip_lp.c:1453
SCIP_RETCODE SCIPcreateEmptyRowUnspec(SCIP *scip, SCIP_ROW **row, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition scip_lp.c:1482
SCIP_Real SCIProwGetDualfarkas(SCIP_ROW *row)
Definition lp.c:17325
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition lp.c:17523
SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
Definition lp.c:17312
const char * SCIPsepaGetName(SCIP_SEPA *sepa)
Definition sepa.c:743
SCIP_Longint SCIPsepaGetNCutsFound(SCIP_SEPA *sepa)
Definition sepa.c:900
SCIP_RETCODE SCIPgetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition scip_sol.c:1254
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition scip_sol.c:1217
void SCIPupdateSolLPConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition scip_sol.c:141
SCIP_RETCODE SCIPupdateCutoffbound(SCIP *scip, SCIP_Real cutoffbound)
int SCIPgetNSepaRounds(SCIP *scip)
SCIP_Real SCIPgetLowerbound(SCIP *scip)
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
SCIP_RETCODE SCIPgetSymActiveVariables(SCIP *scip, SYM_SYMTYPE symtype, SCIP_VAR ***vars, SCIP_Real **scalars, int *nvars, SCIP_Real *constant, SCIP_Bool transformed)
SCIP_RETCODE SCIPextendPermsymDetectionGraphLinear(SCIP *scip, SYM_GRAPH *graph, SCIP_VAR **vars, SCIP_Real *vals, int nvars, SCIP_CONS *cons, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool *success)
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPcutoffbounddelta(SCIP *scip)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPepsilon(SCIP *scip)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition scip_tree.c:146
int SCIPgetDepth(SCIP *scip)
Definition scip_tree.c:670
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:5205
int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition var.c:18270
SCIP_Bool SCIPvarIsDeleted(SCIP_VAR *var)
Definition var.c:17640
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition scip_var.c:4353
SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
Definition var.c:17882
SCIP_VAR * SCIPvarGetNegatedVar(SCIP_VAR *var)
Definition var.c:17894
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition var.c:18292
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition var.c:17748
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition var.c:17599
SCIP_RETCODE SCIPaddClique(SCIP *scip, SCIP_VAR **vars, SCIP_Bool *values, int nvars, SCIP_Bool isequation, SCIP_Bool *infeasible, int *nbdchgs)
Definition scip_var.c:6923
SCIP_RETCODE SCIPcalcCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques)
Definition scip_var.c:7258
SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
Definition scip_var.c:1482
int SCIPvarGetNImpls(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:18356
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition var.c:17538
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition var.c:3353
SCIP_RETCODE SCIPcalcNegatedCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques)
Definition scip_var.c:7477
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition var.c:18144
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition var.c:17561
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition var.c:17926
SCIP_VAR * SCIPvarGetProbvar(SCIP_VAR *var)
Definition var.c:12218
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:5322
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition scip_var.c:533
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition var.c:18088
SCIP_VAR ** SCIPvarGetImplVars(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:18373
int SCIPvarGetIndex(SCIP_VAR *var)
Definition var.c:17758
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition scip_var.c:4261
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition scip_var.c:4439
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition scip_var.c:2130
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition var.c:17768
const char * SCIPvarGetName(SCIP_VAR *var)
Definition var.c:17419
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition scip_var.c:1250
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition var.c:18302
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition var.c:18312
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition var.c:17610
SCIP_Real * SCIPvarGetImplBounds(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:18402
SCIP_RETCODE SCIPflattenVarAggregationGraph(SCIP *scip, SCIP_VAR *var)
Definition scip_var.c:1695
SCIP_RETCODE SCIPgetNegatedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **negvar)
Definition scip_var.c:1529
SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
Definition var.c:17858
int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition var.c:17846
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:18430
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition var.c:18134
SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
Definition var.c:17574
int SCIPgetNCliques(SCIP *scip)
Definition scip_var.c:7577
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition var.c:18282
SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:18441
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition var.c:18078
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition scip_var.c:8278
SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition scip_var.c:1994
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition var.c:11942
SCIP_RETCODE SCIPvarGetProbvarBinary(SCIP_VAR **var, SCIP_Bool *negated)
Definition var.c:12310
SCIP_RETCODE SCIPinferBinvarCons(SCIP *scip, SCIP_VAR *var, SCIP_Bool fixedval, SCIP_CONS *infercons, int inferinfo, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:5725
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition var.c:18344
SCIP_RETCODE SCIPwriteVarName(SCIP *scip, FILE *file, SCIP_VAR *var, SCIP_Bool type)
Definition scip_var.c:230
SCIP_RETCODE SCIPgetBinvarRepresentative(SCIP *scip, SCIP_VAR *var, SCIP_VAR **repvar, SCIP_Bool *negated)
Definition scip_var.c:1599
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition var.c:18324
SCIP_Bool SCIPvarsHaveCommonClique(SCIP_VAR *var1, SCIP_Bool value1, SCIP_VAR *var2, SCIP_Bool value2, SCIP_Bool regardimplics)
Definition var.c:11475
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition var.c:18334
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition var.c:3295
SCIP_RETCODE SCIPgetNegatedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **negvars)
Definition scip_var.c:1562
SCIP_BOUNDTYPE * SCIPvarGetImplTypes(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:18388
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition scip_var.c:1216
SCIP_Bool SCIPallowStrongDualReds(SCIP *scip)
Definition scip_var.c:8631
SCIP_RETCODE SCIPvarsGetProbvarBinary(SCIP_VAR ***vars, SCIP_Bool **negatedarr, int nvars)
Definition var.c:12278
SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition var.c:17870
void SCIPselectWeightedDownRealLongRealInt(SCIP_Real *realarray1, SCIP_Longint *longarray, SCIP_Real *realarray3, int *intarray, SCIP_Real *weights, SCIP_Real capacity, int len, int *medianpos)
void SCIPsortDownLongPtr(SCIP_Longint *longarray, void **ptrarray, int len)
void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
void SCIPsortPtrPtrIntInt(void **ptrarray1, void **ptrarray2, int *intarray1, int *intarray2, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
void SCIPsortPtrPtrLongIntInt(void **ptrarray1, void **ptrarray2, SCIP_Longint *longarray, int *intarray1, int *intarray2, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
void SCIPsortDownPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
void SCIPsortDownLongPtrPtrIntInt(SCIP_Longint *longarray, void **ptrarray1, void **ptrarray2, int *intarray1, int *intarray2, int len)
void SCIPsortRealInt(SCIP_Real *realarray, int *intarray, int len)
void SCIPsortDownRealIntLong(SCIP_Real *realarray, int *intarray, SCIP_Longint *longarray, int len)
void SCIPsortPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
void SCIPsortDownRealInt(SCIP_Real *realarray, int *intarray, int len)
void SCIPsortDownLongPtrInt(SCIP_Longint *longarray, void **ptrarray, int *intarray, int len)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition misc.c:10877
SCIP_RETCODE SCIPskipSpace(char **s)
Definition misc.c:10866
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
memory allocation routines
#define BMScopyMemoryArray(ptr, source, num)
Definition memory.h:134
#define BMSclearMemoryArray(ptr, num)
Definition memory.h:130
struct BMS_BlkMem BMS_BLKMEM
Definition memory.h:437
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition scip_mem.c:57
public methods for managing constraints
public methods for managing events
public methods for implications, variable bounds, and cliques
public methods for LP management
public methods for message output
#define SCIPerrorMessage
Definition pub_message.h:64
#define SCIPdebug(x)
Definition pub_message.h:93
#define SCIPdebugPrintCons(x, y, z)
#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
structs for symmetry computations
methods for dealing with symmetry detection graphs
@ SCIP_CONFTYPE_PROPAGATION
#define SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(x)
Definition type_cons.h:955
#define SCIP_DECL_CONSGETPERMSYMGRAPH(x)
Definition type_cons.h:937
#define SCIP_DECL_CONSENFOLP(x)
Definition type_cons.h:363
#define SCIP_DECL_CONSINITPRE(x)
Definition type_cons.h:156
#define SCIP_DECL_CONSDELETE(x)
Definition type_cons.h:229
#define SCIP_DECL_CONSEXIT(x)
Definition type_cons.h:136
#define SCIP_DECL_CONSGETVARS(x)
Definition type_cons.h:866
#define SCIP_DECL_CONSINITSOL(x)
Definition type_cons.h:201
#define SCIP_DECL_CONSPRINT(x)
Definition type_cons.h:768
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition type_cons.h:64
#define SCIP_DECL_CONSSEPALP(x)
Definition type_cons.h:288
#define SCIP_DECL_CONSENFORELAX(x)
Definition type_cons.h:388
#define SCIP_DECL_CONSPROP(x)
Definition type_cons.h:505
#define SCIP_DECL_CONSGETNVARS(x)
Definition type_cons.h:884
#define SCIP_DECL_CONSRESPROP(x)
Definition type_cons.h:611
#define SCIP_DECL_CONSACTIVE(x)
Definition type_cons.h:690
#define SCIP_DECL_CONSENFOPS(x)
Definition type_cons.h:431
#define SCIP_DECL_CONSPARSE(x)
Definition type_cons.h:844
#define SCIP_DECL_CONSTRANS(x)
Definition type_cons.h:239
#define SCIP_DECL_CONSDEACTIVE(x)
Definition type_cons.h:705
#define SCIP_DECL_CONSPRESOL(x)
Definition type_cons.h:560
#define SCIP_DECL_CONSINITLP(x)
Definition type_cons.h:259
#define SCIP_DECL_CONSEXITPRE(x)
Definition type_cons.h:180
#define SCIP_DECL_CONSLOCK(x)
Definition type_cons.h:675
#define SCIP_DECL_CONSCOPY(x)
Definition type_cons.h:809
#define SCIP_DECL_CONSINIT(x)
Definition type_cons.h:126
struct SCIP_ConsData SCIP_CONSDATA
Definition type_cons.h:65
#define SCIP_DECL_CONSCHECK(x)
Definition type_cons.h:474
#define SCIP_DECL_CONSHDLRCOPY(x)
Definition type_cons.h:108
#define SCIP_DECL_CONSEXITSOL(x)
Definition type_cons.h:216
#define SCIP_DECL_CONSFREE(x)
Definition type_cons.h:116
#define SCIP_DECL_CONSSEPASOL(x)
Definition type_cons.h:320
#define SCIP_DECL_CONSDELVARS(x)
Definition type_cons.h:752
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:65
@ 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
enum SYM_Symtype SYM_SYMTYPE
@ SYM_SYMTYPE_SIGNPERM
@ SYM_SYMTYPE_PERM
#define SCIP_PRESOLTIMING_MEDIUM
Definition type_timing.h:53
unsigned int SCIP_PRESOLTIMING
Definition type_timing.h:61
#define SCIP_PRESOLTIMING_FAST
Definition type_timing.h:52
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition type_timing.h:54
@ 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