SCIP Doxygen Documentation
Loading...
Searching...
No Matches
cons_knapsack.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-2026 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file cons_knapsack.c
26 * @ingroup DEFPLUGINS_CONS
27 * @brief Constraint handler for knapsack constraints of the form \f$a^T x \le b\f$, x binary and \f$a \ge 0\f$.
28 * @author Tobias Achterberg
29 * @author Xin Liu
30 * @author Kati Wolter
31 * @author Michael Winkler
32 * @author Tobias Fischer
33 */
34
35/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
36
38#include "scip/cons_knapsack.h"
39#include "scip/cons_linear.h"
40#include "scip/cons_logicor.h"
41#include "scip/cons_setppc.h"
42#include "scip/pub_cons.h"
43#include "scip/pub_event.h"
44#include "scip/pub_implics.h"
45#include "scip/pub_lp.h"
46#include "scip/pub_message.h"
47#include "scip/pub_misc.h"
49#include "scip/pub_misc_sort.h"
50#include "scip/pub_sepa.h"
51#include "scip/pub_var.h"
52#include "scip/scip_branch.h"
53#include "scip/scip_conflict.h"
54#include "scip/scip_cons.h"
55#include "scip/scip_copy.h"
56#include "scip/scip_cut.h"
57#include "scip/scip_event.h"
58#include "scip/scip_general.h"
59#include "scip/scip_lp.h"
60#include "scip/scip_mem.h"
61#include "scip/scip_message.h"
62#include "scip/scip_nlp.h"
63#include "scip/scip_numerics.h"
64#include "scip/scip_param.h"
65#include "scip/scip_prob.h"
66#include "scip/scip_probing.h"
67#include "scip/scip_sol.h"
69#include "scip/scip_tree.h"
70#include "scip/scip_var.h"
71#include "scip/symmetry_graph.h"
73#include <ctype.h>
74
75#ifdef WITH_CARDINALITY_UPGRADE
77#endif
78
79/* constraint handler properties */
80#define CONSHDLR_NAME "knapsack"
81#define CONSHDLR_DESC "knapsack constraint of the form a^T x <= b, x binary and a >= 0"
82#define CONSHDLR_SEPAPRIORITY +600000 /**< priority of the constraint handler for separation */
83#define CONSHDLR_ENFOPRIORITY -600000 /**< priority of the constraint handler for constraint enforcing */
84#define CONSHDLR_CHECKPRIORITY -600000 /**< priority of the constraint handler for checking feasibility */
85#define CONSHDLR_SEPAFREQ 0 /**< frequency for separating cuts; zero means to separate only in the root node */
86#define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
87#define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
88 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
89#define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
90#define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
91#define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
92#define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
93
94#define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
95#define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
96
97#define EVENTHDLR_NAME "knapsack"
98#define EVENTHDLR_DESC "bound change event handler for knapsack constraints"
99#define EVENTTYPE_KNAPSACK SCIP_EVENTTYPE_LBCHANGED \
100 | SCIP_EVENTTYPE_UBTIGHTENED \
101 | SCIP_EVENTTYPE_VARFIXED \
102 | SCIP_EVENTTYPE_VARDELETED \
103 | SCIP_EVENTTYPE_IMPLADDED /**< variable events that should be caught by the event handler */
104
105#define LINCONSUPGD_PRIORITY +100000 /**< priority of the constraint handler for upgrading of linear constraints */
106
107#define MAX_USECLIQUES_SIZE 1000 /**< maximal number of items in knapsack where clique information is used */
108#define MAX_ZEROITEMS_SIZE 10000 /**< maximal number of items to store in the zero list in preprocessing */
109
110#define KNAPSACKRELAX_MAXDELTA 0.1 /**< maximal allowed rounding distance for scaling in knapsack relaxation */
111#define KNAPSACKRELAX_MAXDNOM 1000LL /**< maximal allowed denominator in knapsack rational relaxation */
112#define KNAPSACKRELAX_MAXSCALE 1000.0 /**< maximal allowed scaling factor in knapsack rational relaxation */
113
114#define DEFAULT_SEPACARDFREQ 1 /**< multiplier on separation frequency, how often knapsack cuts are separated */
115#define DEFAULT_MAXROUNDS 5 /**< maximal number of separation rounds per node (-1: unlimited) */
116#define DEFAULT_MAXROUNDSROOT -1 /**< maximal number of separation rounds in the root node (-1: unlimited) */
117#define DEFAULT_MAXSEPACUTS 50 /**< maximal number of cuts separated per separation round */
118#define DEFAULT_MAXSEPACUTSROOT 200 /**< maximal number of cuts separated per separation round in the root node */
119#define DEFAULT_MAXCARDBOUNDDIST 0.0 /**< maximal relative distance from current node's dual bound to primal bound compared
120 * to best node's dual bound for separating knapsack cuts */
121#define DEFAULT_DISAGGREGATION TRUE /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
122#define DEFAULT_SIMPLIFYINEQUALITIES TRUE/**< should presolving try to simplify knapsacks */
123#define DEFAULT_NEGATEDCLIQUE TRUE /**< should negated clique information be used in solving process */
124
125#define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds used for knapsack relaxation */
126#define USESUPADDLIFT FALSE /**< should lifted minimal cover inequalities using superadditive up-lifting be separated in addition */
127
128#define DEFAULT_PRESOLUSEHASHING TRUE /**< should hash table be used for detecting redundant constraints in advance */
129#define HASHSIZE_KNAPSACKCONS 500 /**< minimal size of hash table in linear constraint tables */
130
131#define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
132#define NMINCOMPARISONS 200000 /**< number for minimal pairwise presolving comparisons */
133#define MINGAINPERNMINCOMPARISONS 1e-06 /**< minimal gain per minimal pairwise presolving comparisons to repeat pairwise
134 * comparison round */
135#define DEFAULT_DUALPRESOLVING TRUE /**< should dual presolving steps be performed? */
136#define DEFAULT_DETECTCUTOFFBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
137 * function defining an upper bound and prevent these constraints from
138 * entering the LP */
139#define DEFAULT_DETECTLOWERBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
140 * function defining a lower bound and prevent these constraints from
141 * entering the LP */
142#define DEFAULT_CLIQUEEXTRACTFACTOR 0.5 /**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
143#define MAXCOVERSIZEITERLEWI 1000 /**< maximal size for which LEWI are iteratively separated by reducing the feasible set */
144
145#define DEFAULT_USEGUBS FALSE /**< should GUB information be used for separation? */
146#define GUBCONSGROWVALUE 6 /**< memory growing value for GUB constraint array */
147#define GUBSPLITGNC1GUBS FALSE /**< should GNC1 GUB conss without F vars be split into GOC1 and GR GUB conss? */
148#define DEFAULT_CLQPARTUPDATEFAC 1.5 /**< factor on the growth of global cliques to decide when to update a previous
149 * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
150#define DEFAULT_UPDATECLIQUEPARTITIONS FALSE /**< should clique partition information be updated when old partition seems outdated? */
151#define MAXNCLIQUEVARSCOMP 1000000 /**< limit on number of pairwise comparisons in clique partitioning algorithm */
152#ifdef WITH_CARDINALITY_UPGRADE
153#define DEFAULT_UPGDCARDINALITY FALSE /**< if TRUE then try to update knapsack constraints to cardinality constraints */
154#endif
155#define DEFAULT_COPYTYPEDCONS FALSE /**< should knapsack constraints be copied as knapsack instead of linear? */
156
157/* @todo maybe use event SCIP_EVENTTYPE_VARUNLOCKED to decide for another dual-presolving run on a constraint */
158
159/*
160 * Data structures
161 */
162
163/** constraint handler data */
164struct SCIP_ConshdlrData
165{
166 int* ints1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
167 * you have to clear it at the end, exists only in presolving stage */
168 int* ints2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
169 * you have to clear it at the end, exists only in presolving stage */
170 SCIP_Longint* longints1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
171 * you have to clear it at the end, exists only in presolving stage */
172 SCIP_Longint* longints2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
173 * you have to clear it at the end, exists only in presolving stage */
174 SCIP_Bool* bools1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
175 * you have to clear it at the end, exists only in presolving stage */
176 SCIP_Bool* bools2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
177 * you have to clear it at the end, exists only in presolving stage */
178 SCIP_Bool* bools3; /**< cleared memory array, all entries are set to zero in initpre, if you use this
179 * you have to clear it at the end, exists only in presolving stage */
180 SCIP_Bool* bools4; /**< cleared memory array, all entries are set to zero in initpre, if you use this
181 * you have to clear it at the end, exists only in presolving stage */
182 SCIP_Real* reals1; /**< cleared memory array, all entries are set to zero in consinit, if you use this
183 * you have to clear it at the end */
184 int ints1size; /**< size of ints1 array */
185 int ints2size; /**< size of ints2 array */
186 int longints1size; /**< size of longints1 array */
187 int longints2size; /**< size of longints2 array */
188 int bools1size; /**< size of bools1 array */
189 int bools2size; /**< size of bools2 array */
190 int bools3size; /**< size of bools3 array */
191 int bools4size; /**< size of bools4 array */
192 int reals1size; /**< size of reals1 array */
193 int* probtoidxmap; /**< cleared memory array with default values -1; used for clique partitions */
194 int probtoidxmapsize; /**< size of probtoidxmap */
195 SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
196 SCIP_Real maxcardbounddist; /**< maximal relative distance from current node's dual bound to primal bound compared
197 * to best node's dual bound for separating knapsack cuts */
198 int sepacardfreq; /**< multiplier on separation frequency, how often knapsack cuts are separated */
199 int maxrounds; /**< maximal number of separation rounds per node (-1: unlimited) */
200 int maxroundsroot; /**< maximal number of separation rounds in the root node (-1: unlimited) */
201 int maxsepacuts; /**< maximal number of cuts separated per separation round */
202 int maxsepacutsroot; /**< maximal number of cuts separated per separation round in the root node */
203 SCIP_Bool disaggregation; /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
204 SCIP_Bool simplifyinequalities;/**< should presolving try to cancel down or delete coefficients in inequalities */
205 SCIP_Bool negatedclique; /**< should negated clique information be used in solving process */
206 SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
207 SCIP_Bool presolusehashing; /**< should hash table be used for detecting redundant constraints in advance */
208 SCIP_Bool dualpresolving; /**< should dual presolving steps be performed? */
209 SCIP_Bool usegubs; /**< should GUB information be used for separation? */
210 SCIP_Bool detectcutoffbound; /**< should presolving try to detect constraints parallel to the objective
211 * function defining an upper bound and prevent these constraints from
212 * entering the LP */
213 SCIP_Bool detectlowerbound; /**< should presolving try to detect constraints parallel to the objective
214 * function defining a lower bound and prevent these constraints from
215 * entering the LP */
216 SCIP_Bool updatecliquepartitions; /**< should clique partition information be updated when old partition seems outdated? */
217 SCIP_Real cliqueextractfactor;/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
218 SCIP_Real clqpartupdatefac; /**< factor on the growth of global cliques to decide when to update a previous
219 * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
220#ifdef WITH_CARDINALITY_UPGRADE
221 SCIP_Bool upgdcardinality; /**< if TRUE then try to update knapsack constraints to cardinality constraints */
222 SCIP_Bool upgradedcard; /**< whether we have already upgraded knapsack constraints to cardinality constraints */
223#endif
224 SCIP_Bool copytypedcons; /**< should knapsack constraints be copied as knapsack instead of linear? */
225};
226
227
228/** constraint data for knapsack constraints */
229struct SCIP_ConsData
230{
231 SCIP_VAR** vars; /**< variables in knapsack constraint */
232 SCIP_Longint* weights; /**< weights of variables in knapsack constraint */
233 SCIP_EVENTDATA** eventdata; /**< event data for bound change events of the variables */
234 int* cliquepartition; /**< clique indices of the clique partition */
235 int* negcliquepartition; /**< clique indices of the negated clique partition */
236 SCIP_ROW* row; /**< corresponding LP row */
237 SCIP_NLROW* nlrow; /**< corresponding NLP row */
238 int nvars; /**< number of variables in knapsack constraint */
239 int varssize; /**< size of vars, weights, and eventdata arrays */
240 int ncliques; /**< number of cliques in the clique partition */
241 int nnegcliques; /**< number of cliques in the negated clique partition */
242 int ncliqueslastnegpart;/**< number of global cliques the last time a negated clique partition was computed */
243 int ncliqueslastpart; /**< number of global cliques the last time a clique partition was computed */
244 SCIP_Longint capacity; /**< capacity of knapsack */
245 SCIP_Longint weightsum; /**< sum of all weights */
246 SCIP_Longint onesweightsum; /**< sum of weights of variables fixed to one */
247 unsigned int presolvedtiming:5; /**< max level in which the knapsack constraint is already presolved */
248 unsigned int sorted:1; /**< are the knapsack items sorted by weight? */
249 unsigned int cliquepartitioned:1;/**< is the clique partition valid? */
250 unsigned int negcliquepartitioned:1;/**< is the negated clique partition valid? */
251 unsigned int merged:1; /**< are the constraint's equal variables already merged? */
252 unsigned int cliquesadded:1; /**< were the cliques of the knapsack already added to clique table? */
253 unsigned int varsdeleted:1; /**< were variables deleted after last cleanup? */
254 unsigned int existmultaggr:1; /**< does this constraint contain multi-aggregations */
255};
256
257/** event data for bound changes events */
258struct SCIP_EventData
259{
260 SCIP_CONS* cons; /**< knapsack constraint to process the bound change for */
261 SCIP_Longint weight; /**< weight of variable */
262 int filterpos; /**< position of event in variable's event filter */
263};
264
265
266/** data structure to combine two sorting key values */
267struct sortkeypair
268{
269 SCIP_Real key1; /**< first sort key value */
270 SCIP_Real key2; /**< second sort key value */
271};
272typedef struct sortkeypair SORTKEYPAIR;
273
274/** status of GUB constraint */
276{
277 GUBVARSTATUS_UNINITIAL = -1, /** unintitialized variable status */
278 GUBVARSTATUS_CAPACITYEXCEEDED = 0, /** variable with weight exceeding the knapsack capacity */
279 GUBVARSTATUS_BELONGSTOSET_R = 1, /** variable in noncovervars R */
280 GUBVARSTATUS_BELONGSTOSET_F = 2, /** variable in noncovervars F */
281 GUBVARSTATUS_BELONGSTOSET_C2 = 3, /** variable in covervars C2 */
282 GUBVARSTATUS_BELONGSTOSET_C1 = 4 /** variable in covervars C1 */
283};
285
286/** status of variable in GUB constraint */
288{
289 GUBCONSSTATUS_UNINITIAL = -1, /** unintitialized GUB constraint status */
290 GUBCONSSTATUS_BELONGSTOSET_GR = 0, /** all GUB variables are in noncovervars R */
291 GUBCONSSTATUS_BELONGSTOSET_GF = 1, /** all GUB variables are in noncovervars F (and noncovervars R) */
292 GUBCONSSTATUS_BELONGSTOSET_GC2 = 2, /** all GUB variables are in covervars C2 */
293 GUBCONSSTATUS_BELONGSTOSET_GNC1 = 3, /** some GUB variables are in covervars C1, others in noncovervars R or F */
294 GUBCONSSTATUS_BELONGSTOSET_GOC1 = 4 /** all GUB variables are in covervars C1 */
295};
297
298/** data structure of GUB constraints */
300{
301 int* gubvars; /**< indices of GUB variables in knapsack constraint */
302 GUBVARSTATUS* gubvarsstatus; /**< status of GUB variables */
303 int ngubvars; /**< number of GUB variables */
304 int gubvarssize; /**< size of gubvars array */
305};
307
308/** data structure of a set of GUB constraints */
310{
311 SCIP_GUBCONS** gubconss; /**< GUB constraints in GUB set */
312 GUBCONSSTATUS* gubconsstatus; /**< status of GUB constraints */
313 int ngubconss; /**< number of GUB constraints */
314 int nvars; /**< number of variables in knapsack constraint */
315 int* gubconssidx; /**< index of GUB constraint (in gubconss array) of each knapsack variable */
316 int* gubvarsidx; /**< index in GUB constraint (in gubvars array) of each knapsack variable */
317};
319
320/*
321 * Local methods
322 */
323
324/** comparison method for two sorting key pairs */
325static
326SCIP_DECL_SORTPTRCOMP(compSortkeypairs)
327{
328 SORTKEYPAIR* sortkeypair1 = (SORTKEYPAIR*)elem1;
329 SORTKEYPAIR* sortkeypair2 = (SORTKEYPAIR*)elem2;
330
331 if( sortkeypair1->key1 < sortkeypair2->key1 )
332 return -1;
333 else if( sortkeypair1->key1 > sortkeypair2->key1 )
334 return +1;
335 else if( sortkeypair1->key2 < sortkeypair2->key2 )
336 return -1;
337 else if( sortkeypair1->key2 > sortkeypair2->key2 )
338 return +1;
339 else
340 return 0;
341}
342
343/** creates event data */
344static
346 SCIP* scip, /**< SCIP data structure */
347 SCIP_EVENTDATA** eventdata, /**< pointer to store event data */
348 SCIP_CONS* cons, /**< constraint */
349 SCIP_Longint weight /**< weight of variable */
350 )
351{
352 assert(eventdata != NULL);
353
354 SCIP_CALL( SCIPallocBlockMemory(scip, eventdata) );
355 (*eventdata)->cons = cons;
356 (*eventdata)->weight = weight;
357
358 return SCIP_OKAY;
359}
360
361/** frees event data */
362static
364 SCIP* scip, /**< SCIP data structure */
365 SCIP_EVENTDATA** eventdata /**< pointer to event data */
366 )
367{
368 assert(eventdata != NULL);
369
370 SCIPfreeBlockMemory(scip, eventdata);
371
372 return SCIP_OKAY;
373}
374
375/** sorts items in knapsack with nonincreasing weights */
376static
378 SCIP_CONSDATA* consdata /**< constraint data */
379 )
380{
381 assert(consdata != NULL);
382 assert(consdata->nvars == 0 || consdata->vars != NULL);
383 assert(consdata->nvars == 0 || consdata->weights != NULL);
384 assert(consdata->nvars == 0 || consdata->eventdata != NULL);
385 assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
386
387 if( !consdata->sorted )
388 {
389 int pos;
390 int lastcliquenum;
391 int v;
392
393 /* sort of five joint arrays of Long/pointer/pointer/ints/ints,
394 * sorted by first array in non-increasing order via sort template */
396 consdata->weights,
397 (void**)consdata->vars,
398 (void**)consdata->eventdata,
399 consdata->cliquepartition,
400 consdata->negcliquepartition,
401 consdata->nvars);
402
403 v = consdata->nvars - 1;
404 /* sort all items with same weight according to their variable index, used for hash value for fast pairwise comparison of all constraints */
405 while( v >= 0 )
406 {
407 int w = v - 1;
408
409 while( w >= 0 && consdata->weights[v] == consdata->weights[w] )
410 --w;
411
412 if( v - w > 1 )
413 {
414 /* sort all corresponding parts of arrays for which the weights are equal by using the variable index */
416 (void**)(&(consdata->vars[w+1])),
417 (void**)(&(consdata->eventdata[w+1])),
418 &(consdata->cliquepartition[w+1]),
419 &(consdata->negcliquepartition[w+1]),
420 SCIPvarComp,
421 v - w);
422 }
423 v = w;
424 }
425
426 /* we need to make sure that our clique numbers of our normal clique will be in increasing order without gaps */
427 if( consdata->cliquepartitioned )
428 {
429 lastcliquenum = 0;
430
431 for( pos = 0; pos < consdata->nvars; ++pos )
432 {
433 /* if the clique number in the normal clique at position pos is greater than the last found clique number the
434 * partition is invalid */
435 if( consdata->cliquepartition[pos] > lastcliquenum )
436 {
437 consdata->cliquepartitioned = FALSE;
438 break;
439 }
440 else if( consdata->cliquepartition[pos] == lastcliquenum )
441 ++lastcliquenum;
442 }
443 }
444 /* we need to make sure that our clique numbers of our negated clique will be in increasing order without gaps */
445 if( consdata->negcliquepartitioned )
446 {
447 lastcliquenum = 0;
448
449 for( pos = 0; pos < consdata->nvars; ++pos )
450 {
451 /* if the clique number in the negated clique at position pos is greater than the last found clique number the
452 * partition is invalid */
453 if( consdata->negcliquepartition[pos] > lastcliquenum )
454 {
455 consdata->negcliquepartitioned = FALSE;
456 break;
457 }
458 else if( consdata->negcliquepartition[pos] == lastcliquenum )
459 ++lastcliquenum;
460 }
461 }
462
463 consdata->sorted = TRUE;
464 }
465#ifndef NDEBUG
466 {
467 /* check if the weight array is sorted in a non-increasing way */
468 int i;
469 for( i = 0; i < consdata->nvars-1; ++i )
470 assert(consdata->weights[i] >= consdata->weights[i+1]);
471 }
472#endif
473}
474
475/** calculates a partition of the variables into cliques */
476static
478 SCIP* scip, /**< SCIP data structure */
479 SCIP_CONSHDLRDATA* conshdlrdata, /**< knapsack constraint handler data */
480 SCIP_CONSDATA* consdata, /**< constraint data */
481 SCIP_Bool normalclique, /**< Should normal cliquepartition be created? */
482 SCIP_Bool negatedclique /**< Should negated cliquepartition be created? */
483 )
484{
485 SCIP_Bool ispartitionoutdated;
486 SCIP_Bool isnegpartitionoutdated;
487 assert(consdata != NULL);
488 assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
489
490 /* rerun eventually if number of global cliques increased considerably since last partition */
491 ispartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->ncliques > 1
492 && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastpart));
493
494 if( normalclique && ( !consdata->cliquepartitioned || ispartitionoutdated ) )
495 {
496 SCIP_CALL( SCIPcalcCliquePartition(scip, consdata->vars, consdata->nvars, &conshdlrdata->probtoidxmap, &conshdlrdata->probtoidxmapsize,
497 consdata->cliquepartition, &consdata->ncliques) );
498 consdata->cliquepartitioned = TRUE;
499 consdata->ncliqueslastpart = SCIPgetNCliques(scip);
500 }
501
502 /* rerun eventually if number of global cliques increased considerably since last negated partition */
503 isnegpartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->nnegcliques > 1
504 && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastnegpart));
505
506 if( negatedclique && (!consdata->negcliquepartitioned || isnegpartitionoutdated) )
507 {
508 SCIP_CALL( SCIPcalcNegatedCliquePartition(scip, consdata->vars, consdata->nvars, &conshdlrdata->probtoidxmap, &conshdlrdata->probtoidxmapsize,
509 consdata->negcliquepartition, &consdata->nnegcliques) );
510 consdata->negcliquepartitioned = TRUE;
511 consdata->ncliqueslastnegpart = SCIPgetNCliques(scip);
512 }
513 assert(!consdata->cliquepartitioned || consdata->ncliques <= consdata->nvars);
514 assert(!consdata->negcliquepartitioned || consdata->nnegcliques <= consdata->nvars);
515
516 return SCIP_OKAY;
517}
518
519/** installs rounding locks for the given variable in the given knapsack constraint */
520static
522 SCIP* scip, /**< SCIP data structure */
523 SCIP_CONS* cons, /**< knapsack constraint */
524 SCIP_VAR* var /**< variable of constraint entry */
525 )
526{
528
529 return SCIP_OKAY;
530}
531
532/** removes rounding locks for the given variable in the given knapsack constraint */
533static
535 SCIP* scip, /**< SCIP data structure */
536 SCIP_CONS* cons, /**< knapsack constraint */
537 SCIP_VAR* var /**< variable of constraint entry */
538 )
539{
541
542 return SCIP_OKAY;
543}
544
545/** catches bound change events for variables in knapsack */
546static
548 SCIP* scip, /**< SCIP data structure */
549 SCIP_CONS* cons, /**< constraint */
550 SCIP_CONSDATA* consdata, /**< constraint data */
551 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
552 )
553{
554 int i;
555
556 assert(cons != NULL);
557 assert(consdata != NULL);
558 assert(consdata->nvars == 0 || consdata->vars != NULL);
559 assert(consdata->nvars == 0 || consdata->weights != NULL);
560 assert(consdata->nvars == 0 || consdata->eventdata != NULL);
561
562 for( i = 0; i < consdata->nvars; i++)
563 {
564 SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[i], cons, consdata->weights[i]) );
566 eventhdlr, consdata->eventdata[i], &consdata->eventdata[i]->filterpos) );
567 }
568
569 return SCIP_OKAY;
570}
571
572/** drops bound change events for variables in knapsack */
573static
575 SCIP* scip, /**< SCIP data structure */
576 SCIP_CONSDATA* consdata, /**< constraint data */
577 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
578 )
579{
580 int i;
581
582 assert(consdata != NULL);
583 assert(consdata->nvars == 0 || consdata->vars != NULL);
584 assert(consdata->nvars == 0 || consdata->weights != NULL);
585 assert(consdata->nvars == 0 || consdata->eventdata != NULL);
586
587 for( i = 0; i < consdata->nvars; i++)
588 {
590 eventhdlr, consdata->eventdata[i], consdata->eventdata[i]->filterpos) );
591 SCIP_CALL( eventdataFree(scip, &consdata->eventdata[i]) );
592 }
593
594 return SCIP_OKAY;
595}
596
597/** ensures, that vars and vals arrays can store at least num entries */
598static
600 SCIP* scip, /**< SCIP data structure */
601 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
602 int num, /**< minimum number of entries to store */
603 SCIP_Bool transformed /**< is constraint from transformed problem? */
604 )
605{
606 assert(consdata != NULL);
607 assert(consdata->nvars <= consdata->varssize);
608
609 if( num > consdata->varssize )
610 {
611 int newsize;
612
613 newsize = SCIPcalcMemGrowSize(scip, num);
614 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) );
615 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->weights, consdata->varssize, newsize) );
616 if( transformed )
617 {
618 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->eventdata, consdata->varssize, newsize) );
619 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->cliquepartition, consdata->varssize, newsize) );
620 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->negcliquepartition, consdata->varssize, newsize) );
621 }
622 else
623 {
624 assert(consdata->eventdata == NULL);
625 assert(consdata->cliquepartition == NULL);
626 assert(consdata->negcliquepartition == NULL);
627 }
628 consdata->varssize = newsize;
629 }
630 assert(num <= consdata->varssize);
631
632 return SCIP_OKAY;
633}
634
635/** updates all weight sums for fixed and unfixed variables */
636static
638 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
639 SCIP_VAR* var, /**< variable for this weight */
640 SCIP_Longint weightdelta /**< difference between the old and the new weight of the variable */
641 )
642{
643 assert(consdata != NULL);
644 assert(var != NULL);
645
646 consdata->weightsum += weightdelta;
647
648 if( SCIPvarGetLbLocal(var) > 0.5 )
649 consdata->onesweightsum += weightdelta;
650
651 assert(consdata->weightsum >= 0);
652 assert(consdata->onesweightsum >= 0);
653}
654
655/** creates knapsack constraint data */
656static
658 SCIP* scip, /**< SCIP data structure */
659 SCIP_CONSDATA** consdata, /**< pointer to store constraint data */
660 int nvars, /**< number of variables in knapsack */
661 SCIP_VAR** vars, /**< variables of knapsack */
662 SCIP_Longint* weights, /**< weights of knapsack items */
663 SCIP_Longint capacity /**< capacity of knapsack */
664 )
665{
666 int v;
667 SCIP_Longint constant;
668
669 assert(consdata != NULL);
670
671 SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
672
673 constant = 0L;
674 (*consdata)->vars = NULL;
675 (*consdata)->weights = NULL;
676 (*consdata)->nvars = 0;
677 if( nvars > 0 )
678 {
679 SCIP_VAR** varsbuffer;
680 SCIP_Longint* weightsbuffer;
681 int k;
682
683 SCIP_CALL( SCIPallocBufferArray(scip, &varsbuffer, nvars) );
684 SCIP_CALL( SCIPallocBufferArray(scip, &weightsbuffer, nvars) );
685
686 k = 0;
687 for( v = 0; v < nvars; ++v )
688 {
689 assert(vars[v] != NULL);
691
692 /* all weight have to be non negative */
693 assert( weights[v] >= 0 );
694
695 if( weights[v] > 0 )
696 {
697 /* treat fixed variables as constants if problem compression is enabled */
699 {
700 /* only if the variable is fixed to 1, we add its weight to the constant */
701 if( SCIPvarGetUbGlobal(vars[v]) > 0.5 )
702 constant += weights[v];
703 }
704 else
705 {
706 varsbuffer[k] = vars[v];
707 weightsbuffer[k] = weights[v];
708 ++k;
709 }
710 }
711 }
712 assert(k >= 0);
713 assert(constant >= 0);
714
715 (*consdata)->nvars = k;
716
717 /* copy the active variables and weights into the constraint data structure */
718 if( k > 0 )
719 {
720 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, varsbuffer, k) );
721 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->weights, weightsbuffer, k) );
722 }
723
724 /* free buffer storage */
725 SCIPfreeBufferArray(scip, &weightsbuffer);
726 SCIPfreeBufferArray(scip, &varsbuffer);
727 }
728
729 (*consdata)->varssize = (*consdata)->nvars;
730 (*consdata)->capacity = capacity - constant;
731 (*consdata)->eventdata = NULL;
732 (*consdata)->cliquepartition = NULL;
733 (*consdata)->negcliquepartition = NULL;
734 (*consdata)->row = NULL;
735 (*consdata)->nlrow = NULL;
736 (*consdata)->weightsum = 0;
737 (*consdata)->onesweightsum = 0;
738 (*consdata)->ncliques = 0;
739 (*consdata)->nnegcliques = 0;
740 (*consdata)->presolvedtiming = 0;
741 (*consdata)->sorted = FALSE;
742 (*consdata)->cliquepartitioned = FALSE;
743 (*consdata)->negcliquepartitioned = FALSE;
744 (*consdata)->ncliqueslastpart = -1;
745 (*consdata)->ncliqueslastnegpart = -1;
746 (*consdata)->merged = FALSE;
747 (*consdata)->cliquesadded = FALSE;
748 (*consdata)->varsdeleted = FALSE;
749 (*consdata)->existmultaggr = FALSE;
750
751 /* get transformed variables, if we are in the transformed problem */
753 {
754 SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
755
756 for( v = 0; v < (*consdata)->nvars; v++ )
757 {
758 SCIP_VAR* var = SCIPvarGetProbvar((*consdata)->vars[v]);
759 assert(var != NULL);
760 (*consdata)->existmultaggr = (*consdata)->existmultaggr || (SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
761 }
762
763 /* allocate memory for additional data structures */
764 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->nvars) );
765 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->nvars) );
766 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->nvars) );
767 }
768
769 /* calculate sum of weights and capture variables */
770 for( v = 0; v < (*consdata)->nvars; ++v )
771 {
772 /* calculate sum of weights */
773 updateWeightSums(*consdata, (*consdata)->vars[v], (*consdata)->weights[v]);
774
775 /* capture variables */
776 SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) );
777 }
778 return SCIP_OKAY;
779}
780
781/** frees knapsack constraint data */
782static
784 SCIP* scip, /**< SCIP data structure */
785 SCIP_CONSDATA** consdata, /**< pointer to the constraint data */
786 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
787 )
788{
789 assert(consdata != NULL);
790 assert(*consdata != NULL);
791
792 if( (*consdata)->row != NULL )
793 {
794 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->row) );
795 }
796 if( (*consdata)->nlrow != NULL )
797 {
798 SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
799 }
800 if( (*consdata)->eventdata != NULL )
801 {
802 SCIP_CALL( dropEvents(scip, *consdata, eventhdlr) );
803 SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->varssize);
804 }
805 if( (*consdata)->negcliquepartition != NULL )
806 {
807 SCIPfreeBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->varssize);
808 }
809 if( (*consdata)->cliquepartition != NULL )
810 {
811 SCIPfreeBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->varssize);
812 }
813 if( (*consdata)->vars != NULL )
814 {
815 int v;
816
817 /* release variables */
818 for( v = 0; v < (*consdata)->nvars; v++ )
819 {
820 assert((*consdata)->vars[v] != NULL);
821 SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->vars[v])) );
822 }
823
824 assert( (*consdata)->weights != NULL );
825 assert( (*consdata)->varssize > 0 );
826 SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->varssize);
827 SCIPfreeBlockMemoryArray(scip, &(*consdata)->weights, (*consdata)->varssize);
828 }
829
830 SCIPfreeBlockMemory(scip, consdata);
831
832 return SCIP_OKAY;
833}
834
835/** changes a single weight in knapsack constraint data */
836static
838 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
839 int item, /**< item number */
840 SCIP_Longint newweight /**< new weight of item */
841 )
842{
843 SCIP_Longint oldweight;
844 SCIP_Longint weightdiff;
845
846 assert(consdata != NULL);
847 assert(0 <= item && item < consdata->nvars);
848
849 oldweight = consdata->weights[item];
850 weightdiff = newweight - oldweight;
851 consdata->weights[item] = newweight;
852
853 /* update weight sums for all and fixed variables */
854 updateWeightSums(consdata, consdata->vars[item], weightdiff);
855
856 if( consdata->eventdata != NULL )
857 {
858 assert(consdata->eventdata[item] != NULL);
859 assert(consdata->eventdata[item]->weight == oldweight);
860 consdata->eventdata[item]->weight = newweight;
861 }
862
863 consdata->presolvedtiming = 0;
864 consdata->sorted = FALSE;
865
866 /* recalculate cliques extraction after a weight was increased */
867 if( oldweight < newweight )
868 {
869 consdata->cliquesadded = FALSE;
870 }
871}
872
873/** creates LP row corresponding to knapsack constraint */
874static
876 SCIP* scip, /**< SCIP data structure */
877 SCIP_CONS* cons /**< knapsack constraint */
878 )
879{
880 SCIP_CONSDATA* consdata;
881 int i;
882
883 consdata = SCIPconsGetData(cons);
884 assert(consdata != NULL);
885 assert(consdata->row == NULL);
886
887 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, cons, SCIPconsGetName(cons),
888 -SCIPinfinity(scip), (SCIP_Real)consdata->capacity,
890
891 SCIP_CALL( SCIPcacheRowExtensions(scip, consdata->row) );
892 for( i = 0; i < consdata->nvars; ++i )
893 {
894 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, consdata->vars[i], (SCIP_Real)consdata->weights[i]) );
895 }
896 SCIP_CALL( SCIPflushRowExtensions(scip, consdata->row) );
897
898 return SCIP_OKAY;
899}
900
901/** adds linear relaxation of knapsack constraint to the LP */
902static
904 SCIP* scip, /**< SCIP data structure */
905 SCIP_CONS* cons, /**< knapsack constraint */
906 SCIP_Bool* cutoff /**< whether a cutoff has been detected */
907 )
908{
909 SCIP_CONSDATA* consdata;
910
911 assert( cutoff != NULL );
912 *cutoff = FALSE;
913
914 consdata = SCIPconsGetData(cons);
915 assert(consdata != NULL);
916
917 if( consdata->row == NULL )
918 {
920 }
921 assert(consdata->row != NULL);
922
923 /* insert LP row as cut */
924 if( !SCIProwIsInLP(consdata->row) )
925 {
926 SCIPdebugMsg(scip, "adding relaxation of knapsack constraint <%s> (capacity %" SCIP_LONGINT_FORMAT "): ",
927 SCIPconsGetName(cons), consdata->capacity);
928 SCIPdebug( SCIP_CALL( SCIPprintRow(scip, consdata->row, NULL) ) );
929 SCIP_CALL( SCIPaddRow(scip, consdata->row, FALSE, cutoff) );
930 }
931
932 return SCIP_OKAY;
933}
934
935/** adds knapsack constraint as row to the NLP, if not added yet */
936static
938 SCIP* scip, /**< SCIP data structure */
939 SCIP_CONS* cons /**< knapsack constraint */
940 )
941{
942 SCIP_CONSDATA* consdata;
943
945
946 /* skip deactivated, redundant, or local linear constraints (the NLP does not allow for local rows at the moment) */
947 if( !SCIPconsIsActive(cons) || !SCIPconsIsChecked(cons) || SCIPconsIsLocal(cons) )
948 return SCIP_OKAY;
949
950 consdata = SCIPconsGetData(cons);
951 assert(consdata != NULL);
952
953 if( consdata->nlrow == NULL )
954 {
955 SCIP_Real* coefs;
956 int i;
957
958 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, consdata->nvars) );
959 for( i = 0; i < consdata->nvars; ++i )
960 coefs[i] = (SCIP_Real)consdata->weights[i]; /*lint !e613*/
961
962 SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
963 consdata->nvars, consdata->vars, coefs, NULL,
964 -SCIPinfinity(scip), (SCIP_Real)consdata->capacity, SCIP_EXPRCURV_LINEAR) );
965
966 assert(consdata->nlrow != NULL);
967
968 SCIPfreeBufferArray(scip, &coefs);
969 }
970
971 if( !SCIPnlrowIsInNLP(consdata->nlrow) )
972 {
973 SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
974 }
975
976 return SCIP_OKAY;
977}
978
979/** checks knapsack constraint for feasibility of given solution: returns TRUE iff constraint is feasible */
980static
982 SCIP* scip, /**< SCIP data structure */
983 SCIP_CONS* cons, /**< constraint to check */
984 SCIP_SOL* sol, /**< solution to check, NULL for current solution */
985 SCIP_Bool checklprows, /**< Do constraints represented by rows in the current LP have to be checked? */
986 SCIP_Bool printreason, /**< Should the reason for the violation be printed? */
987 SCIP_Bool* violated /**< pointer to store whether the constraint is violated */
988 )
989{
990 SCIP_CONSDATA* consdata;
991
992 assert(violated != NULL);
993
994 consdata = SCIPconsGetData(cons);
995 assert(consdata != NULL);
996
997 SCIPdebugMsg(scip, "checking knapsack constraint <%s> for feasibility of solution %p (lprows=%u)\n",
998 SCIPconsGetName(cons), (void*)sol, checklprows);
999
1000 *violated = FALSE;
1001
1002 if( checklprows || consdata->row == NULL || !SCIProwIsInLP(consdata->row) )
1003 {
1004 SCIP_Real normsum = 0.0;
1005 SCIP_Real hugesum = 0.0;
1006 SCIP_Real absviol;
1007 SCIP_Real relviol;
1008 int v;
1009
1010 /* increase age of constraint; age is reset to zero, if a violation was found only in case we are in
1011 * enforcement
1012 */
1013 if( sol == NULL )
1014 {
1015 SCIP_CALL( SCIPincConsAge(scip, cons) );
1016 }
1017
1018 /* sum separately over normal and huge weight contributions in order to reduce numerical cancellation */
1019 for( v = consdata->nvars - 1; v >= 0; --v )
1020 {
1021 assert(SCIPvarIsBinary(consdata->vars[v]));
1022
1023 if( SCIPisHugeValue(scip, (SCIP_Real)consdata->weights[v]) )
1024 hugesum += consdata->weights[v] * SCIPgetSolVal(scip, sol, consdata->vars[v]);
1025 else
1026 normsum += consdata->weights[v] * SCIPgetSolVal(scip, sol, consdata->vars[v]);
1027 }
1028
1029 /* calculate constraint violation and update it in solution */
1030 normsum += hugesum;
1031
1032 if( normsum > consdata->capacity )
1033 {
1034 absviol = normsum - consdata->capacity;
1035 relviol = SCIPrelDiff(normsum, (SCIP_Real)consdata->capacity);
1036 }
1037 else
1038 {
1039 absviol = 0.0;
1040 relviol = 0.0;
1041 }
1042
1043 if( sol != NULL )
1044 SCIPupdateSolLPConsViolation(scip, sol, absviol, relviol);
1045
1046 if( SCIPisFeasPositive(scip, absviol) )
1047 {
1048 *violated = TRUE;
1049
1050 /* only reset constraint age if we are in enforcement */
1051 if( sol == NULL )
1052 {
1054 }
1055
1056 if( printreason )
1057 {
1058 SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
1059
1060 SCIPinfoMessage(scip, NULL, ";\n");
1061 SCIPinfoMessage(scip, NULL, "violation: the capacity is violated by %.15g\n", absviol);
1062 }
1063 }
1064 }
1065
1066 return SCIP_OKAY;
1067}
1068
1069/* IDX computes the integer index for the optimal solution array */
1070#define IDX(j,d) ((j)*(intcap)+(d))
1071
1072/** solves knapsack problem in maximization form exactly using dynamic programming;
1073 * if needed, one can provide arrays to store all selected items and all not selected items
1074 *
1075 * @note in case you provide the solitems or nonsolitems array you also have to provide the counter part, as well
1076 *
1077 * @note the algorithm will first compute a greedy solution and terminate
1078 * if the greedy solution is proven to be optimal.
1079 * The dynamic programming algorithm runs with a time and space complexity
1080 * of O(nitems * capacity).
1081 *
1082 * @todo If only the objective is relevant, it is easy to change the code to use only one slice with O(capacity) space.
1083 * There are recursive methods (see the book by Kellerer et al.) that require O(capacity) space, but it remains
1084 * to be checked whether they are faster and whether they can reconstruct the solution.
1085 * Dembo and Hammer (see Kellerer et al. Section 5.1.3, page 126) found a method that relies on a fast probing method.
1086 * This fixes additional elements to 0 or 1 similar to a reduced cost fixing.
1087 * This could be implemented, however, it would be technically a bit cumbersome,
1088 * since one needs the greedy solution and the LP-value for this.
1089 * This is currently only available after the redundant items have already been sorted out.
1090 */
1092 SCIP* scip, /**< SCIP data structure */
1093 int nitems, /**< number of available items */
1094 SCIP_Longint* weights, /**< item weights */
1095 SCIP_Real* profits, /**< item profits */
1096 SCIP_Longint capacity, /**< capacity of knapsack */
1097 int* items, /**< item numbers */
1098 int* solitems, /**< array to store items in solution, or NULL */
1099 int* nonsolitems, /**< array to store items not in solution, or NULL */
1100 int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1101 int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1102 SCIP_Real* solval, /**< pointer to store optimal solution value, or NULL */
1103 SCIP_Bool* success /**< pointer to store if an error occurred during solving
1104 * (normally a memory problem) */
1105 )
1106{
1107 SCIP_RETCODE retcode;
1108 SCIP_Real* tempsort;
1109 SCIP_Real* optvalues;
1110 int intcap;
1111 int d;
1112 int j;
1113 int greedymedianpos;
1114 SCIP_Longint weightsum;
1115 int* myitems;
1116 SCIP_Longint* myweights;
1117 SCIP_Real* realweights;
1118 int* allcurrminweight;
1119 SCIP_Real* myprofits;
1120 int nmyitems;
1121 SCIP_Longint gcd;
1122 SCIP_Longint minweight;
1123 SCIP_Longint maxweight;
1124 int currminweight;
1125 SCIP_Longint greedysolweight;
1126 SCIP_Real greedysolvalue;
1127 SCIP_Real greedyupperbound;
1128 SCIP_Bool eqweights;
1129 SCIP_Bool intprofits;
1130 int lastitem; /* last item processed in DP (for early termination) */
1131
1132 assert(weights != NULL);
1133 assert(profits != NULL);
1134 assert(capacity >= 0);
1135 assert(items != NULL);
1136 assert(nitems >= 0);
1137 assert(success != NULL);
1138
1139 *success = TRUE;
1140
1141#ifndef NDEBUG
1142 for( j = nitems - 1; j >= 0; --j )
1143 assert(weights[j] >= 0);
1144#endif
1145
1146 SCIPdebugMsg(scip, "Solving knapsack exactly.\n");
1147
1148 /* initializing solution value */
1149 if( solval != NULL )
1150 *solval = 0.0;
1151
1152 /* init solution information */
1153 if( solitems != NULL )
1154 {
1155 assert(items != NULL);
1156 assert(nsolitems != NULL);
1157 assert(nonsolitems != NULL);
1158 assert(nnonsolitems != NULL);
1159
1160 *nnonsolitems = 0;
1161 *nsolitems = 0;
1162 }
1163
1164 /* allocate temporary memory */
1165 SCIP_CALL( SCIPallocBufferArray(scip, &myweights, nitems) );
1166 SCIP_CALL( SCIPallocBufferArray(scip, &myprofits, nitems) );
1167 SCIP_CALL( SCIPallocBufferArray(scip, &myitems, nitems) );
1168 nmyitems = 0;
1169 weightsum = 0;
1170 minweight = SCIP_LONGINT_MAX;
1171 maxweight = 0;
1172
1173 /* remove unnecessary items */
1174 for( j = 0; j < nitems; ++j )
1175 {
1176 assert(0 <= weights[j] && weights[j] < SCIP_LONGINT_MAX);
1177
1178 /* item does not fit */
1179 if( weights[j] > capacity )
1180 {
1181 if( solitems != NULL )
1182 nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
1183 }
1184 /* item is not profitable */
1185 else if( profits[j] <= 0.0 )
1186 {
1187 if( solitems != NULL )
1188 nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
1189 }
1190 /* item always fits */
1191 else if( weights[j] == 0 )
1192 {
1193 if( solitems != NULL )
1194 solitems[(*nsolitems)++] = items[j]; /*lint !e413*/
1195
1196 if( solval != NULL )
1197 *solval += profits[j];
1198 }
1199 /* all important items */
1200 else
1201 {
1202 myweights[nmyitems] = weights[j];
1203 myprofits[nmyitems] = profits[j];
1204 myitems[nmyitems] = items[j];
1205
1206 /* remember smallest item */
1207 if( myweights[nmyitems] < minweight )
1208 minweight = myweights[nmyitems];
1209
1210 /* remember bigest item */
1211 if( myweights[nmyitems] > maxweight )
1212 maxweight = myweights[nmyitems];
1213
1214 weightsum += myweights[nmyitems];
1215 ++nmyitems;
1216 }
1217 }
1218
1219 intprofits = TRUE;
1220 /* check if all profits are integer to strengthen the upper bound on the greedy solution */
1221 for( j = 0; j < nmyitems && intprofits; ++j )
1222 intprofits = intprofits && SCIPisIntegral(scip, myprofits[j]);
1223
1224 /* if no item is left then goto end */
1225 if( nmyitems == 0 )
1226 {
1227 SCIPdebugMsg(scip, "After preprocessing no items are left.\n");
1228
1229 goto TERMINATE;
1230 }
1231
1232 /* if all items fit, we also do not need to do the expensive stuff later on */
1233 if( weightsum > 0 && weightsum <= capacity )
1234 {
1235 SCIPdebugMsg(scip, "After preprocessing all items fit into knapsack.\n");
1236
1237 for( j = nmyitems - 1; j >= 0; --j )
1238 {
1239 if( solitems != NULL )
1240 solitems[(*nsolitems)++] = myitems[j]; /*lint !e413*/
1241
1242 if( solval != NULL )
1243 *solval += myprofits[j];
1244 }
1245
1246 goto TERMINATE;
1247 }
1248
1249 assert(0 < minweight && minweight <= capacity );
1250 assert(0 < maxweight && maxweight <= capacity);
1251
1252 /* make weights relatively prime */
1253 eqweights = TRUE;
1254 if( maxweight > 1 )
1255 {
1256 /* determine greatest common divisor */
1257 gcd = myweights[nmyitems - 1];
1258 for( j = nmyitems - 2; j >= 0 && gcd >= 2; --j )
1259 gcd = SCIPcalcGreComDiv(gcd, myweights[j]);
1260
1261 SCIPdebugMsg(scip, "Gcd is %" SCIP_LONGINT_FORMAT ".\n", gcd);
1262
1263 /* divide by greatest common divisor */
1264 if( gcd > 1 )
1265 {
1266 for( j = nmyitems - 1; j >= 0; --j )
1267 {
1268 myweights[j] /= gcd;
1269 eqweights = eqweights && (myweights[j] == 1);
1270 }
1271 capacity /= gcd;
1272 minweight /= gcd;
1273 }
1274 else
1275 eqweights = FALSE;
1276 }
1277 assert(minweight <= capacity);
1278
1279 /* if only one item fits, then take the best */
1280 if( minweight > capacity / 2 )
1281 {
1282 int p;
1283
1284 SCIPdebugMsg(scip, "Only one item fits into knapsack, so take the best.\n");
1285
1286 p = nmyitems - 1;
1287
1288 /* find best item */
1289 for( j = nmyitems - 2; j >= 0; --j )
1290 {
1291 if( myprofits[j] > myprofits[p] )
1292 p = j;
1293 }
1294
1295 /* update solution information */
1296 if( solitems != NULL )
1297 {
1298 assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1299
1300 solitems[(*nsolitems)++] = myitems[p];
1301 for( j = nmyitems - 1; j >= 0; --j )
1302 {
1303 if( j != p )
1304 nonsolitems[(*nnonsolitems)++] = myitems[j];
1305 }
1306 }
1307 /* update solution value */
1308 if( solval != NULL )
1309 *solval += myprofits[p];
1310
1311 goto TERMINATE;
1312 }
1313
1314 /* if all items have the same weight, then take the best */
1315 if( eqweights )
1316 {
1317 SCIP_Real addval = 0.0;
1318
1319 SCIPdebugMsg(scip, "All weights are equal, so take the best.\n");
1320
1321 SCIPsortDownRealIntLong(myprofits, myitems, myweights, nmyitems);
1322
1323 /* update solution information */
1324 if( solitems != NULL || solval != NULL )
1325 {
1327
1328 /* if all items would fit we had handled this case before */
1329 assert((SCIP_Longint) nmyitems > capacity);
1330 assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1331
1332 /* take the first best items into the solution */
1333 for( i = capacity - 1; i >= 0; --i )
1334 {
1335 if( solitems != NULL )
1336 solitems[(*nsolitems)++] = myitems[i];
1337 addval += myprofits[i];
1338 }
1339
1340 if( solitems != NULL )
1341 {
1342 /* the rest are not in the solution */
1343 for( i = nmyitems - 1; i >= capacity; --i )
1344 nonsolitems[(*nnonsolitems)++] = myitems[i];
1345 }
1346 }
1347 /* update solution value */
1348 if( solval != NULL )
1349 {
1350 assert(addval > 0.0);
1351 *solval += addval;
1352 }
1353
1354 goto TERMINATE;
1355 }
1356
1357 SCIPdebugMsg(scip, "Determine greedy solution.\n");
1358
1359 /* sort myitems (plus corresponding arrays myweights and myprofits) such that
1360 * p_1/w_1 >= p_2/w_2 >= ... >= p_n/w_n, this is only used for the greedy solution
1361 */
1362 SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nmyitems) );
1363 SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nmyitems) );
1364
1365 for( j = 0; j < nmyitems; ++j )
1366 {
1367 tempsort[j] = myprofits[j]/((SCIP_Real) myweights[j]);
1368 realweights[j] = (SCIP_Real)myweights[j];
1369 }
1370
1371 SCIPselectWeightedDownRealLongRealInt(tempsort, myweights, myprofits, myitems, realweights,
1372 (SCIP_Real)capacity, nmyitems, &greedymedianpos);
1373
1374 SCIPfreeBufferArray(scip, &realweights);
1375 SCIPfreeBufferArray(scip, &tempsort);
1376
1377 /* initialize values for greedy solution information */
1378 greedysolweight = 0;
1379 greedysolvalue = 0.0;
1380
1381 /* determine greedy solution */
1382 for( j = 0; j < greedymedianpos; ++j )
1383 {
1384 assert(myweights[j] <= capacity);
1385
1386 /* update greedy solution weight and value */
1387 greedysolweight += myweights[j];
1388 greedysolvalue += myprofits[j];
1389 }
1390
1391 assert(0 < greedysolweight && greedysolweight <= capacity);
1392 assert(greedysolvalue > 0.0);
1393
1394 /* If the greedy solution is optimal by comparing to the LP solution, we take this solution. This happens if:
1395 * - the greedy solution reaches the capacity, because then the LP solution is integral;
1396 * - the greedy solution has an objective that is at least the LP value rounded down in case that all profits are integer, too. */
1397 greedyupperbound = greedysolvalue + myprofits[j] * (SCIP_Real) (capacity - greedysolweight)/((SCIP_Real) myweights[j]);
1398 if( intprofits )
1399 greedyupperbound = SCIPfloor(scip, greedyupperbound);
1400 if( greedysolweight == capacity || SCIPisGE(scip, greedysolvalue, greedyupperbound) )
1401 {
1402 SCIPdebugMsg(scip, "Greedy solution is optimal.\n");
1403
1404 /* update solution information */
1405 if( solitems != NULL )
1406 {
1407 int l;
1408
1409 assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1410
1411 /* collect items */
1412 for( l = 0; l < j; ++l )
1413 solitems[(*nsolitems)++] = myitems[l];
1414 for ( ; l < nmyitems; ++l )
1415 nonsolitems[(*nnonsolitems)++] = myitems[l];
1416 }
1417 /* update solution value */
1418 if( solval != NULL )
1419 {
1420 assert(greedysolvalue > 0.0);
1421 *solval += greedysolvalue;
1422 }
1423
1424 goto TERMINATE;
1425 }
1426
1427 /* in the following table we do not need the first minweight columns */
1428 capacity -= (minweight - 1);
1429
1430 /* we can only handle integers */
1431 if( capacity >= INT_MAX )
1432 {
1433 SCIPdebugMsg(scip, "Capacity is to big, so we cannot handle it here.\n");
1434
1435 *success = FALSE;
1436 goto TERMINATE;
1437 }
1438 assert(capacity < INT_MAX);
1439
1440 intcap = (int)capacity;
1441 assert(intcap >= 0);
1442 assert(nmyitems > 0);
1443 assert(sizeof(size_t) >= sizeof(int)); /*lint !e506*/ /* no following conversion should be messed up */
1444
1445 /* this condition checks whether we will try to allocate a correct number of bytes and do not have an overflow, while
1446 * computing the size for the allocation
1447 */
1448 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*/
1449 {
1450 SCIPdebugMsg(scip, "Too much memory (%lu) would be consumed.\n", (unsigned long) (((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues))); /*lint !e571*/
1451
1452 *success = FALSE;
1453 goto TERMINATE;
1454 }
1455
1456 /* allocate temporary memory and check for memory exceedance */
1457 retcode = SCIPallocBufferArray(scip, &optvalues, nmyitems * intcap);
1458 if( retcode == SCIP_NOMEMORY )
1459 {
1460 SCIPdebugMsg(scip, "Did not get enough memory.\n");
1461
1462 *success = FALSE;
1463 goto TERMINATE;
1464 }
1465 else
1466 {
1467 SCIP_CALL( retcode );
1468 }
1469
1470 SCIPdebugMsg(scip, "Start real exact algorithm.\n");
1471
1472 /* we memorize at each step the current minimal weight to later on know which value in our optvalues matrix is valid;
1473 * each value entries of the j-th row of optvalues is valid if the index is >= allcurrminweight[j], otherwise it is
1474 * invalid; a second possibility would be to clear the whole optvalues, which should be more expensive than storing
1475 * 'nmyitem' values
1476 */
1477 SCIP_CALL( SCIPallocBufferArray(scip, &allcurrminweight, nmyitems) );
1478 assert(myweights[0] - minweight < INT_MAX);
1479 currminweight = (int) (myweights[0] - minweight);
1480 allcurrminweight[0] = currminweight;
1481
1482 /* fills first row of dynamic programming table with optimal values */
1483 for( d = currminweight; d < intcap; ++d )
1484 optvalues[d] = myprofits[0];
1485
1486 /* by default, all items are processed */
1487 lastitem = nmyitems - 1;
1488
1489 /* fills dynamic programming table with optimal values */
1490 for( j = 1; j < nmyitems; ++j )
1491 {
1492 int intweight;
1493
1494 /* compute important part of weight, which will be represented in the table */
1495 intweight = (int)(myweights[j] - minweight);
1496 assert(0 <= intweight && intweight < intcap);
1497
1498 /* copy all nonzeros from row above */
1499 for( d = currminweight; d < intweight && d < intcap; ++d )
1500 optvalues[IDX(j,d)] = optvalues[IDX(j-1,d)];
1501
1502 /* update corresponding row */
1503 for( d = intweight; d < intcap; ++d )
1504 {
1505 /* if index d < current minweight then optvalues[IDX(j-1,d)] is not initialized, i.e. should be 0 */
1506 if( d < currminweight )
1507 optvalues[IDX(j,d)] = myprofits[j];
1508 else
1509 {
1510 SCIP_Real sumprofit;
1511
1512 if( d - myweights[j] < currminweight )
1513 sumprofit = myprofits[j];
1514 else
1515 sumprofit = optvalues[IDX(j-1,(int)(d-myweights[j]))] + myprofits[j];
1516
1517 optvalues[IDX(j,d)] = MAX(sumprofit, optvalues[IDX(j-1,d)]);
1518 }
1519 }
1520
1521 /* update currminweight */
1522 if( intweight < currminweight )
1523 currminweight = intweight;
1524
1525 allcurrminweight[j] = currminweight;
1526
1527 /* early termination: if current best value reaches the LP upper bound, we have found an optimal solution */
1528 if( intprofits && optvalues[IDX(j, intcap - 1)] >= greedyupperbound )
1529 {
1530 lastitem = j;
1531 break;
1532 }
1533 }
1534
1535 /* update optimal solution by following the table */
1536 if( solitems != NULL )
1537 {
1538 assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1539 d = intcap - 1;
1540
1541 SCIPdebugMsg(scip, "Fill the solution vector after solving exactly.\n");
1542
1543 /* items after lastitem were not processed due to early termination; they are not in the solution */
1544 for( j = nmyitems - 1; j > lastitem; --j )
1545 nonsolitems[(*nnonsolitems)++] = myitems[j];
1546
1547 /* insert all items in (non-) solution vector */
1548 for( j = lastitem; j > 0; --j )
1549 {
1550 /* if the following condition holds this means all remaining items does not fit anymore */
1551 if( d < allcurrminweight[j] )
1552 {
1553 /* we cannot have exceeded our capacity */
1554 assert((SCIP_Longint) d >= -minweight);
1555 break;
1556 }
1557
1558 /* collect solution items; the first condition means that no further item can fit anymore, but this does */
1559 if( d < allcurrminweight[j-1] || optvalues[IDX(j,d)] > optvalues[IDX(j-1,d)] )
1560 {
1561 solitems[(*nsolitems)++] = myitems[j];
1562
1563 /* check that we do not have an underflow */
1564 assert(myweights[j] <= (INT_MAX + (SCIP_Longint) d));
1565 d = (int)(d - myweights[j]);
1566 }
1567 /* collect non-solution items */
1568 else
1569 nonsolitems[(*nnonsolitems)++] = myitems[j];
1570 }
1571
1572 /* insert remaining items */
1573 if( d >= allcurrminweight[j] )
1574 {
1575 assert(j == 0);
1576 solitems[(*nsolitems)++] = myitems[j];
1577 }
1578 else
1579 {
1580 assert(j >= 0);
1581 assert(d < allcurrminweight[j]);
1582
1583 for( ; j >= 0; --j )
1584 nonsolitems[(*nnonsolitems)++] = myitems[j];
1585 }
1586
1587 assert(*nsolitems + *nnonsolitems == nitems);
1588 }
1589
1590 /* update solution value */
1591 if( solval != NULL )
1592 *solval += optvalues[IDX(lastitem, intcap - 1)];
1593 SCIPfreeBufferArray(scip, &allcurrminweight);
1594
1595 /* free all temporary memory */
1596 SCIPfreeBufferArray(scip, &optvalues);
1597
1598 TERMINATE:
1599 SCIPfreeBufferArray(scip, &myitems);
1600 SCIPfreeBufferArray(scip, &myprofits);
1601 SCIPfreeBufferArray(scip, &myweights);
1602
1603 return SCIP_OKAY;
1604}
1605
1606/** solves knapsack problem in maximization form approximately by solving the LP-relaxation of the problem using Dantzig's
1607 * method and rounding down the solution; if needed, one can provide arrays to store all selected items and all not
1608 * selected items
1609 */
1611 SCIP* scip, /**< SCIP data structure */
1612 int nitems, /**< number of available items */
1613 SCIP_Longint* weights, /**< item weights */
1614 SCIP_Real* profits, /**< item profits */
1615 SCIP_Longint capacity, /**< capacity of knapsack */
1616 int* items, /**< item numbers */
1617 int* solitems, /**< array to store items in solution, or NULL */
1618 int* nonsolitems, /**< array to store items not in solution, or NULL */
1619 int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1620 int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1621 SCIP_Real* solval /**< pointer to store optimal solution value, or NULL */
1622 )
1623{
1624 SCIP_Real* tempsort;
1625 SCIP_Longint solitemsweight;
1626 SCIP_Real* realweights;
1627 int j;
1628 int criticalindex;
1629
1630 assert(weights != NULL);
1631 assert(profits != NULL);
1632 assert(capacity >= 0);
1633 assert(items != NULL);
1634 assert(nitems >= 0);
1635
1636 if( solitems != NULL )
1637 {
1638 *nsolitems = 0;
1639 *nnonsolitems = 0;
1640 }
1641 if( solval != NULL )
1642 *solval = 0.0;
1643
1644 /* initialize data for median search */
1645 SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nitems) );
1646 SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nitems) );
1647 for( j = nitems - 1; j >= 0; --j )
1648 {
1649 tempsort[j] = profits[j]/((SCIP_Real) weights[j]);
1650 realweights[j] = (SCIP_Real)weights[j];
1651 }
1652
1653 /* partially sort indices such that all elements that are larger than the break item appear first */
1654 SCIPselectWeightedDownRealLongRealInt(tempsort, weights, profits, items, realweights, (SCIP_Real)capacity, nitems, &criticalindex);
1655
1656 /* selects items as long as they fit into the knapsack */
1657 solitemsweight = 0;
1658 for( j = 0; j < nitems && solitemsweight + weights[j] <= capacity; ++j )
1659 {
1660 if( solitems != NULL )
1661 solitems[(*nsolitems)++] = items[j];
1662
1663 if( solval != NULL )
1664 (*solval) += profits[j];
1665 solitemsweight += weights[j];
1666 }
1667 if ( solitems != NULL )
1668 {
1669 for( ; j < nitems; j++ )
1670 nonsolitems[(*nnonsolitems)++] = items[j];
1671 }
1672
1673 SCIPfreeBufferArray(scip, &realweights);
1674 SCIPfreeBufferArray(scip, &tempsort);
1675
1676 return SCIP_OKAY;
1677}
1678
1679#ifdef SCIP_DEBUG
1680/** prints all nontrivial GUB constraints and their LP solution values */
1681static
1682void GUBsetPrint(
1683 SCIP* scip, /**< SCIP data structure */
1684 SCIP_GUBSET* gubset, /**< GUB set data structure */
1685 SCIP_VAR** vars, /**< variables in knapsack constraint */
1686 SCIP_Real* solvals /**< solution values of variables in knapsack constraint; or NULL */
1687 )
1688{
1689 int nnontrivialgubconss;
1690 int c;
1691
1692 nnontrivialgubconss = 0;
1693
1694 SCIPdebugMsg(scip, " Nontrivial GUBs of current GUB set:\n");
1695
1696 /* print out all nontrivial GUB constraints, i.e., with more than one variable */
1697 for( c = 0; c < gubset->ngubconss; c++ )
1698 {
1699 SCIP_Real gubsolval;
1700
1701 assert(gubset->gubconss[c]->ngubvars >= 0);
1702
1703 /* nontrivial GUB */
1704 if( gubset->gubconss[c]->ngubvars > 1 )
1705 {
1706 int v;
1707
1708 gubsolval = 0.0;
1709 SCIPdebugMsg(scip, " GUB<%d>:\n", c);
1710
1711 /* print GUB var */
1712 for( v = 0; v < gubset->gubconss[c]->ngubvars; v++ )
1713 {
1714 int currentvar;
1715
1716 currentvar = gubset->gubconss[c]->gubvars[v];
1717 if( solvals != NULL )
1718 {
1719 gubsolval += solvals[currentvar];
1720 SCIPdebugMsg(scip, " +<%s>(%4.2f)\n", SCIPvarGetName(vars[currentvar]), solvals[currentvar]);
1721 }
1722 else
1723 {
1724 SCIPdebugMsg(scip, " +<%s>\n", SCIPvarGetName(vars[currentvar]));
1725 }
1726 }
1727
1728 /* check whether LP solution satisfies the GUB constraint */
1729 if( solvals != NULL )
1730 {
1731 SCIPdebugMsg(scip, " =%4.2f <= 1 %s\n", gubsolval,
1732 SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1733 }
1734 else
1735 {
1736 SCIPdebugMsg(scip, " <= 1 %s\n", SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1737 }
1738 nnontrivialgubconss++;
1739 }
1740 }
1741
1742 SCIPdebugMsg(scip, " --> %d/%d nontrivial GUBs\n", nnontrivialgubconss, gubset->ngubconss);
1743}
1744#endif
1745
1746/** creates an empty GUB constraint */
1747static
1749 SCIP* scip, /**< SCIP data structure */
1750 SCIP_GUBCONS** gubcons /**< pointer to store GUB constraint data */
1751 )
1752{
1753 assert(scip != NULL);
1754 assert(gubcons != NULL);
1755
1756 /* allocate memory for GUB constraint data structures */
1757 SCIP_CALL( SCIPallocBuffer(scip, gubcons) );
1758 (*gubcons)->gubvarssize = GUBCONSGROWVALUE;
1759 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvars, (*gubcons)->gubvarssize) );
1760 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvarsstatus, (*gubcons)->gubvarssize) );
1761
1762 (*gubcons)->ngubvars = 0;
1763
1764 return SCIP_OKAY;
1765}
1766
1767/** frees GUB constraint */
1768static
1770 SCIP* scip, /**< SCIP data structure */
1771 SCIP_GUBCONS** gubcons /**< pointer to GUB constraint data structure */
1772 )
1773{
1774 assert(scip != NULL);
1775 assert(gubcons != NULL);
1776 assert((*gubcons)->gubvars != NULL);
1777 assert((*gubcons)->gubvarsstatus != NULL);
1778
1779 /* free allocated memory */
1780 SCIPfreeBufferArray(scip, &(*gubcons)->gubvarsstatus);
1781 SCIPfreeBufferArray(scip, &(*gubcons)->gubvars);
1782 SCIPfreeBuffer(scip, gubcons);
1783}
1784
1785/** adds variable to given GUB constraint */
1786static
1788 SCIP* scip, /**< SCIP data structure */
1789 SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1790 int var /**< index of given variable in knapsack constraint */
1791 )
1792{
1793 assert(scip != NULL);
1794 assert(gubcons != NULL);
1795 assert(gubcons->ngubvars >= 0 && gubcons->ngubvars < gubcons->gubvarssize);
1796 assert(gubcons->gubvars != NULL);
1797 assert(gubcons->gubvarsstatus != NULL);
1798 assert(var >= 0);
1799
1800 /* add variable to GUB constraint */
1801 gubcons->gubvars[gubcons->ngubvars] = var;
1802 gubcons->gubvarsstatus[gubcons->ngubvars] = GUBVARSTATUS_UNINITIAL;
1803 gubcons->ngubvars++;
1804
1805 /* increase space allocated to GUB constraint if the number of variables reaches the size */
1806 if( gubcons->ngubvars == gubcons->gubvarssize )
1807 {
1808 int newlen;
1809
1810 newlen = gubcons->gubvarssize + GUBCONSGROWVALUE;
1811 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1812 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1813
1814 gubcons->gubvarssize = newlen;
1815 }
1816
1817 return SCIP_OKAY;
1818}
1819
1820/** deletes variable from its current GUB constraint */
1821static
1823 SCIP* scip, /**< SCIP data structure */
1824 SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1825 int var, /**< index of given variable in knapsack constraint */
1826 int gubvarsidx /**< index of the variable in its current GUB constraint */
1827 )
1828{
1829 assert(scip != NULL);
1830 assert(gubcons != NULL);
1831 assert(var >= 0);
1832 assert(gubvarsidx >= 0 && gubvarsidx < gubcons->ngubvars);
1833 assert(gubcons->ngubvars >= gubvarsidx+1);
1834 assert(gubcons->gubvars[gubvarsidx] == var);
1835
1836 /* delete variable from GUB by swapping it replacing in by the last variable in the GUB constraint */
1837 gubcons->gubvars[gubvarsidx] = gubcons->gubvars[gubcons->ngubvars-1];
1838 gubcons->gubvarsstatus[gubvarsidx] = gubcons->gubvarsstatus[gubcons->ngubvars-1];
1839 gubcons->ngubvars--;
1840
1841 /* decrease space allocated for the GUB constraint, if the last GUBCONSGROWVALUE+1 array entries are now empty */
1842 if( gubcons->ngubvars < gubcons->gubvarssize - GUBCONSGROWVALUE && gubcons->ngubvars > 0 )
1843 {
1844 int newlen;
1845
1846 newlen = gubcons->gubvarssize - GUBCONSGROWVALUE;
1847
1848 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1849 SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1850
1851 gubcons->gubvarssize = newlen;
1852 }
1853
1854 return SCIP_OKAY;
1855}
1856
1857/** moves variable from current GUB constraint to a different existing (nonempty) GUB constraint */
1858static
1860 SCIP* scip, /**< SCIP data structure */
1861 SCIP_GUBSET* gubset, /**< GUB set data structure */
1862 SCIP_VAR** vars, /**< variables in knapsack constraint */
1863 int var, /**< index of given variable in knapsack constraint */
1864 int oldgubcons, /**< index of old GUB constraint of given variable */
1865 int newgubcons /**< index of new GUB constraint of given variable */
1866 )
1867{
1868 int oldgubvaridx;
1869 int replacevar;
1870 int j;
1871
1872 assert(scip != NULL);
1873 assert(gubset != NULL);
1874 assert(var >= 0);
1875 assert(oldgubcons >= 0 && oldgubcons < gubset->ngubconss);
1876 assert(newgubcons >= 0 && newgubcons < gubset->ngubconss);
1877 assert(oldgubcons != newgubcons);
1878 assert(gubset->gubconssidx[var] == oldgubcons);
1879 assert(gubset->gubconss[oldgubcons]->ngubvars > 0);
1880 assert(gubset->gubconss[newgubcons]->ngubvars >= 0);
1881
1882 SCIPdebugMsg(scip, " moving variable<%s> from GUB<%d> to GUB<%d>\n", SCIPvarGetName(vars[var]), oldgubcons, newgubcons);
1883
1884 oldgubvaridx = gubset->gubvarsidx[var];
1885
1886 /* delete variable from old GUB constraint by replacing it by the last variable of the GUB constraint */
1887 SCIP_CALL( GUBconsDelVar(scip, gubset->gubconss[oldgubcons], var, oldgubvaridx) );
1888
1889 /* in GUB set, update stored index of variable in old GUB constraint for the variable used for replacement;
1890 * replacement variable is given by old position of the deleted variable
1891 */
1892 replacevar = gubset->gubconss[oldgubcons]->gubvars[oldgubvaridx];
1893 assert(gubset->gubvarsidx[replacevar] == gubset->gubconss[oldgubcons]->ngubvars);
1894 gubset->gubvarsidx[replacevar] = oldgubvaridx;
1895
1896 /* add variable to the end of new GUB constraint */
1897 SCIP_CALL( GUBconsAddVar(scip, gubset->gubconss[newgubcons], var) );
1898 assert(gubset->gubconss[newgubcons]->gubvars[gubset->gubconss[newgubcons]->ngubvars-1] == var);
1899
1900 /* in GUB set, update stored index of GUB of moved variable and stored index of variable in this GUB constraint */
1901 gubset->gubconssidx[var] = newgubcons;
1902 gubset->gubvarsidx[var] = gubset->gubconss[newgubcons]->ngubvars-1;
1903
1904 /* delete old GUB constraint if it became empty */
1905 if( gubset->gubconss[oldgubcons]->ngubvars == 0 )
1906 {
1907 SCIPdebugMsg(scip, "deleting empty GUB cons<%d> from current GUB set\n", oldgubcons);
1908#ifdef SCIP_DEBUG
1909 GUBsetPrint(scip, gubset, vars, NULL);
1910#endif
1911
1912 /* free old GUB constraint */
1913 GUBconsFree(scip, &gubset->gubconss[oldgubcons]);
1914
1915 /* if empty GUB was not the last one in GUB set data structure, replace it by last GUB constraint */
1916 if( oldgubcons != gubset->ngubconss-1 )
1917 {
1918 gubset->gubconss[oldgubcons] = gubset->gubconss[gubset->ngubconss-1];
1919 gubset->gubconsstatus[oldgubcons] = gubset->gubconsstatus[gubset->ngubconss-1];
1920
1921 /* in GUB set, update stored index of GUB constraint for all variable of the GUB constraint used for replacement;
1922 * replacement GUB is given by old position of the deleted GUB
1923 */
1924 for( j = 0; j < gubset->gubconss[oldgubcons]->ngubvars; j++ )
1925 {
1926 assert(gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] == gubset->ngubconss-1);
1927 gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] = oldgubcons;
1928 }
1929 }
1930
1931 /* update number of GUB constraints */
1932 gubset->ngubconss--;
1933
1934 /* variable should be at given new position, unless new GUB constraint replaced empty old GUB constraint
1935 * (because it was at the end of the GUB constraint array)
1936 */
1937 assert(gubset->gubconssidx[var] == newgubcons
1938 || (newgubcons == gubset->ngubconss && gubset->gubconssidx[var] == oldgubcons));
1939 }
1940#ifndef NDEBUG
1941 else
1942 assert(gubset->gubconssidx[var] == newgubcons);
1943#endif
1944
1945 return SCIP_OKAY;
1946}
1947
1948/** swaps two variables in the same GUB constraint */
1949static
1951 SCIP* scip, /**< SCIP data structure */
1952 SCIP_GUBSET* gubset, /**< GUB set data structure */
1953 int var1, /**< first variable to be swapped */
1954 int var2 /**< second variable to be swapped */
1955 )
1956{
1957 int gubcons;
1958 int var1idx;
1959 GUBVARSTATUS var1status;
1960 int var2idx;
1961 GUBVARSTATUS var2status;
1962
1963 assert(scip != NULL);
1964 assert(gubset != NULL);
1965
1966 gubcons = gubset->gubconssidx[var1];
1967 assert(gubcons == gubset->gubconssidx[var2]);
1968
1969 /* nothing to be done if both variables are the same */
1970 if( var1 == var2 )
1971 return;
1972
1973 /* swap index and status of variables in GUB constraint */
1974 var1idx = gubset->gubvarsidx[var1];
1975 var1status = gubset->gubconss[gubcons]->gubvarsstatus[var1idx];
1976 var2idx = gubset->gubvarsidx[var2];
1977 var2status = gubset->gubconss[gubcons]->gubvarsstatus[var2idx];
1978
1979 gubset->gubvarsidx[var1] = var2idx;
1980 gubset->gubconss[gubcons]->gubvars[var1idx] = var2;
1981 gubset->gubconss[gubcons]->gubvarsstatus[var1idx] = var2status;
1982
1983 gubset->gubvarsidx[var2] = var1idx;
1984 gubset->gubconss[gubcons]->gubvars[var2idx] = var1;
1985 gubset->gubconss[gubcons]->gubvarsstatus[var2idx] = var1status;
1986}
1987
1988/** initializes partition of knapsack variables into nonoverlapping trivial GUB constraints (GUB with one variable) */
1989static
1991 SCIP* scip, /**< SCIP data structure */
1992 SCIP_GUBSET** gubset, /**< pointer to store GUB set data structure */
1993 int nvars, /**< number of variables in the knapsack constraint */
1994 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
1995 SCIP_Longint capacity /**< capacity of knapsack */
1996 )
1997{
1998 int i;
1999
2000 assert(scip != NULL);
2001 assert(gubset != NULL);
2002 assert(nvars > 0);
2003 assert(weights != NULL);
2004 assert(capacity >= 0);
2005
2006 /* allocate memory for GUB set data structures */
2007 SCIP_CALL( SCIPallocBuffer(scip, gubset) );
2008 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconss, nvars) );
2009 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconsstatus, nvars) );
2010 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconssidx, nvars) );
2011 SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubvarsidx, nvars) );
2012 (*gubset)->ngubconss = nvars;
2013 (*gubset)->nvars = nvars;
2014
2015 /* initialize the set of GUB constraints */
2016 for( i = 0; i < nvars; i++ )
2017 {
2018 /* assign each variable to a new (trivial) GUB constraint */
2019 SCIP_CALL( GUBconsCreate(scip, &(*gubset)->gubconss[i]) );
2020 SCIP_CALL( GUBconsAddVar(scip, (*gubset)->gubconss[i], i) );
2021
2022 /* set status of GUB constraint to initial */
2023 (*gubset)->gubconsstatus[i] = GUBCONSSTATUS_UNINITIAL;
2024
2025 (*gubset)->gubconssidx[i] = i;
2026 (*gubset)->gubvarsidx[i] = 0;
2027 assert((*gubset)->gubconss[i]->ngubvars == 1);
2028
2029 /* already updated status of variable in GUB constraint if it exceeds the capacity of the knapsack */
2030 if( weights[i] > capacity )
2031 (*gubset)->gubconss[(*gubset)->gubconssidx[i]]->gubvarsstatus[(*gubset)->gubvarsidx[i]] = GUBVARSTATUS_CAPACITYEXCEEDED;
2032 }
2033
2034 return SCIP_OKAY;
2035}
2036
2037/** frees GUB set data structure */
2038static
2040 SCIP* scip, /**< SCIP data structure */
2041 SCIP_GUBSET** gubset /**< pointer to GUB set data structure */
2042 )
2043{
2044 int i;
2045
2046 assert(scip != NULL);
2047 assert(gubset != NULL);
2048 assert((*gubset)->gubconss != NULL);
2049 assert((*gubset)->gubconsstatus != NULL);
2050 assert((*gubset)->gubconssidx != NULL);
2051 assert((*gubset)->gubvarsidx != NULL);
2052
2053 /* free all GUB constraints */
2054 for( i = (*gubset)->ngubconss-1; i >= 0; --i )
2055 {
2056 assert((*gubset)->gubconss[i] != NULL);
2057 GUBconsFree(scip, &(*gubset)->gubconss[i]);
2058 }
2059
2060 /* free allocated memory */
2061 SCIPfreeBufferArray( scip, &(*gubset)->gubvarsidx );
2062 SCIPfreeBufferArray( scip, &(*gubset)->gubconssidx );
2063 SCIPfreeBufferArray( scip, &(*gubset)->gubconsstatus );
2064 SCIPfreeBufferArray( scip, &(*gubset)->gubconss );
2065 SCIPfreeBuffer(scip, gubset);
2066}
2067
2068#ifndef NDEBUG
2069/** checks whether GUB set data structure is consistent */
2070static
2072 SCIP* scip, /**< SCIP data structure */
2073 SCIP_GUBSET* gubset, /**< GUB set data structure */
2074 SCIP_VAR** vars /**< variables in the knapsack constraint */
2075 )
2076{
2077 int i;
2078 int gubconsidx;
2079 int gubvaridx;
2080 SCIP_VAR* var1;
2081 SCIP_VAR* var2;
2082 SCIP_Bool var1negated;
2083 SCIP_Bool var2negated;
2084
2085 assert(scip != NULL);
2086 assert(gubset != NULL);
2087
2088 SCIPdebugMsg(scip, " GUB set consistency check:\n");
2089
2090 /* checks for all knapsack vars consistency of stored index of associated gubcons and corresponding index in gubvars */
2091 for( i = 0; i < gubset->nvars; i++ )
2092 {
2093 gubconsidx = gubset->gubconssidx[i];
2094 gubvaridx = gubset->gubvarsidx[i];
2095
2096 if( gubset->gubconss[gubconsidx]->gubvars[gubvaridx] != i )
2097 {
2098 SCIPdebugMsg(scip, " var<%d> should be in GUB<%d> at position<%d>, but stored is var<%d> instead\n", i,
2099 gubconsidx, gubvaridx, gubset->gubconss[gubconsidx]->gubvars[gubvaridx] );
2100 }
2101 assert(gubset->gubconss[gubconsidx]->gubvars[gubvaridx] == i);
2102 }
2103
2104 /* checks for each GUB whether all pairs of its variables have a common clique */
2105 for( i = 0; i < gubset->ngubconss; i++ )
2106 {
2107 int j;
2108
2109 for( j = 0; j < gubset->gubconss[i]->ngubvars; j++ )
2110 {
2111 int k;
2112
2113 /* get corresponding active problem variable */
2114 var1 = vars[gubset->gubconss[i]->gubvars[j]];
2115 var1negated = FALSE;
2116 SCIP_CALL( SCIPvarGetProbvarBinary(&var1, &var1negated) );
2117
2118 for( k = j+1; k < gubset->gubconss[i]->ngubvars; k++ )
2119 {
2120 /* get corresponding active problem variable */
2121 var2 = vars[gubset->gubconss[i]->gubvars[k]];
2122 var2negated = FALSE;
2123 SCIP_CALL( SCIPvarGetProbvarBinary(&var2, &var2negated) );
2124
2125 if( !SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE) )
2126 {
2127 SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2128 SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[j]]), k,
2129 SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[k]]));
2130 SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2131 SCIPvarGetName(var1), k,
2132 SCIPvarGetName(var2));
2133 }
2134
2135 /* @todo: in case we used also negated cliques for the GUB partition, this assert has to be changed */
2136 assert(SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE));
2137 }
2138 }
2139 }
2140 SCIPdebugMsg(scip, " --> successful\n");
2141
2142 return SCIP_OKAY;
2143}
2144#endif
2145
2146/** calculates a partition of the given set of binary variables into cliques;
2147 * afterwards the output array contains one value for each variable, such that two variables got the same value iff they
2148 * were assigned to the same clique;
2149 * the first variable is always assigned to clique 0, and a variable can only be assigned to clique i if at least one of
2150 * the preceding variables was assigned to clique i-1;
2151 * note: in contrast to SCIPcalcCliquePartition(), variables with LP value 1 are put into trivial cliques (with one
2152 * variable) and for the remaining variables, a partition with a small number of cliques is constructed
2153 */
2154
2155static
2157 SCIP*const scip, /**< SCIP data structure */
2158 SCIP_VAR**const vars, /**< binary variables in the clique from which at most one can be set to 1 */
2159 int const nvars, /**< number of variables in the clique */
2160 int*const cliquepartition, /**< array of length nvars to store the clique partition */
2161 int*const ncliques, /**< pointer to store number of cliques actually contained in the partition */
2162 SCIP_Real* solvals /**< solution values of all given binary variables */
2163 )
2164{
2165 SCIP_VAR** tmpvars;
2166 SCIP_VAR** cliquevars;
2167 SCIP_Bool* cliquevalues;
2168 SCIP_Bool* tmpvalues;
2169 int* varseq;
2170 int* sortkeys;
2171 int ncliquevars;
2172 int maxncliquevarscomp;
2173 int nignorevars;
2174 int nvarsused;
2175 int i;
2176
2177 assert(scip != NULL);
2178 assert(nvars == 0 || vars != NULL);
2179 assert(nvars == 0 || cliquepartition != NULL);
2180 assert(ncliques != NULL);
2181
2182 if( nvars == 0 )
2183 {
2184 *ncliques = 0;
2185 return SCIP_OKAY;
2186 }
2187
2188 /* allocate temporary memory for storing the variables of the current clique */
2189 SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
2190 SCIP_CALL( SCIPallocBufferArray(scip, &cliquevalues, nvars) );
2191 SCIP_CALL( SCIPallocBufferArray(scip, &tmpvalues, nvars) );
2194 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvars) );
2195
2196 /* initialize the cliquepartition array with -1 */
2197 /* initialize the tmpvalues array */
2198 for( i = nvars - 1; i >= 0; --i )
2199 {
2200 tmpvalues[i] = TRUE;
2201 cliquepartition[i] = -1;
2202 }
2203
2204 /* get corresponding active problem variables */
2205 SCIP_CALL( SCIPvarsGetProbvarBinary(&tmpvars, &tmpvalues, nvars) );
2206
2207 /* ignore variables with LP value 1 (will be assigned to trivial GUBs at the end) and sort remaining variables
2208 * by nondecreasing number of cliques the variables are in
2209 */
2210 nignorevars = 0;
2211 nvarsused = 0;
2212 for( i = 0; i < nvars; i++ )
2213 {
2214 if( SCIPisFeasEQ(scip, solvals[i], 1.0) )
2215 {
2216 /* variables with LP value 1 are put to the end of varseq array and will not be sorted */
2217 varseq[nvars-1-nignorevars] = i;
2218 nignorevars++;
2219 }
2220 else
2221 {
2222 /* remaining variables are put to the front of varseq array and will be sorted by their number of cliques */
2223 varseq[nvarsused] = i;
2224 sortkeys[nvarsused] = SCIPvarGetNCliques(tmpvars[i], tmpvalues[i]);
2225 nvarsused++;
2226 }
2227 }
2228 assert(nvarsused + nignorevars == nvars);
2229
2230 /* sort variables with LP value less than 1 by nondecreasing order of the number of cliques they are in */
2231 SCIPsortIntInt(sortkeys, varseq, nvarsused);
2232
2233 maxncliquevarscomp = MIN(nvars*nvars, MAXNCLIQUEVARSCOMP);
2234
2235 /* calculate the clique partition */
2236 *ncliques = 0;
2237 for( i = 0; i < nvars; ++i )
2238 {
2239 if( cliquepartition[varseq[i]] == -1 )
2240 {
2241 int j;
2242
2243 /* variable starts a new clique */
2244 cliquepartition[varseq[i]] = *ncliques;
2245 cliquevars[0] = tmpvars[varseq[i]];
2246 cliquevalues[0] = tmpvalues[varseq[i]];
2247 ncliquevars = 1;
2248
2249 /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique and
2250 * if the variable has LP value 1 we do not want it to be in nontrivial cliques
2251 */
2252 if( i < nvarsused && SCIPvarIsActive(tmpvars[varseq[i]]) )
2253 {
2254 /* greedily fill up the clique */
2255 for( j = i + 1; j < nvarsused; ++j )
2256 {
2257 /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique */
2258 if( cliquepartition[varseq[j]] == -1 && SCIPvarIsActive(tmpvars[varseq[j]]) )
2259 {
2260 int k;
2261
2262 /* check if every variable in the actual clique is in clique with the new variable */
2263 for( k = ncliquevars - 1; k >= 0; --k )
2264 {
2265 if( !SCIPvarsHaveCommonClique(tmpvars[varseq[j]], tmpvalues[varseq[j]], cliquevars[k],
2266 cliquevalues[k], TRUE) )
2267 break;
2268 }
2269
2270 if( k == -1 )
2271 {
2272 /* put the variable into the same clique */
2273 cliquepartition[varseq[j]] = cliquepartition[varseq[i]];
2274 cliquevars[ncliquevars] = tmpvars[varseq[j]];
2275 cliquevalues[ncliquevars] = tmpvalues[varseq[j]];
2276 ++ncliquevars;
2277 }
2278 }
2279 }
2280 }
2281
2282 /* this clique is finished */
2283 ++(*ncliques);
2284 }
2285 assert(cliquepartition[varseq[i]] >= 0 && cliquepartition[varseq[i]] < i + 1);
2286
2287 /* break if we reached the maximal number of comparisons */
2288 if( i * nvars > maxncliquevarscomp )
2289 break;
2290 }
2291 /* if we had too many variables fill up the cliquepartition and put each variable in a separate clique */
2292 for( ; i < nvars; ++i )
2293 {
2294 if( cliquepartition[varseq[i]] == -1 )
2295 {
2296 cliquepartition[varseq[i]] = *ncliques;
2297 ++(*ncliques);
2298 }
2299 }
2300
2301 /* free temporary memory */
2302 SCIPfreeBufferArray(scip, &sortkeys);
2303 SCIPfreeBufferArray(scip, &varseq);
2304 SCIPfreeBufferArray(scip, &tmpvars);
2305 SCIPfreeBufferArray(scip, &tmpvalues);
2306 SCIPfreeBufferArray(scip, &cliquevalues);
2307 SCIPfreeBufferArray(scip, &cliquevars);
2308
2309 return SCIP_OKAY;
2310}
2311
2312/** constructs sophisticated partition of knapsack variables into non-overlapping GUBs; current partition uses trivial GUBs */
2313static
2315 SCIP* scip, /**< SCIP data structure */
2316 SCIP_GUBSET* gubset, /**< GUB set data structure */
2317 SCIP_VAR** vars, /**< variables in the knapsack constraint */
2318 SCIP_Real* solvals /**< solution values of all knapsack variables */
2319 )
2320{
2321 int* cliquepartition;
2322 int* gubfirstvar;
2323 int ncliques;
2324 int currentgubconsidx;
2325 int newgubconsidx;
2326 int cliqueidx;
2327 int nvars;
2328 int i;
2329
2330 assert(scip != NULL);
2331 assert(gubset != NULL);
2332 assert(vars != NULL);
2333
2334 nvars = gubset->nvars;
2335 assert(nvars >= 0);
2336
2337 /* allocate temporary memory for clique partition */
2338 SCIP_CALL( SCIPallocBufferArray(scip, &cliquepartition, nvars) );
2339
2340 /* compute sophisticated clique partition */
2341 SCIP_CALL( GUBsetCalcCliquePartition(scip, vars, nvars, cliquepartition, &ncliques, solvals) );
2342
2343 /* allocate temporary memory for GUB set data structure */
2344 SCIP_CALL( SCIPallocBufferArray(scip, &gubfirstvar, ncliques) );
2345
2346 /* translate GUB partition into GUB set data structure */
2347 for( i = 0; i < ncliques; i++ )
2348 {
2349 /* initialize first variable for every GUB */
2350 gubfirstvar[i] = -1;
2351 }
2352 /* move every knapsack variable into GUB defined by clique partition */
2353 for( i = 0; i < nvars; i++ )
2354 {
2355 assert(cliquepartition[i] >= 0);
2356
2357 cliqueidx = cliquepartition[i];
2358 currentgubconsidx = gubset->gubconssidx[i];
2359 assert(gubset->gubconss[currentgubconsidx]->ngubvars == 1 );
2360
2361 /* variable is first element in GUB constraint defined by clique partition */
2362 if( gubfirstvar[cliqueidx] == -1 )
2363 {
2364 /* corresponding GUB constraint in GUB set data structure was already constructed (as initial trivial GUB);
2365 * note: no assert for gubconssidx, because it can changed due to deleting empty GUBs in GUBsetMoveVar()
2366 */
2367 assert(gubset->gubvarsidx[i] == 0);
2368 assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2369
2370 /* remember the first variable found for the current GUB */
2371 gubfirstvar[cliqueidx] = i;
2372 }
2373 /* variable is additional element of GUB constraint defined by clique partition */
2374 else
2375 {
2376 assert(gubfirstvar[cliqueidx] >= 0 && gubfirstvar[cliqueidx] < i);
2377
2378 /* move variable to GUB constraint defined by clique partition; index of this GUB constraint is given by the
2379 * first variable of this GUB constraint
2380 */
2381 newgubconsidx = gubset->gubconssidx[gubfirstvar[cliqueidx]];
2382 assert(newgubconsidx != currentgubconsidx); /* because initially every variable is in a different GUB */
2383 SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, i, currentgubconsidx, newgubconsidx) );
2384
2385 assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2386 }
2387 }
2388
2389#ifdef SCIP_DEBUG
2390 /* prints GUB set data structure */
2391 GUBsetPrint(scip, gubset, vars, solvals);
2392#endif
2393
2394#ifndef NDEBUG
2395 /* checks consistency of GUB set data structure */
2396 SCIP_CALL( GUBsetCheck(scip, gubset, vars) );
2397#endif
2398
2399 /* free temporary memory */
2400 SCIPfreeBufferArray(scip, &gubfirstvar);
2401 SCIPfreeBufferArray(scip, &cliquepartition);
2402
2403 return SCIP_OKAY;
2404}
2405
2406/** 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$
2407 * 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
2408 * \f$j \in N \setminus C\f$, if \f$j \in N_0 = \{j \in N : x^*_j = 0\}\f$, if one exists.
2409 */
2410static
2412 SCIP* scip, /**< SCIP data structure */
2413 SCIP_VAR** vars, /**< variables in knapsack constraint */
2414 int nvars, /**< number of variables in knapsack constraint */
2415 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2416 SCIP_Longint capacity, /**< capacity of knapsack */
2417 SCIP_Real* solvals, /**< solution values of all problem variables */
2418 int* covervars, /**< pointer to store cover variables */
2419 int* noncovervars, /**< pointer to store noncover variables */
2420 int* ncovervars, /**< pointer to store number of cover variables */
2421 int* nnoncovervars, /**< pointer to store number of noncover variables */
2422 SCIP_Longint* coverweight, /**< pointer to store weight of cover */
2423 SCIP_Bool* found, /**< pointer to store whether a cover was found */
2424 SCIP_Bool modtransused, /**< should modified transformed separation problem be used to find cover */
2425 int* ntightened, /**< pointer to store number of variables with tightened upper bound */
2426 SCIP_Bool* fractional /**< pointer to store whether the LP sol for knapsack vars is fractional */
2427 )
2428{
2429 SCIP_Longint* transweights;
2430 SCIP_Real* transprofits;
2431 SCIP_Longint transcapacity;
2432 SCIP_Longint fixedonesweight;
2433 SCIP_Longint itemsweight;
2434 SCIP_Bool infeasible;
2435 int* fixedones;
2436 int* fixedzeros;
2437 int* items;
2438 int nfixedones;
2439 int nfixedzeros;
2440 int nitems;
2441 int j;
2442
2443 assert(scip != NULL);
2444 assert(vars != NULL);
2445 assert(nvars > 0);
2446 assert(weights != NULL);
2447 assert(capacity >= 0);
2448 assert(solvals != NULL);
2449 assert(covervars != NULL);
2450 assert(noncovervars != NULL);
2451 assert(ncovervars != NULL);
2452 assert(nnoncovervars != NULL);
2453 assert(coverweight != NULL);
2454 assert(found != NULL);
2455 assert(ntightened != NULL);
2456 assert(fractional != NULL);
2457
2458 SCIPdebugMsg(scip, " get cover for knapsack constraint\n");
2459
2460 /* allocates temporary memory */
2461 SCIP_CALL( SCIPallocBufferArray(scip, &transweights, nvars) );
2462 SCIP_CALL( SCIPallocBufferArray(scip, &transprofits, nvars) );
2463 SCIP_CALL( SCIPallocBufferArray(scip, &fixedones, nvars) );
2464 SCIP_CALL( SCIPallocBufferArray(scip, &fixedzeros, nvars) );
2466
2467 *found = FALSE;
2468 *ncovervars = 0;
2469 *nnoncovervars = 0;
2470 *coverweight = 0;
2471 *fractional = TRUE;
2472
2473 /* gets the following sets
2474 * N_1 = {j in N : x*_j = 1} (fixedones),
2475 * N_0 = {j in N : x*_j = 0} (fixedzeros) and
2476 * N\‍(N_0 & N_1) (items),
2477 * where x*_j is the solution value of variable x_j
2478 */
2479 nfixedones = 0;
2480 nfixedzeros = 0;
2481 nitems = 0;
2482 fixedonesweight = 0;
2483 itemsweight = 0;
2484 *ntightened = 0;
2485 for( j = 0; j < nvars; j++ )
2486 {
2488
2489 /* tightens upper bound of x_j if weight of x_j is greater than capacity of knapsack */
2490 if( weights[j] > capacity )
2491 {
2492 SCIP_CALL( SCIPtightenVarUb(scip, vars[j], 0.0, FALSE, &infeasible, NULL) );
2493 assert(!infeasible);
2494 (*ntightened)++;
2495 continue;
2496 }
2497
2498 /* variable x_j has solution value one */
2499 if( SCIPisFeasEQ(scip, solvals[j], 1.0) )
2500 {
2501 fixedones[nfixedones] = j;
2502 nfixedones++;
2503 fixedonesweight += weights[j];
2504 }
2505 /* variable x_j has solution value zero */
2506 else if( SCIPisFeasEQ(scip, solvals[j], 0.0) )
2507 {
2508 fixedzeros[nfixedzeros] = j;
2509 nfixedzeros++;
2510 }
2511 /* variable x_j has fractional solution value */
2512 else
2513 {
2514 assert( SCIPisFeasGT(scip, solvals[j], 0.0) && SCIPisFeasLT(scip, solvals[j], 1.0) );
2515 items[nitems] = j;
2516 nitems++;
2517 itemsweight += weights[j];
2518 }
2519 }
2520 assert(nfixedones + nfixedzeros + nitems == nvars - (*ntightened));
2521
2522 /* sets whether the LP solution x* for the knapsack variables is fractional; if it is not fractional we stop
2523 * the separation routine
2524 */
2525 assert(nitems >= 0);
2526 if( nitems == 0 )
2527 {
2528 *fractional = FALSE;
2529 goto TERMINATE;
2530 }
2531 assert(*fractional);
2532
2533 /* transforms the traditional separation problem (under consideration of the following fixing:
2534 * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2535 *
2536 * min sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) z_j
2537 * sum_{j in N\‍(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2538 * z_j in {0,1}, j in N\‍(N_0 & N_1)
2539 *
2540 * to a knapsack problem in maximization form by complementing the variables
2541 *
2542 * sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) -
2543 * max sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) z_j
2544 * sum_{j in N\‍(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2545 * z_j in {0,1}, j in N\‍(N_0 & N_1)
2546 */
2547
2548 /* gets weight and profit of variables in transformed knapsack problem */
2549 for( j = 0; j < nitems; j++ )
2550 {
2551 transweights[j] = weights[items[j]];
2552 transprofits[j] = 1.0 - solvals[items[j]];
2553 }
2554 /* gets capacity of transformed knapsack problem */
2555 transcapacity = fixedonesweight + itemsweight - capacity - 1;
2556
2557 /* if capacity of transformed knapsack problem is less than zero, there is no cover
2558 * (when variables fixed to zero are not used)
2559 */
2560 if( transcapacity < 0 )
2561 {
2562 assert(!(*found));
2563 goto TERMINATE;
2564 }
2565
2566 if( modtransused )
2567 {
2568 /* transforms the modified separation problem (under consideration of the following fixing:
2569 * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2570 *
2571 * min sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) a_j z_j
2572 * sum_{j in N\‍(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2573 * z_j in {0,1}, j in N\‍(N_0 & N_1)
2574 *
2575 * to a knapsack problem in maximization form by complementing the variables
2576 *
2577 * sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) a_j -
2578 * max sum_{j in N\‍(N_0 & N_1)} (1 - x*_j) a_j z_j
2579 * sum_{j in N\‍(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2580 * z_j in {0,1}, j in N\‍(N_0 & N_1)
2581 */
2582
2583 /* gets weight and profit of variables in modified transformed knapsack problem */
2584 for( j = 0; j < nitems; j++ )
2585 {
2586 transprofits[j] *= weights[items[j]];
2587 assert(SCIPisFeasPositive(scip, transprofits[j]));
2588 }
2589 }
2590
2591 /* solves (modified) transformed knapsack problem approximately by solving the LP-relaxation of the (modified)
2592 * transformed knapsack problem using Dantzig's method and rounding down the solution.
2593 * let z* be the solution, then
2594 * j in C, if z*_j = 0 and
2595 * i in N\C, if z*_j = 1.
2596 */
2597 SCIP_CALL( SCIPsolveKnapsackApproximately(scip, nitems, transweights, transprofits, transcapacity, items,
2598 noncovervars, covervars, nnoncovervars, ncovervars, NULL) );
2599 /*assert(checkSolveKnapsack(scip, nitems, transweights, transprofits, items, weights, solvals, modtransused));*/
2600
2601 /* constructs cover C (sum_{j in C} a_j > a_0) */
2602 for( j = 0; j < *ncovervars; j++ )
2603 {
2604 (*coverweight) += weights[covervars[j]];
2605 }
2606
2607 /* adds all variables from N_1 to C */
2608 for( j = 0; j < nfixedones; j++ )
2609 {
2610 covervars[*ncovervars] = fixedones[j];
2611 (*ncovervars)++;
2612 (*coverweight) += weights[fixedones[j]];
2613 }
2614
2615 /* adds all variables from N_0 to N\C */
2616 for( j = 0; j < nfixedzeros; j++ )
2617 {
2618 noncovervars[*nnoncovervars] = fixedzeros[j];
2619 (*nnoncovervars)++;
2620 }
2621 assert((*ncovervars) + (*nnoncovervars) == nvars - (*ntightened));
2622 assert((*coverweight) > capacity);
2623 *found = TRUE;
2624
2625 TERMINATE:
2626 /* frees temporary memory */
2627 SCIPfreeBufferArray(scip, &items);
2628 SCIPfreeBufferArray(scip, &fixedzeros);
2629 SCIPfreeBufferArray(scip, &fixedones);
2630 SCIPfreeBufferArray(scip, &transprofits);
2631 SCIPfreeBufferArray(scip, &transweights);
2632
2633 SCIPdebugMsg(scip, " get cover for knapsack constraint -- end\n");
2634
2635 return SCIP_OKAY;
2636}
2637
2638#ifndef NDEBUG
2639/** checks if minweightidx is set correctly
2640 */
2641static
2643 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2644 SCIP_Longint capacity, /**< capacity of knapsack */
2645 int* covervars, /**< pointer to store cover variables */
2646 int ncovervars, /**< pointer to store number of cover variables */
2647 SCIP_Longint coverweight, /**< pointer to store weight of cover */
2648 int minweightidx, /**< index of variable in cover variables with minimum weight */
2649 int j /**< current index in cover variables */
2650 )
2651{
2652 SCIP_Longint minweight;
2653 int i;
2654
2655 assert(weights != NULL);
2656 assert(covervars != NULL);
2657 assert(ncovervars > 0);
2658
2659 minweight = weights[covervars[minweightidx]];
2660
2661 /* checks if all cover variables before index j have weight greater than minweight */
2662 for( i = 0; i < j; i++ )
2663 {
2664 assert(weights[covervars[i]] > minweight);
2665 if( weights[covervars[i]] <= minweight )
2666 return FALSE;
2667 }
2668
2669 /* checks if all variables before index j cannot be removed, i.e. i cannot be the next minweightidx */
2670 for( i = 0; i < j; i++ )
2671 {
2672 assert(coverweight - weights[covervars[i]] <= capacity);
2673 if( coverweight - weights[covervars[i]] > capacity )
2674 return FALSE;
2675 }
2676 return TRUE;
2677}
2678#endif
2679
2680
2681/** 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$,
2682 * 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$
2683 */
2684static
2686 SCIP* scip, /**< SCIP data structure */
2687 SCIP_Real* solvals, /**< solution values of all problem variables */
2688 int* covervars, /**< cover variables */
2689 int ncovervars, /**< number of cover variables */
2690 int* varsC1, /**< pointer to store variables in C1 */
2691 int* varsC2, /**< pointer to store variables in C2 */
2692 int* nvarsC1, /**< pointer to store number of variables in C1 */
2693 int* nvarsC2 /**< pointer to store number of variables in C2 */
2694 )
2695{
2696 int j;
2697
2698 assert(scip != NULL);
2699 assert(ncovervars >= 0);
2700 assert(solvals != NULL);
2701 assert(covervars != NULL);
2702 assert(varsC1 != NULL);
2703 assert(varsC2 != NULL);
2704 assert(nvarsC1 != NULL);
2705 assert(nvarsC2 != NULL);
2706
2707 *nvarsC1 = 0;
2708 *nvarsC2 = 0;
2709 for( j = 0; j < ncovervars; j++ )
2710 {
2711 assert(SCIPisFeasGT(scip, solvals[covervars[j]], 0.0));
2712
2713 /* variable has solution value one */
2714 if( SCIPisGE(scip, solvals[covervars[j]], 1.0) )
2715 {
2716 varsC2[*nvarsC2] = covervars[j];
2717 (*nvarsC2)++;
2718 }
2719 /* variable has solution value less than one */
2720 else
2721 {
2722 assert(SCIPisLT(scip, solvals[covervars[j]], 1.0));
2723 varsC1[*nvarsC1] = covervars[j];
2724 (*nvarsC1)++;
2725 }
2726 }
2727 assert((*nvarsC1) + (*nvarsC2) == ncovervars);
2728}
2729
2730/** changes given partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one and two (if possible) variables from
2731 * C2 to C1 if |C1| = 1 and |C1| = 0, respectively.
2732 */
2733static
2735 SCIP* scip, /**< SCIP data structure */
2736 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2737 int* varsC1, /**< pointer to store variables in C1 */
2738 int* varsC2, /**< pointer to store variables in C2 */
2739 int* nvarsC1, /**< pointer to store number of variables in C1 */
2740 int* nvarsC2 /**< pointer to store number of variables in C2 */
2741 )
2742{
2743 SCIP_Real* sortkeysC2;
2744 int j;
2745
2746 assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2747 assert(*nvarsC2 > 0);
2748
2749 /* allocates temporary memory */
2750 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2751
2752 /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2753 for( j = 0; j < *nvarsC2; j++ )
2754 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2755 SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2756
2757 /* adds one or two variable from C2 with smallest weight to C1 and removes them from C2 */
2758 assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2759 while( *nvarsC1 < 2 && *nvarsC2 > 0 )
2760 {
2761 varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2762 (*nvarsC1)++;
2763 (*nvarsC2)--;
2764 }
2765
2766 /* frees temporary memory */
2767 SCIPfreeBufferArray(scip, &sortkeysC2);
2768
2769 return SCIP_OKAY;
2770}
2771
2772/** changes given partition (C_1,C_2) of feasible set C, if |C1| = 1, by moving one variable from C2 to C1 */
2773static
2775 SCIP* scip, /**< SCIP data structure */
2776 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2777 int* varsC1, /**< pointer to store variables in C1 */
2778 int* varsC2, /**< pointer to store variables in C2 */
2779 int* nvarsC1, /**< pointer to store number of variables in C1 */
2780 int* nvarsC2 /**< pointer to store number of variables in C2 */
2781 )
2782{
2783 SCIP_Real* sortkeysC2;
2784 int j;
2785
2786 assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2787 assert(*nvarsC2 > 0);
2788
2789 /* allocates temporary memory */
2790 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2791
2792 /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2793 for( j = 0; j < *nvarsC2; j++ )
2794 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2795 SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2796
2797 /* adds variable from C2 with smallest weight to C1 and removes it from C2 */
2798 assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2799 varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2800 (*nvarsC1)++;
2801 (*nvarsC2)--;
2802
2803 /* frees temporary memory */
2804 SCIPfreeBufferArray(scip, &sortkeysC2);
2805
2806 return SCIP_OKAY;
2807}
2808
2809
2810/** 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$
2811 * and \f$F \cap R = \emptyset\f$; chooses partition as follows \f$R = \{ j \in N \setminus C : x^*_j = 0 \}\f$ and
2812 * \f$F = (N \setminus C) \setminus F\f$
2813 */
2814static
2816 SCIP* scip, /**< SCIP data structure */
2817 SCIP_Real* solvals, /**< solution values of all problem variables */
2818 int* noncovervars, /**< noncover variables */
2819 int nnoncovervars, /**< number of noncover variables */
2820 int* varsF, /**< pointer to store variables in F */
2821 int* varsR, /**< pointer to store variables in R */
2822 int* nvarsF, /**< pointer to store number of variables in F */
2823 int* nvarsR /**< pointer to store number of variables in R */
2824 )
2825{
2826 int j;
2827
2828 assert(scip != NULL);
2829 assert(nnoncovervars >= 0);
2830 assert(solvals != NULL);
2831 assert(noncovervars != NULL);
2832 assert(varsF != NULL);
2833 assert(varsR != NULL);
2834 assert(nvarsF != NULL);
2835 assert(nvarsR != NULL);
2836
2837 *nvarsF = 0;
2838 *nvarsR = 0;
2839
2840 for( j = 0; j < nnoncovervars; j++ )
2841 {
2842 /* variable has solution value zero */
2843 if( SCIPisFeasEQ(scip, solvals[noncovervars[j]], 0.0) )
2844 {
2845 varsR[*nvarsR] = noncovervars[j];
2846 (*nvarsR)++;
2847 }
2848 /* variable has solution value greater than zero */
2849 else
2850 {
2851 assert(SCIPisFeasGT(scip, solvals[noncovervars[j]], 0.0));
2852 varsF[*nvarsF] = noncovervars[j];
2853 (*nvarsF)++;
2854 }
2855 }
2856 assert((*nvarsF) + (*nvarsR) == nnoncovervars);
2857}
2858
2859/** sorts variables in F, C_2, and R according to the second level lifting sequence that will be used in the sequential
2860 * lifting procedure
2861 */
2862static
2864 SCIP* scip, /**< SCIP data structure */
2865 SCIP_Real* solvals, /**< solution values of all problem variables */
2866 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2867 int* varsF, /**< pointer to store variables in F */
2868 int* varsC2, /**< pointer to store variables in C2 */
2869 int* varsR, /**< pointer to store variables in R */
2870 int nvarsF, /**< number of variables in F */
2871 int nvarsC2, /**< number of variables in C2 */
2872 int nvarsR /**< number of variables in R */
2873 )
2874{
2875 SORTKEYPAIR** sortkeypairsF;
2876 SORTKEYPAIR* sortkeypairsFstore;
2877 SCIP_Real* sortkeysC2;
2878 SCIP_Real* sortkeysR;
2879 int j;
2880
2881 assert(scip != NULL);
2882 assert(solvals != NULL);
2883 assert(weights != NULL);
2884 assert(varsF != NULL);
2885 assert(varsC2 != NULL);
2886 assert(varsR != NULL);
2887 assert(nvarsF >= 0);
2888 assert(nvarsC2 >= 0);
2889 assert(nvarsR >= 0);
2890
2891 /* allocates temporary memory */
2892 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsF, nvarsF) );
2893 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsFstore, nvarsF) );
2894 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
2895 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
2896
2897 /* gets sorting key for variables in F corresponding to the following lifting sequence
2898 * sequence 1: non-increasing absolute difference between x*_j and the value the variable is fixed to, i.e.
2899 * x*_1 >= x*_2 >= ... >= x*_|F|
2900 * in case of equality uses
2901 * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2902 */
2903 for( j = 0; j < nvarsF; j++ )
2904 {
2905 sortkeypairsF[j] = &(sortkeypairsFstore[j]);
2906 sortkeypairsF[j]->key1 = solvals[varsF[j]];
2907 sortkeypairsF[j]->key2 = (SCIP_Real) weights[varsF[j]];
2908 }
2909
2910 /* gets sorting key for variables in C_2 corresponding to the following lifting sequence
2911 * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2912 */
2913 for( j = 0; j < nvarsC2; j++ )
2914 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2915
2916 /* gets sorting key for variables in R corresponding to the following lifting sequence
2917 * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|R|
2918 */
2919 for( j = 0; j < nvarsR; j++ )
2920 sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
2921
2922 /* sorts F, C2 and R */
2923 if( nvarsF > 0 )
2924 {
2925 SCIPsortDownPtrInt((void**)sortkeypairsF, varsF, compSortkeypairs, nvarsF);
2926 }
2927 if( nvarsC2 > 0 )
2928 {
2929 SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
2930 }
2931 if( nvarsR > 0)
2932 {
2933 SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
2934 }
2935
2936 /* frees temporary memory */
2937 SCIPfreeBufferArray(scip, &sortkeysR);
2938 SCIPfreeBufferArray(scip, &sortkeysC2);
2939 SCIPfreeBufferArray(scip, &sortkeypairsFstore);
2940 SCIPfreeBufferArray(scip, &sortkeypairsF);
2941
2942 return SCIP_OKAY;
2943}
2944
2945/** categorizes GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of the GUBs
2946 * for the sequential GUB wise lifting procedure
2947 */
2948static
2950 SCIP* scip, /**< SCIP data structure */
2951 SCIP_GUBSET* gubset, /**< GUB set data structure */
2952 SCIP_Real* solvals, /**< solution values of variables in knapsack constraint */
2953 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2954 int* varsC1, /**< variables in C1 */
2955 int* varsC2, /**< variables in C2 */
2956 int* varsF, /**< variables in F */
2957 int* varsR, /**< variables in R */
2958 int nvarsC1, /**< number of variables in C1 */
2959 int nvarsC2, /**< number of variables in C2 */
2960 int nvarsF, /**< number of variables in F */
2961 int nvarsR, /**< number of variables in R */
2962 int* gubconsGC1, /**< pointer to store GUBs in GC1(GNC1+GOC1) */
2963 int* gubconsGC2, /**< pointer to store GUBs in GC2 */
2964 int* gubconsGFC1, /**< pointer to store GUBs in GFC1(GNC1+GF) */
2965 int* gubconsGR, /**< pointer to store GUBs in GR */
2966 int* ngubconsGC1, /**< pointer to store number of GUBs in GC1(GNC1+GOC1) */
2967 int* ngubconsGC2, /**< pointer to store number of GUBs in GC2 */
2968 int* ngubconsGFC1, /**< pointer to store number of GUBs in GFC1(GNC1+GF) */
2969 int* ngubconsGR, /**< pointer to store number of GUBs in GR */
2970 int* ngubconscapexceed, /**< pointer to store number of GUBs with only capacity exceeding variables */
2971 int* maxgubvarssize /**< pointer to store the maximal size of GUB constraints */
2972 )
2973{
2974 SORTKEYPAIR** sortkeypairsGFC1;
2975 SORTKEYPAIR* sortkeypairsGFC1store;
2976 SCIP_Real* sortkeysC1;
2977 SCIP_Real* sortkeysC2;
2978 SCIP_Real* sortkeysR;
2979 int* nC1varsingubcons;
2980 int var;
2981 int gubconsidx;
2982 int varidx;
2983 int ngubconss;
2984 int ngubconsGOC1;
2985 int targetvar;
2986#ifndef NDEBUG
2987 int nvarsprocessed = 0;
2988#endif
2989 int i;
2990 int j;
2991
2992#if GUBSPLITGNC1GUBS
2993 SCIP_Bool gubconswithF;
2994 int origngubconss;
2995 origngubconss = gubset->ngubconss;
2996#endif
2997
2998 assert(scip != NULL);
2999 assert(gubset != NULL);
3000 assert(solvals != NULL);
3001 assert(weights != NULL);
3002 assert(varsC1 != NULL);
3003 assert(varsC2 != NULL);
3004 assert(varsF != NULL);
3005 assert(varsR != NULL);
3006 assert(nvarsC1 > 0);
3007 assert(nvarsC2 >= 0);
3008 assert(nvarsF >= 0);
3009 assert(nvarsR >= 0);
3010 assert(gubconsGC1 != NULL);
3011 assert(gubconsGC2 != NULL);
3012 assert(gubconsGFC1 != NULL);
3013 assert(gubconsGR != NULL);
3014 assert(ngubconsGC1 != NULL);
3015 assert(ngubconsGC2 != NULL);
3016 assert(ngubconsGFC1 != NULL);
3017 assert(ngubconsGR != NULL);
3018 assert(maxgubvarssize != NULL);
3019
3020 ngubconss = gubset->ngubconss;
3021 ngubconsGOC1 = 0;
3022
3023 /* GUBs are categorized into different types according to the variables in volved
3024 * - GOC1: involves variables in C1 only -- no C2, R, F
3025 * - GNC1: involves variables in C1 and F (and R) -- no C2
3026 * - GF: involves variables in F (and R) only -- no C1, C2
3027 * - GC2: involves variables in C2 only -- no C1, R, F
3028 * - GR: involves variables in R only -- no C1, C2, F
3029 * which requires splitting GUBs in case they include variable in F and R.
3030 *
3031 * afterwards all GUBs (except GOC1 GUBs, which we do not need to lift) are sorted by a two level lifting sequence.
3032 * - first ordering level is: GFC1 (GNC1+GF), GC2, and GR.
3033 * - second ordering level is
3034 * GFC1: non-increasing number of variables in F and non-increasing max{x*_k : k in GFC1_j} in case of equality
3035 * GC2: non-increasing max{ a_k : k in GC2_j}; note that |GFC2_j| = 1
3036 * GR: non-increasing max{ a_k : k in GR_j}
3037 *
3038 * in additon, another GUB union, which is helpful for the lifting procedure, is formed
3039 * - GC1: GUBs of category GOC1 and GNC1
3040 * with second ordering level non-decreasing min{ a_k : k in GC1_j };
3041 * note that min{ a_k : k in GC1_j } always comes from the first variable in the GUB
3042 */
3043
3044 /* allocates temporary memory */
3045 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC1, nvarsC1) );
3046 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
3047 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
3048
3049 /* to get the GUB lifting sequence, we first sort all variables in F, C2, and R
3050 * - F: non-increasing x*_j and non-increasing a_j in case of equality
3051 * - C2: non-increasing a_j
3052 * - R: non-increasing a_j
3053 * furthermore, sort C1 variables as needed for initializing the minweight table (non-increasing a_j).
3054 */
3055
3056 /* gets sorting key for variables in C1 corresponding to the following ordering
3057 * non-decreasing a_j, i.e. a_1 <= a_2 <= ... <= a_|C_1|
3058 */
3059 for( j = 0; j < nvarsC1; j++ )
3060 {
3061 /* gets sortkeys */
3062 sortkeysC1[j] = (SCIP_Real) weights[varsC1[j]];
3063
3064 /* update status of variable in its gub constraint */
3065 gubconsidx = gubset->gubconssidx[varsC1[j]];
3066 varidx = gubset->gubvarsidx[varsC1[j]];
3068 }
3069
3070 /* gets sorting key for variables in F corresponding to the following ordering
3071 * non-increasing x*_j, i.e., x*_1 >= x*_2 >= ... >= x*_|F|, and
3072 * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|F| in case of equality
3073 * and updates status of each variable in F in GUB set data structure
3074 */
3075 for( j = 0; j < nvarsF; j++ )
3076 {
3077 /* update status of variable in its gub constraint */
3078 gubconsidx = gubset->gubconssidx[varsF[j]];
3079 varidx = gubset->gubvarsidx[varsF[j]];
3081 }
3082
3083 /* gets sorting key for variables in C2 corresponding to the following ordering
3084 * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|C2|
3085 * and updates status of each variable in F in GUB set data structure
3086 */
3087 for( j = 0; j < nvarsC2; j++ )
3088 {
3089 /* gets sortkeys */
3090 sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
3091
3092 /* update status of variable in its gub constraint */
3093 gubconsidx = gubset->gubconssidx[varsC2[j]];
3094 varidx = gubset->gubvarsidx[varsC2[j]];
3096 }
3097
3098 /* gets sorting key for variables in R corresponding to the following ordering
3099 * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|R|
3100 * and updates status of each variable in F in GUB set data structure
3101 */
3102 for( j = 0; j < nvarsR; j++ )
3103 {
3104 /* gets sortkeys */
3105 sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
3106
3107 /* update status of variable in its gub constraint */
3108 gubconsidx = gubset->gubconssidx[varsR[j]];
3109 varidx = gubset->gubvarsidx[varsR[j]];
3111 }
3112
3113 /* sorts C1, F, C2 and R */
3114 assert(nvarsC1 > 0);
3115 SCIPsortRealInt(sortkeysC1, varsC1, nvarsC1);
3116
3117 if( nvarsC2 > 0 )
3118 {
3119 SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
3120 }
3121 if( nvarsR > 0)
3122 {
3123 SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
3124 }
3125
3126 /* frees temporary memory */
3127 SCIPfreeBufferArray(scip, &sortkeysR);
3128 SCIPfreeBufferArray(scip, &sortkeysC2);
3129 SCIPfreeBufferArray(scip, &sortkeysC1);
3130
3131 /* allocate and initialize temporary memory for sorting GUB constraints */
3132 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1, ngubconss) );
3133 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1store, ngubconss) );
3134 SCIP_CALL( SCIPallocBufferArray(scip, &nC1varsingubcons, ngubconss) );
3135 BMSclearMemoryArray(nC1varsingubcons, ngubconss);
3136 for( i = 0; i < ngubconss; i++)
3137 {
3138 sortkeypairsGFC1[i] = &(sortkeypairsGFC1store[i]);
3139 sortkeypairsGFC1[i]->key1 = 0.0;
3140 sortkeypairsGFC1[i]->key2 = 0.0;
3141 }
3142 *ngubconsGC1 = 0;
3143 *ngubconsGC2 = 0;
3144 *ngubconsGFC1 = 0;
3145 *ngubconsGR = 0;
3146 *ngubconscapexceed = 0;
3147 *maxgubvarssize = 0;
3148
3149#ifndef NDEBUG
3150 for( i = 0; i < gubset->ngubconss; i++ )
3152#endif
3153
3154 /* stores GUBs of group GC1 (GOC1+GNC1) and part of the GUBs of group GFC1 (GNC1 GUBs) and sorts variables in these GUBs
3155 * s.t. C1 variables come first (will automatically be sorted by non-decreasing weight).
3156 * gets sorting keys for GUBs of type GFC1 corresponding to the following ordering
3157 * non-increasing number of variables in F, and
3158 * non-increasing max{x*_k : k in GFC1_j} in case of equality
3159 */
3160 for( i = 0; i < nvarsC1; i++ )
3161 {
3162 int nvarsC1capexceed;
3163
3164 nvarsC1capexceed = 0;
3165
3166 var = varsC1[i];
3167 gubconsidx = gubset->gubconssidx[var];
3168 varidx = gubset->gubvarsidx[var];
3169
3170 assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3172
3173 /* current C1 variable is put to the front of its GUB where C1 part is stored by non-decreasing weigth;
3174 * note that variables in C1 are already sorted by non-decreasing weigth
3175 */
3176 targetvar = gubset->gubconss[gubconsidx]->gubvars[nC1varsingubcons[gubconsidx]];
3177 GUBsetSwapVars(scip, gubset, var, targetvar);
3178 nC1varsingubcons[gubconsidx]++;
3179
3180 /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3181 if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3182 {
3184 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3185 continue;
3186 }
3187
3188 /* determine the status of the current GUB constraint, GOC1 or GNC1; GUBs involving R variables are split into
3189 * GOC1/GNC1 and GF, if wanted. also update sorting key if GUB is of type GFC1 (GNC1)
3190 */
3191#if GUBSPLITGNC1GUBS
3192 gubconswithF = FALSE;
3193#endif
3194 for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3195 {
3196 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2);
3197
3198 /* C1-variable: update number of C1/capacity exceeding variables */
3199 if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_C1 )
3200 {
3201 nvarsC1capexceed++;
3202#ifndef NDEBUG
3203 nvarsprocessed++;
3204#endif
3205 }
3206 /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3207 else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3208 {
3209#if GUBSPLITGNC1GUBS
3210 gubconswithF = TRUE;
3211#endif
3212 sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3213
3214 if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3215 sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3216 }
3217 else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_CAPACITYEXCEEDED )
3218 {
3219 nvarsC1capexceed++;
3220 }
3221 else
3222 assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_R);
3223 }
3224
3225 /* update set of GC1 GUBs */
3226 gubconsGC1[*ngubconsGC1] = gubconsidx;
3227 (*ngubconsGC1)++;
3228
3229 /* update maximum size of all GUB constraints */
3230 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3231 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3232
3233 /* set status of GC1-GUB (GOC1 or GNC1) and update set of GFC1 GUBs */
3234 if( nvarsC1capexceed == gubset->gubconss[gubconsidx]->ngubvars )
3235 {
3236 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3237 ngubconsGOC1++;
3238 }
3239 else
3240 {
3241#if GUBSPLITGNC1GUBS
3242 /* only variables in C1 and R -- no in F: GUB will be split into GR and GOC1 GUBs */
3243 if( !gubconswithF )
3244 {
3245 GUBVARSTATUS movevarstatus;
3246
3247 assert(gubset->ngubconss < gubset->nvars);
3248
3249 /* create a new GUB for GR part of splitting */
3250 SCIP_CALL( GUBconsCreate(scip, &gubset->gubconss[gubset->ngubconss]) );
3251 gubset->ngubconss++;
3252 ngubconss = gubset->ngubconss;
3253
3254 /* fill GR with R variables in current GUB */
3255 for( j = gubset->gubconss[gubconsidx]->ngubvars-1; j >= 0; j-- )
3256 {
3257 movevarstatus = gubset->gubconss[gubconsidx]->gubvarsstatus[j];
3258 if( movevarstatus != GUBVARSTATUS_BELONGSTOSET_C1 )
3259 {
3260 assert(movevarstatus == GUBVARSTATUS_BELONGSTOSET_R || movevarstatus == GUBVARSTATUS_CAPACITYEXCEEDED);
3261 SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, gubset->gubconss[gubconsidx]->gubvars[j],
3262 gubconsidx, ngubconss-1) );
3263 gubset->gubconss[ngubconss-1]->gubvarsstatus[gubset->gubconss[ngubconss-1]->ngubvars-1] =
3264 movevarstatus;
3265 }
3266 }
3267
3268 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3269 ngubconsGOC1++;
3270
3272 gubconsGR[*ngubconsGR] = ngubconss-1;
3273 (*ngubconsGR)++;
3274 }
3275 /* variables in C1, F, and maybe R: GNC1 GUB */
3276 else
3277 {
3278 assert(gubconswithF);
3279
3280 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3281 gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3282 (*ngubconsGFC1)++;
3283 }
3284#else
3285 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3286 gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3287 (*ngubconsGFC1)++;
3288#endif
3289 }
3290 }
3291
3292 /* stores GUBs of group GC2 (only trivial GUBs); sorting is not required because the C2 variables (which we loop over)
3293 * are already sorted correctly
3294 */
3295 for( i = 0; i < nvarsC2; i++ )
3296 {
3297 var = varsC2[i];
3298 gubconsidx = gubset->gubconssidx[var];
3299 varidx = gubset->gubvarsidx[var];
3300
3301 assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3302 assert(gubset->gubconss[gubconsidx]->ngubvars == 1);
3303 assert(varidx == 0);
3305 assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_UNINITIAL);
3306
3307 /* set status of GC2 GUB */
3308 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GC2;
3309
3310 /* update group of GC2 GUBs */
3311 gubconsGC2[*ngubconsGC2] = gubconsidx;
3312 (*ngubconsGC2)++;
3313
3314 /* update maximum size of all GUB constraints */
3315 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3316 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3317
3318#ifndef NDEBUG
3319 nvarsprocessed++;
3320#endif
3321 }
3322
3323 /* stores remaining part of the GUBs of group GFC1 (GF GUBs) and gets GUB sorting keys corresp. to following ordering
3324 * non-increasing number of variables in F, and
3325 * non-increasing max{x*_k : k in GFC1_j} in case of equality
3326 */
3327 for( i = 0; i < nvarsF; i++ )
3328 {
3329 var = varsF[i];
3330 gubconsidx = gubset->gubconssidx[var];
3331 varidx = gubset->gubvarsidx[var];
3332
3333 assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3335
3336#ifndef NDEBUG
3337 nvarsprocessed++;
3338#endif
3339
3340 /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3341 if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3342 {
3344 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3345 continue;
3346 }
3347
3348 /* set status of GF GUB */
3349 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GF;
3350
3351 /* update sorting key of corresponding GFC1 GUB */
3352 for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3353 {
3355 && gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C1);
3356
3357 /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3358 if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3359 {
3360 sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3361
3362 if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3363 sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3364 }
3365 }
3366
3367 /* update set of GFC1 GUBs */
3368 gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3369 (*ngubconsGFC1)++;
3370
3371 /* update maximum size of all GUB constraints */
3372 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3373 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3374 }
3375
3376 /* stores GUBs of group GR; sorting is not required because the R variables (which we loop over) are already sorted
3377 * correctly
3378 */
3379 for( i = 0; i < nvarsR; i++ )
3380 {
3381 var = varsR[i];
3382 gubconsidx = gubset->gubconssidx[var];
3383 varidx = gubset->gubvarsidx[var];
3384
3385 assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3387
3388#ifndef NDEBUG
3389 nvarsprocessed++;
3390#endif
3391
3392 /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3393 if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3394 {
3396 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3397 || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3398 continue;
3399 }
3400
3401 /* set status of GR GUB */
3402 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GR;
3403
3404 /* update set of GR GUBs */
3405 gubconsGR[*ngubconsGR] = gubconsidx;
3406 (*ngubconsGR)++;
3407
3408 /* update maximum size of all GUB constraints */
3409 if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3410 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3411 }
3412 assert(nvarsprocessed == nvarsC1 + nvarsC2 + nvarsF + nvarsR);
3413
3414 /* update number of GUBs with only capacity exceeding variables (will not be used for lifting) */
3415 (*ngubconscapexceed) = ngubconss - (ngubconsGOC1 + (*ngubconsGC2) + (*ngubconsGFC1) + (*ngubconsGR));
3416 assert(*ngubconscapexceed >= 0);
3417#ifndef NDEBUG
3418 {
3419 int check;
3420
3421 check = 0;
3422
3423 /* remaining not handled GUBs should only contain capacity exceeding variables */
3424 for( i = 0; i < ngubconss; i++ )
3425 {
3426 if( gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL )
3427 check++;
3428 }
3429 assert(check == *ngubconscapexceed);
3430 }
3431#endif
3432
3433 /* sort GFCI GUBs according to computed sorting keys */
3434 if( (*ngubconsGFC1) > 0 )
3435 {
3436 SCIPsortDownPtrInt((void**)sortkeypairsGFC1, gubconsGFC1, compSortkeypairs, (*ngubconsGFC1));
3437 }
3438
3439 /* free temporary memory */
3440#if GUBSPLITGNC1GUBS
3441 ngubconss = origngubconss;
3442#endif
3443 SCIPfreeBufferArray(scip, &nC1varsingubcons);
3444 SCIPfreeBufferArray(scip, &sortkeypairsGFC1store);
3445 SCIPfreeBufferArray(scip, &sortkeypairsGFC1);
3446
3447 return SCIP_OKAY;
3448}
3449
3450/** enlarges minweight table to at least the given length */
3451static
3453 SCIP* scip, /**< SCIP data structure */
3454 SCIP_Longint** minweightsptr, /**< pointer to minweights table */
3455 int* minweightslen, /**< pointer to store number of entries in minweights table (incl. z=0) */
3456 int* minweightssize, /**< pointer to current size of minweights table */
3457 int newlen /**< new length of minweights table */
3458 )
3459{
3460 int j;
3461
3462 assert(minweightsptr != NULL);
3463 assert(*minweightsptr != NULL);
3464 assert(minweightslen != NULL);
3465 assert(*minweightslen >= 0);
3466 assert(minweightssize != NULL);
3467 assert(*minweightssize >= 0);
3468
3469 if( newlen > *minweightssize )
3470 {
3471 int newsize;
3472
3473 /* reallocate table memory */
3474 newsize = SCIPcalcMemGrowSize(scip, newlen);
3475 SCIP_CALL( SCIPreallocBufferArray(scip, minweightsptr, newsize) );
3476 *minweightssize = newsize;
3477 }
3478 assert(newlen <= *minweightssize);
3479
3480 /* initialize new elements */
3481 for( j = *minweightslen; j < newlen; ++j )
3482 (*minweightsptr)[j] = SCIP_LONGINT_MAX;
3483 *minweightslen = newlen;
3484
3485 return SCIP_OKAY;
3486}
3487
3488/** lifts given inequality
3489 * sum_{j in M_1} x_j <= alpha_0
3490 * valid for
3491 * 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 }
3492 * to a valid inequality
3493 * 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
3494 * <= alpha_0 + sum_{j in M_2} alpha_j
3495 * for
3496 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 };
3497 * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in M_2, and
3498 * sequential up-lifting for the variables in R; procedure can be used to strengthen minimal cover inequalities and
3499 * extended weight inequalities.
3500 */
3501static
3503 SCIP* scip, /**< SCIP data structure */
3504 SCIP_VAR** vars, /**< variables in knapsack constraint */
3505 int nvars, /**< number of variables in knapsack constraint */
3506 int ntightened, /**< number of variables with tightened upper bound */
3507 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3508 SCIP_Longint capacity, /**< capacity of knapsack */
3509 SCIP_Real* solvals, /**< solution values of all problem variables */
3510 int* varsM1, /**< variables in M_1 */
3511 int* varsM2, /**< variables in M_2 */
3512 int* varsF, /**< variables in F */
3513 int* varsR, /**< variables in R */
3514 int nvarsM1, /**< number of variables in M_1 */
3515 int nvarsM2, /**< number of variables in M_2 */
3516 int nvarsF, /**< number of variables in F */
3517 int nvarsR, /**< number of variables in R */
3518 int alpha0, /**< rights hand side of given valid inequality */
3519 int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3520 SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3521 int* liftrhs /**< pointer to store right hand side of the lifted valid inequality */
3522 )
3523{
3524 SCIP_Longint* minweights;
3525 SCIP_Real* sortkeys;
3526 SCIP_Longint fixedonesweight;
3527 int minweightssize;
3528 int minweightslen;
3529 int j;
3530 int w;
3531
3532 assert(scip != NULL);
3533 assert(vars != NULL);
3534 assert(nvars >= 0);
3535 assert(weights != NULL);
3536 assert(capacity >= 0);
3537 assert(solvals != NULL);
3538 assert(varsM1 != NULL);
3539 assert(varsM2 != NULL);
3540 assert(varsF != NULL);
3541 assert(varsR != NULL);
3542 assert(nvarsM1 >= 0 && nvarsM1 <= nvars - ntightened);
3543 assert(nvarsM2 >= 0 && nvarsM2 <= nvars - ntightened);
3544 assert(nvarsF >= 0 && nvarsF <= nvars - ntightened);
3545 assert(nvarsR >= 0 && nvarsR <= nvars - ntightened);
3546 assert(nvarsM1 + nvarsM2 + nvarsF + nvarsR == nvars - ntightened);
3547 assert(alpha0 >= 0);
3548 assert(liftcoefs != NULL);
3549 assert(cutact != NULL);
3550 assert(liftrhs != NULL);
3551
3552 /* allocates temporary memory */
3553 minweightssize = nvarsM1 + 1;
3554 SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
3555 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvarsM1) );
3556
3557 /* initializes data structures */
3558 BMSclearMemoryArray(liftcoefs, nvars);
3559 *cutact = 0.0;
3560
3561 /* sets lifting coefficient of variables in M1, sorts variables in M1 such that a_1 <= a_2 <= ... <= a_|M1|
3562 * and calculates activity of the current valid inequality
3563 */
3564 for( j = 0; j < nvarsM1; j++ )
3565 {
3566 assert(liftcoefs[varsM1[j]] == 0);
3567 liftcoefs[varsM1[j]] = 1;
3568 sortkeys[j] = (SCIP_Real) (weights[varsM1[j]]);
3569 (*cutact) += solvals[varsM1[j]];
3570 }
3571
3572 SCIPsortRealInt(sortkeys, varsM1, nvarsM1);
3573
3574 /* initializes (i = 1) the minweight table, defined as: minweights_i[w] =
3575 * min sum_{j in M_1} a_j x_j + sum_{k=1}^{i-1} a_{j_k} x_{j_k}
3576 * s.t. sum_{j in M_1} x_j + sum_{k=1}^{i-1} alpha_{j_k} x_{j_k} >= w
3577 * x_j in {0,1} for j in M_1 & {j_i,...,j_i-1},
3578 * for i = 1,...,t with t = |N\M1| and w = 0,...,|M1| + sum_{k=1}^{i-1} alpha_{j_k};
3579 */
3580 minweights[0] = 0;
3581 for( w = 1; w <= nvarsM1; w++ )
3582 minweights[w] = minweights[w-1] + weights[varsM1[w-1]];
3583 minweightslen = nvarsM1 + 1;
3584
3585 /* gets sum of weights of variables fixed to one, i.e. sum of weights of variables in M_2 */
3586 fixedonesweight = 0;
3587 for( j = 0; j < nvarsM2; j++ )
3588 fixedonesweight += weights[varsM2[j]];
3589 assert(fixedonesweight >= 0);
3590
3591 /* initializes right hand side of lifted valid inequality */
3592 *liftrhs = alpha0;
3593
3594 /* sequentially up-lifts all variables in F: */
3595 for( j = 0; j < nvarsF; j++ )
3596 {
3597 SCIP_Longint weight;
3598 int liftvar;
3599 int liftcoef;
3600 int z;
3601
3602 liftvar = varsF[j];
3603 weight = weights[liftvar];
3604 assert(liftvar >= 0 && liftvar < nvars);
3605 assert(SCIPisFeasGT(scip, solvals[liftvar], 0.0));
3606 assert(weight > 0);
3607
3608 /* knapsack problem is infeasible:
3609 * sets z = 0
3610 */
3611 if( capacity - fixedonesweight - weight < 0 )
3612 {
3613 z = 0;
3614 }
3615 /* knapsack problem is feasible:
3616 * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
3617 * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
3618 */
3619 else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
3620 {
3621 z = *liftrhs;
3622 }
3623 /* knapsack problem is feasible:
3624 * uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} }
3625 */
3626 else
3627 {
3628 int left;
3629 int right;
3630 int middle;
3631
3632 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
3633 left = 0;
3634 right = (*liftrhs) + 1;
3635 while( left < right - 1 )
3636 {
3637 middle = (left + right) / 2;
3638 assert(0 <= middle && middle < minweightslen);
3639 if( minweights[middle] <= capacity - fixedonesweight - weight )
3640 left = middle;
3641 else
3642 right = middle;
3643 }
3644 assert(left == right - 1);
3645 assert(0 <= left && left < minweightslen);
3646 assert(minweights[left] <= capacity - fixedonesweight - weight );
3647 assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
3648
3649 /* now z = left */
3650 z = left;
3651 assert(z <= *liftrhs);
3652 }
3653
3654 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3655 liftcoef = (*liftrhs) - z;
3656 liftcoefs[liftvar] = liftcoef;
3657 assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
3658
3659 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3660 if( liftcoef == 0 )
3661 continue;
3662
3663 /* updates activity of current valid inequality */
3664 (*cutact) += liftcoef * solvals[liftvar];
3665
3666 /* enlarges current minweight table:
3667 * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3668 * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3669 * and sets minweights_i[w] = infinity for
3670 * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3671 */
3672 SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3673
3674 /* updates minweight table: minweight_i+1[w] =
3675 * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3676 * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3677 */
3678 for( w = minweightslen - 1; w >= 0; w-- )
3679 {
3680 SCIP_Longint min;
3681 if( w < liftcoef )
3682 {
3683 min = MIN(minweights[w], weight);
3684 minweights[w] = min;
3685 }
3686 else
3687 {
3688 assert(w >= liftcoef);
3689 min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3690 minweights[w] = min;
3691 }
3692 }
3693 }
3694 assert(minweights[0] == 0);
3695
3696 /* sequentially down-lifts all variables in M_2: */
3697 for( j = 0; j < nvarsM2; j++ )
3698 {
3699 SCIP_Longint weight;
3700 int liftvar;
3701 int liftcoef;
3702 int left;
3703 int right;
3704 int middle;
3705 int z;
3706
3707 liftvar = varsM2[j];
3708 weight = weights[liftvar];
3709 assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
3710 assert(liftvar >= 0 && liftvar < nvars);
3711 assert(weight > 0);
3712
3713 /* uses binary search to find
3714 * z = max { w : 0 <= w <= |M_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
3715 */
3716 left = 0;
3717 right = minweightslen;
3718 while( left < right - 1 )
3719 {
3720 middle = (left + right) / 2;
3721 assert(0 <= middle && middle < minweightslen);
3722 if( minweights[middle] <= capacity - fixedonesweight + weight )
3723 left = middle;
3724 else
3725 right = middle;
3726 }
3727 assert(left == right - 1);
3728 assert(0 <= left && left < minweightslen);
3729 assert(minweights[left] <= capacity - fixedonesweight + weight );
3730 assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight + weight);
3731
3732 /* now z = left */
3733 z = left;
3734 assert(z >= *liftrhs);
3735
3736 /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
3737 liftcoef = z - (*liftrhs);
3738 liftcoefs[liftvar] = liftcoef;
3739 assert(liftcoef >= 0);
3740
3741 /* updates sum of weights of variables fixed to one */
3742 fixedonesweight -= weight;
3743
3744 /* updates right-hand side of current valid inequality */
3745 (*liftrhs) += liftcoef;
3746 assert(*liftrhs >= alpha0);
3747
3748 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3749 if( liftcoef == 0 )
3750 continue;
3751
3752 /* updates activity of current valid inequality */
3753 (*cutact) += liftcoef * solvals[liftvar];
3754
3755 /* enlarges current minweight table:
3756 * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3757 * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3758 * and sets minweights_i[w] = infinity for
3759 * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3760 */
3761 SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3762
3763 /* updates minweight table: minweight_i+1[w] =
3764 * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3765 * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3766 */
3767 for( w = minweightslen - 1; w >= 0; w-- )
3768 {
3769 SCIP_Longint min;
3770 if( w < liftcoef )
3771 {
3772 min = MIN(minweights[w], weight);
3773 minweights[w] = min;
3774 }
3775 else
3776 {
3777 assert(w >= liftcoef);
3778 min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3779 minweights[w] = min;
3780 }
3781 }
3782 }
3783 assert(fixedonesweight == 0);
3784 assert(*liftrhs >= alpha0);
3785
3786 /* sequentially up-lifts all variables in R: */
3787 for( j = 0; j < nvarsR; j++ )
3788 {
3789 SCIP_Longint weight;
3790 int liftvar;
3791 int liftcoef;
3792 int z;
3793
3794 liftvar = varsR[j];
3795 weight = weights[liftvar];
3796 assert(liftvar >= 0 && liftvar < nvars);
3797 assert(SCIPisFeasEQ(scip, solvals[liftvar], 0.0));
3798 assert(weight > 0);
3799 assert(capacity - weight >= 0);
3800 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
3801
3802 /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
3803 * if minweights_i[liftrhs] <= a_0 - a_{j_i}
3804 */
3805 if( minweights[*liftrhs] <= capacity - weight )
3806 {
3807 z = *liftrhs;
3808 }
3809 /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
3810 */
3811 else
3812 {
3813 int left;
3814 int right;
3815 int middle;
3816
3817 left = 0;
3818 right = (*liftrhs) + 1;
3819 while( left < right - 1)
3820 {
3821 middle = (left + right) / 2;
3822 assert(0 <= middle && middle < minweightslen);
3823 if( minweights[middle] <= capacity - weight )
3824 left = middle;
3825 else
3826 right = middle;
3827 }
3828 assert(left == right - 1);
3829 assert(0 <= left && left < minweightslen);
3830 assert(minweights[left] <= capacity - weight );
3831 assert(left == minweightslen - 1 || minweights[left+1] > capacity - weight);
3832
3833 /* now z = left */
3834 z = left;
3835 assert(z <= *liftrhs);
3836 }
3837
3838 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3839 liftcoef = (*liftrhs) - z;
3840 liftcoefs[liftvar] = liftcoef;
3841 assert(liftcoef >= 0 && liftcoef <= *liftrhs);
3842
3843 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3844 if( liftcoef == 0 )
3845 continue;
3846
3847 /* updates activity of current valid inequality */
3848 (*cutact) += liftcoef * solvals[liftvar];
3849
3850 /* updates minweight table: minweight_i+1[w] =
3851 * min{ minweight_i[w], a_{j_i}}, if w < alpha_j_i
3852 * min{ minweight_i[w], minweight_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3853 */
3854 for( w = *liftrhs; w >= 0; w-- )
3855 {
3856 SCIP_Longint min;
3857 if( w < liftcoef )
3858 {
3859 min = MIN(minweights[w], weight);
3860 minweights[w] = min;
3861 }
3862 else
3863 {
3864 assert(w >= liftcoef);
3865 min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3866 minweights[w] = min;
3867 }
3868 }
3869 }
3870
3871 /* frees temporary memory */
3872 SCIPfreeBufferArray(scip, &sortkeys);
3873 SCIPfreeBufferArray(scip, &minweights);
3874
3875 return SCIP_OKAY;
3876}
3877
3878/** adds two minweight values in a safe way, i.e,, ensures no overflow */
3879static
3881 SCIP_Longint val1, /**< first value to add */
3882 SCIP_Longint val2 /**< second value to add */
3883 )
3884{
3885 assert(val1 >= 0);
3886 assert(val2 >= 0);
3887
3888 if( val1 >= SCIP_LONGINT_MAX || val2 >= SCIP_LONGINT_MAX )
3889 return SCIP_LONGINT_MAX;
3890 else
3891 {
3892 assert(val1 <= SCIP_LONGINT_MAX - val2);
3893 return (val1 + val2);
3894 }
3895}
3896
3897/** computes minweights table for lifting with GUBs by combining unfished and fished tables */
3898static
3900 SCIP_Longint* minweights, /**< minweight table to compute */
3901 SCIP_Longint* finished, /**< given finished table */
3902 SCIP_Longint* unfinished, /**< given unfinished table */
3903 int minweightslen /**< length of minweight, finished, and unfinished tables */
3904 )
3905{
3906 int w1;
3907 int w2;
3908
3909 /* minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
3910 * note that finished and unfished arrays sorted by non-decreasing weight
3911 */
3912
3913 /* initialize minweight with w2 = 0 */
3914 w2 = 0;
3915 assert(unfinished[w2] == 0);
3916 for( w1 = 0; w1 < minweightslen; w1++ )
3917 minweights[w1] = finished[w1];
3918
3919 /* consider w2 = 1, ..., minweightslen-1 */
3920 for( w2 = 1; w2 < minweightslen; w2++ )
3921 {
3922 if( unfinished[w2] >= SCIP_LONGINT_MAX )
3923 break;
3924
3925 for( w1 = 0; w1 < minweightslen - w2; w1++ )
3926 {
3927 SCIP_Longint temp;
3928
3929 temp = safeAddMinweightsGUB(finished[w1], unfinished[w2]);
3930 if( temp <= minweights[w1+w2] )
3931 minweights[w1+w2] = temp;
3932 }
3933 }
3934}
3935
3936/** lifts given inequality
3937 * sum_{j in C_1} x_j <= alpha_0
3938 * valid for
3939 * 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;
3940 * sum_{j in Q_i} x_j <= 1, forall i in I }
3941 * to a valid inequality
3942 * 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
3943 * <= alpha_0 + sum_{j in C_2} alpha_j
3944 * for
3945 * 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 };
3946 * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
3947 * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
3948 * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
3949 */
3950static
3952 SCIP* scip, /**< SCIP data structure */
3953 SCIP_GUBSET* gubset, /**< GUB set data structure */
3954 SCIP_VAR** vars, /**< variables in knapsack constraint */
3955 int ngubconscapexceed, /**< number of GUBs with only capacity exceeding variables */
3956 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3957 SCIP_Longint capacity, /**< capacity of knapsack */
3958 SCIP_Real* solvals, /**< solution values of all knapsack variables */
3959 int* gubconsGC1, /**< GUBs in GC1(GNC1+GOC1) */
3960 int* gubconsGC2, /**< GUBs in GC2 */
3961 int* gubconsGFC1, /**< GUBs in GFC1(GNC1+GF) */
3962 int* gubconsGR, /**< GUBs in GR */
3963 int ngubconsGC1, /**< number of GUBs in GC1(GNC1+GOC1) */
3964 int ngubconsGC2, /**< number of GUBs in GC2 */
3965 int ngubconsGFC1, /**< number of GUBs in GFC1(GNC1+GF) */
3966 int ngubconsGR, /**< number of GUBs in GR */
3967 int alpha0, /**< rights hand side of given valid inequality */
3968 int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3969 SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3970 int* liftrhs, /**< pointer to store right hand side of the lifted valid inequality */
3971 int maxgubvarssize /**< maximal size of GUB constraints */
3972 )
3973{
3974 SCIP_Longint* minweights;
3975 SCIP_Longint* finished;
3976 SCIP_Longint* unfinished;
3977 int* gubconsGOC1;
3978 int* gubconsGNC1;
3979 int* liftgubvars;
3980 SCIP_Longint fixedonesweight;
3981 SCIP_Longint weight;
3982 SCIP_Longint weightdiff1;
3983 SCIP_Longint weightdiff2;
3984 SCIP_Longint min;
3985 int minweightssize;
3986 int minweightslen;
3987 int nvars;
3988 int varidx;
3989 int liftgubconsidx;
3990 int liftvar;
3991 int sumliftcoef;
3992 int liftcoef;
3993 int ngubconsGOC1;
3994 int ngubconsGNC1;
3995 int left;
3996 int right;
3997 int middle;
3998 int nliftgubvars;
3999 int tmplen;
4000 int tmpsize;
4001 int j;
4002 int k;
4003 int w;
4004 int z;
4005#ifndef NDEBUG
4006 int ngubconss;
4007 int nliftgubC1;
4008
4009 assert(gubset != NULL);
4010 ngubconss = gubset->ngubconss;
4011#else
4012 assert(gubset != NULL);
4013#endif
4014
4015 nvars = gubset->nvars;
4016
4017 assert(scip != NULL);
4018 assert(vars != NULL);
4019 assert(nvars >= 0);
4020 assert(weights != NULL);
4021 assert(capacity >= 0);
4022 assert(solvals != NULL);
4023 assert(gubconsGC1 != NULL);
4024 assert(gubconsGC2 != NULL);
4025 assert(gubconsGFC1 != NULL);
4026 assert(gubconsGR != NULL);
4027 assert(ngubconsGC1 >= 0 && ngubconsGC1 <= ngubconss - ngubconscapexceed);
4028 assert(ngubconsGC2 >= 0 && ngubconsGC2 <= ngubconss - ngubconscapexceed);
4029 assert(ngubconsGFC1 >= 0 && ngubconsGFC1 <= ngubconss - ngubconscapexceed);
4030 assert(ngubconsGR >= 0 && ngubconsGR <= ngubconss - ngubconscapexceed);
4031 assert(alpha0 >= 0);
4032 assert(liftcoefs != NULL);
4033 assert(cutact != NULL);
4034 assert(liftrhs != NULL);
4035
4036 minweightssize = ngubconsGC1+1;
4037
4038 /* allocates temporary memory */
4039 SCIP_CALL( SCIPallocBufferArray(scip, &liftgubvars, maxgubvarssize) );
4040 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGOC1, ngubconsGC1) );
4041 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGNC1, ngubconsGC1) );
4042 SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
4043 SCIP_CALL( SCIPallocBufferArray(scip, &finished, minweightssize) );
4044 SCIP_CALL( SCIPallocBufferArray(scip, &unfinished, minweightssize) );
4045
4046 /* initializes data structures */
4047 BMSclearMemoryArray(liftcoefs, nvars);
4048 *cutact = 0.0;
4049
4050 /* gets GOC1 and GNC1 GUBs, sets lifting coefficient of variables in C1 and calculates activity of the current
4051 * valid inequality
4052 */
4053 ngubconsGOC1 = 0;
4054 ngubconsGNC1 = 0;
4055 for( j = 0; j < ngubconsGC1; j++ )
4056 {
4057 if( gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GOC1 )
4058 {
4059 gubconsGOC1[ngubconsGOC1] = gubconsGC1[j];
4060 ngubconsGOC1++;
4061 }
4062 else
4063 {
4064 assert(gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4065 gubconsGNC1[ngubconsGNC1] = gubconsGC1[j];
4066 ngubconsGNC1++;
4067 }
4068 for( k = 0; k < gubset->gubconss[gubconsGC1[j]]->ngubvars
4069 && gubset->gubconss[gubconsGC1[j]]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4070 {
4071 varidx = gubset->gubconss[gubconsGC1[j]]->gubvars[k];
4072 assert(varidx >= 0 && varidx < nvars);
4073 assert(liftcoefs[varidx] == 0);
4074
4075 liftcoefs[varidx] = 1;
4076 (*cutact) += solvals[varidx];
4077 }
4078 assert(k >= 1);
4079 }
4080 assert(ngubconsGOC1 + ngubconsGFC1 + ngubconsGC2 + ngubconsGR == ngubconss - ngubconscapexceed);
4081 assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4082
4083 /* initialize the minweight tables, defined as: for i = 1,...,m with m = |I| and w = 0,...,|gubconsGC1|;
4084 * - finished_i[w] =
4085 * min sum_{k = 1,2,...,i-1} sum_{j in Q_k} a_j x_j
4086 * s.t. sum_{k = 1,2,...,i-1} sum_{j in Q_k} alpha_j x_j >= w
4087 * sum_{j in Q_k} x_j <= 1
4088 * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4089 * - unfinished_i[w] =
4090 * min sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} a_j x_j
4091 * s.t. sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} x_j >= w
4092 * sum_{j in Q_k} x_j <= 1
4093 * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4094 * - minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
4095 */
4096
4097 /* initialize finished table; note that variables in GOC1 GUBs (includes C1 and capacity exceeding variables)
4098 * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4099 * 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
4100 * comes from the first variable in the GUB
4101 */
4102 assert(ngubconsGOC1 <= ngubconsGC1);
4103 finished[0] = 0;
4104 for( w = 1; w <= ngubconsGOC1; w++ )
4105 {
4106 liftgubconsidx = gubconsGOC1[w-1];
4107
4108 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1);
4109 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4110
4111 varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4112
4113 assert(varidx >= 0 && varidx < nvars);
4114 assert(liftcoefs[varidx] == 1);
4115
4116 min = weights[varidx];
4117 finished[w] = finished[w-1] + min;
4118
4119#ifndef NDEBUG
4120 for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4121 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4122 {
4123 varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4124 assert(varidx >= 0 && varidx < nvars);
4125 assert(liftcoefs[varidx] == 1);
4126 assert(weights[varidx] >= min);
4127 }
4128#endif
4129 }
4130 for( w = ngubconsGOC1+1; w <= ngubconsGC1; w++ )
4131 finished[w] = SCIP_LONGINT_MAX;
4132
4133 /* initialize unfinished table; note that variables in GNC1 GUBs
4134 * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4135 * 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
4136 * comes from the first variable in the GUB
4137 */
4138 assert(ngubconsGNC1 <= ngubconsGC1);
4139 unfinished[0] = 0;
4140 for( w = 1; w <= ngubconsGNC1; w++ )
4141 {
4142 liftgubconsidx = gubconsGNC1[w-1];
4143
4144 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4145 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4146
4147 varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4148
4149 assert(varidx >= 0 && varidx < nvars);
4150 assert(liftcoefs[varidx] == 1);
4151
4152 min = weights[varidx];
4153 unfinished[w] = unfinished[w-1] + min;
4154
4155#ifndef NDEBUG
4156 for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4157 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4158 {
4159 varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4160 assert(varidx >= 0 && varidx < nvars);
4161 assert(liftcoefs[varidx] == 1);
4162 assert(weights[varidx] >= min );
4163 }
4164#endif
4165 }
4166 for( w = ngubconsGNC1 + 1; w <= ngubconsGC1; w++ )
4167 unfinished[w] = SCIP_LONGINT_MAX;
4168
4169 /* initialize minweights table; note that variables in GC1 GUBs
4170 * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4171 * we can directly initialize minweights instead of computing it from finished and unfinished (which would be more time
4172 * consuming) because is it has to be build using weights from C1 only.
4173 */
4174 assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4175 minweights[0] = 0;
4176 for( w = 1; w <= ngubconsGC1; w++ )
4177 {
4178 liftgubconsidx = gubconsGC1[w-1];
4179
4180 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
4181 || gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4182 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4183
4184 varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4185
4186 assert(varidx >= 0 && varidx < nvars);
4187 assert(liftcoefs[varidx] == 1);
4188
4189 min = weights[varidx];
4190 minweights[w] = minweights[w-1] + min;
4191
4192#ifndef NDEBUG
4193 for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4194 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4195 {
4196 varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4197 assert(varidx >= 0 && varidx < nvars);
4198 assert(liftcoefs[varidx] == 1);
4199 assert(weights[varidx] >= min);
4200 }
4201#endif
4202 }
4203 minweightslen = ngubconsGC1 + 1;
4204
4205 /* gets sum of weights of variables fixed to one, i.e. sum of weights of C2 variables GC2 GUBs */
4206 fixedonesweight = 0;
4207 for( j = 0; j < ngubconsGC2; j++ )
4208 {
4209 varidx = gubset->gubconss[gubconsGC2[j]]->gubvars[0];
4210
4211 assert(gubset->gubconss[gubconsGC2[j]]->ngubvars == 1);
4212 assert(varidx >= 0 && varidx < nvars);
4213 assert(gubset->gubconss[gubconsGC2[j]]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4214
4215 fixedonesweight += weights[varidx];
4216 }
4217 assert(fixedonesweight >= 0);
4218
4219 /* initializes right hand side of lifted valid inequality */
4220 *liftrhs = alpha0;
4221
4222 /* sequentially up-lifts all variables in GFC1 GUBs */
4223 for( j = 0; j < ngubconsGFC1; j++ )
4224 {
4225 liftgubconsidx = gubconsGFC1[j];
4226 assert(liftgubconsidx >= 0 && liftgubconsidx < ngubconss);
4227
4228 /* GNC1 GUB: update unfinished table (remove current GUB, i.e., remove min weight of C1 vars in GUB) and
4229 * compute minweight table via updated unfinished table and aleady upto date finished table;
4230 */
4231 k = 0;
4232 if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4233 {
4234 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4235 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4236 assert(ngubconsGNC1 > 0);
4237
4238 /* get number of C1 variables of current GNC1 GUB and put them into array of variables in GUB that
4239 * are considered for the lifting, i.e., not capacity exceeding
4240 */
4241 for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars
4242 && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4243 liftgubvars[k] = gubset->gubconss[liftgubconsidx]->gubvars[k];
4244 assert(k >= 1);
4245
4246 /* update unfinished table by removing current GNC1 GUB, i.e, remove C1 variable with minimal weight
4247 * unfinished[w] = MAX{unfinished[w], unfinished[w+1] - weight}, "weight" is the minimal weight of current GUB
4248 */
4249 weight = weights[liftgubvars[0]];
4250
4251 weightdiff2 = unfinished[ngubconsGNC1] - weight;
4252 unfinished[ngubconsGNC1] = SCIP_LONGINT_MAX;
4253 for( w = ngubconsGNC1-1; w >= 1; w-- )
4254 {
4255 weightdiff1 = weightdiff2;
4256 weightdiff2 = unfinished[w] - weight;
4257
4258 if( unfinished[w] < weightdiff1 )
4259 unfinished[w] = weightdiff1;
4260 else
4261 break;
4262 }
4263 ngubconsGNC1--;
4264
4265 /* computes minweights table by combining unfished and fished tables */
4266 computeMinweightsGUB(minweights, finished, unfinished, minweightslen);
4267 assert(minweights[0] == 0);
4268 }
4269 /* GF GUB: no update of unfinished table (and minweight table) required because GF GUBs have no C1 variables and
4270 * are therefore not in the unfinished table
4271 */
4272 else
4273 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4274
4275#ifndef NDEBUG
4276 nliftgubC1 = k;
4277#endif
4278 nliftgubvars = k;
4279 sumliftcoef = 0;
4280
4281 /* compute lifting coefficient of F and R variables in GNC1 and GF GUBs (C1 vars have already liftcoef 1) */
4282 for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4283 {
4284 if( gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_F
4285 || gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4286 {
4287 liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4288 weight = weights[liftvar];
4289 assert(weight > 0);
4290 assert(liftvar >= 0 && liftvar < nvars);
4291 assert(capacity - weight >= 0);
4292
4293 /* put variable into array of variables in GUB that are considered for the lifting,
4294 * i.e., not capacity exceeding
4295 */
4296 liftgubvars[nliftgubvars] = liftvar;
4297 nliftgubvars++;
4298
4299 /* knapsack problem is infeasible:
4300 * sets z = 0
4301 */
4302 if( capacity - fixedonesweight - weight < 0 )
4303 {
4304 z = 0;
4305 }
4306 /* knapsack problem is feasible:
4307 * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
4308 * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
4309 */
4310 else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
4311 {
4312 z = *liftrhs;
4313 }
4314 /* knapsack problem is feasible:
4315 * binary search to find z = max {w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i}}
4316 */
4317 else
4318 {
4319 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
4320 left = 0;
4321 right = (*liftrhs) + 1;
4322 while( left < right - 1 )
4323 {
4324 middle = (left + right) / 2;
4325 assert(0 <= middle && middle < minweightslen);
4326 if( minweights[middle] <= capacity - fixedonesweight - weight )
4327 left = middle;
4328 else
4329 right = middle;
4330 }
4331 assert(left == right - 1);
4332 assert(0 <= left && left < minweightslen);
4333 assert(minweights[left] <= capacity - fixedonesweight - weight);
4334 assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
4335
4336 /* now z = left */
4337 z = left;
4338 assert(z <= *liftrhs);
4339 }
4340
4341 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4342 liftcoef = (*liftrhs) - z;
4343 liftcoefs[liftvar] = liftcoef;
4344 assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4345
4346 /* updates activity of current valid inequality */
4347 (*cutact) += liftcoef * solvals[liftvar];
4348
4349 /* updates sum of all lifting coefficients in GUB */
4350 sumliftcoef += liftcoefs[liftvar];
4351 }
4352 else
4353 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4354 }
4355 /* at least one variable is in F or R (j = number of C1 variables in current GUB) */
4356 assert(nliftgubvars > nliftgubC1);
4357
4358 /* activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0
4359 * and finished and minweight table can be updated easily as only C1 variables need to be considered;
4360 * not needed for GF GUBs
4361 */
4362 if( sumliftcoef == 0 )
4363 {
4364 if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4365 {
4366 weight = weights[liftgubvars[0]];
4367 /* update finished table and minweights table by applying special case of
4368 * finished[w] = MIN{finished[w], finished[w-1] + weight}, "weight" is the minimal weight of current GUB
4369 * minweights[w] = MIN{minweights[w], minweights[w-1] + weight}, "weight" is the minimal weight of current GUB
4370 */
4371 for( w = minweightslen-1; w >= 1; w-- )
4372 {
4373 SCIP_Longint tmpval;
4374
4375 tmpval = safeAddMinweightsGUB(finished[w-1], weight);
4376 finished[w] = MIN(finished[w], tmpval);
4377
4378 tmpval = safeAddMinweightsGUB(minweights[w-1], weight);
4379 minweights[w] = MIN(minweights[w], tmpval);
4380 }
4381 }
4382 else
4383 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4384
4385 continue;
4386 }
4387
4388 /* enlarges current minweights tables(finished, unfinished, minweights):
4389 * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4390 * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4391 * and sets minweights_i[w] = infinity for
4392 * 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
4393 */
4394 tmplen = minweightslen; /* will be updated in enlargeMinweights() */
4395 tmpsize = minweightssize;
4396 SCIP_CALL( enlargeMinweights(scip, &unfinished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4397 tmplen = minweightslen;
4398 tmpsize = minweightssize;
4399 SCIP_CALL( enlargeMinweights(scip, &finished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4400 SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + sumliftcoef) );
4401
4402 /* update finished table and minweight table;
4403 * note that instead of computing minweight table from updated finished and updated unfinished table again
4404 * (for the lifting coefficient, we had to update unfinished table and compute minweight table), we here
4405 * only need to update the minweight table and the updated finished in the same way (i.e., computing for minweight
4406 * not needed because only finished table changed at this point and the change was "adding" one weight)
4407 *
4408 * update formular for minweight table is: minweight_i+1[w] =
4409 * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4410 * formular for finished table has the same pattern.
4411 */
4412 for( w = minweightslen-1; w >= 0; w-- )
4413 {
4414 SCIP_Longint minminweight;
4415 SCIP_Longint minfinished;
4416
4417 for( k = 0; k < nliftgubvars; k++ )
4418 {
4419 liftcoef = liftcoefs[liftgubvars[k]];
4420 weight = weights[liftgubvars[k]];
4421
4422 if( w < liftcoef )
4423 {
4424 minfinished = MIN(finished[w], weight);
4425 minminweight = MIN(minweights[w], weight);
4426
4427 finished[w] = minfinished;
4428 minweights[w] = minminweight;
4429 }
4430 else
4431 {
4432 SCIP_Longint tmpval;
4433
4434 assert(w >= liftcoef);
4435
4436 tmpval = safeAddMinweightsGUB(finished[w-liftcoef], weight);
4437 minfinished = MIN(finished[w], tmpval);
4438
4439 tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4440 minminweight = MIN(minweights[w], tmpval);
4441
4442 finished[w] = minfinished;
4443 minweights[w] = minminweight;
4444 }
4445 }
4446 }
4447 assert(minweights[0] == 0);
4448 }
4449 assert(ngubconsGNC1 == 0);
4450
4451 /* note: now the unfinished table no longer exists, i.e., it is "0, MAX, MAX, ..." and minweight equals to finished;
4452 * therefore, only work with minweight table from here on
4453 */
4454
4455 /* sequentially down-lifts C2 variables contained in trivial GC2 GUBs */
4456 for( j = 0; j < ngubconsGC2; j++ )
4457 {
4458 liftgubconsidx = gubconsGC2[j];
4459
4460 assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4461 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GC2);
4462 assert(gubset->gubconss[liftgubconsidx]->ngubvars == 1);
4463 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4464
4465 liftvar = gubset->gubconss[liftgubconsidx]->gubvars[0]; /* C2 GUBs contain only one variable */
4466 weight = weights[liftvar];
4467
4468 assert(liftvar >= 0 && liftvar < nvars);
4469 assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
4470 assert(weight > 0);
4471
4472 /* uses binary search to find
4473 * z = max { w : 0 <= w <= |C_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
4474 */
4475 left = 0;
4476 right = minweightslen;
4477 while( left < right - 1 )
4478 {
4479 middle = (left + right) / 2;
4480 assert(0 <= middle && middle < minweightslen);
4481 if( minweights[middle] <= capacity - fixedonesweight + weight )
4482 left = middle;
4483 else
4484 right = middle;
4485 }
4486 assert(left == right - 1);
4487 assert(0 <= left && left < minweightslen);
4488 assert(minweights[left] <= capacity - fixedonesweight + weight);
4489 assert(left == minweightslen - 1 || minweights[left + 1] > capacity - fixedonesweight + weight);
4490
4491 /* now z = left */
4492 z = left;
4493 assert(z >= *liftrhs);
4494
4495 /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
4496 liftcoef = z - (*liftrhs);
4497 liftcoefs[liftvar] = liftcoef;
4498 assert(liftcoef >= 0);
4499
4500 /* updates sum of weights of variables fixed to one */
4501 fixedonesweight -= weight;
4502
4503 /* updates right-hand side of current valid inequality */
4504 (*liftrhs) += liftcoef;
4505 assert(*liftrhs >= alpha0);
4506
4507 /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
4508 if( liftcoef == 0 )
4509 continue;
4510
4511 /* updates activity of current valid inequality */
4512 (*cutact) += liftcoef * solvals[liftvar];
4513
4514 /* enlarges current minweight table:
4515 * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4516 * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4517 * and sets minweights_i[w] = infinity for
4518 * 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
4519 */
4520 SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
4521
4522 /* updates minweight table: minweight_i+1[w] =
4523 * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
4524 * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
4525 */
4526 for( w = minweightslen - 1; w >= 0; w-- )
4527 {
4528 if( w < liftcoef )
4529 {
4530 min = MIN(minweights[w], weight);
4531 minweights[w] = min;
4532 }
4533 else
4534 {
4535 SCIP_Longint tmpval;
4536
4537 assert(w >= liftcoef);
4538
4539 tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4540 min = MIN(minweights[w], tmpval);
4541 minweights[w] = min;
4542 }
4543 }
4544 }
4545 assert(fixedonesweight == 0);
4546 assert(*liftrhs >= alpha0);
4547
4548 /* sequentially up-lifts variables in GUB constraints in GR GUBs */
4549 for( j = 0; j < ngubconsGR; j++ )
4550 {
4551 liftgubconsidx = gubconsGR[j];
4552
4553 assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4554 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR);
4555
4556 sumliftcoef = 0;
4557 nliftgubvars = 0;
4558 for( k = 0; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4559 {
4560 if(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4561 {
4562 liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4563 weight = weights[liftvar];
4564 assert(weight > 0);
4565 assert(liftvar >= 0 && liftvar < nvars);
4566 assert(capacity - weight >= 0);
4567 assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
4568
4569 /* put variable into array of variables in GUB that are considered for the lifting,
4570 * i.e., not capacity exceeding
4571 */
4572 liftgubvars[nliftgubvars] = liftvar;
4573 nliftgubvars++;
4574
4575 /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
4576 * if minweights_i[liftrhs] <= a_0 - a_{j_i}
4577 */
4578 if( minweights[*liftrhs] <= capacity - weight )
4579 {
4580 z = *liftrhs;
4581 }
4582 /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
4583 */
4584 else
4585 {
4586 left = 0;
4587 right = (*liftrhs) + 1;
4588 while( left < right - 1 )
4589 {
4590 middle = (left + right) / 2;
4591 assert(0 <= middle && middle < minweightslen);
4592 if( minweights[middle] <= capacity - weight )
4593 left = middle;
4594 else
4595 right = middle;
4596 }
4597 assert(left == right - 1);
4598 assert(0 <= left && left < minweightslen);
4599 assert(minweights[left] <= capacity - weight);
4600 assert(left == minweightslen - 1 || minweights[left + 1] > capacity - weight);
4601
4602 /* now z = left */
4603 z = left;
4604 assert(z <= *liftrhs);
4605 }
4606 /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4607 liftcoef = (*liftrhs) - z;
4608 liftcoefs[liftvar] = liftcoef;
4609 assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4610
4611 /* updates activity of current valid inequality */
4612 (*cutact) += liftcoef * solvals[liftvar];
4613
4614 /* updates sum of all lifting coefficients in GUB */
4615 sumliftcoef += liftcoefs[liftvar];
4616 }
4617 else
4618 assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4619 }
4620 assert(nliftgubvars >= 1); /* at least one variable is in R */
4621
4622 /* minweight table and activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0 */
4623 if( sumliftcoef == 0 )
4624 continue;
4625
4626 /* updates minweight table: minweight_i+1[w] =
4627 * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4628 */
4629 for( w = *liftrhs; w >= 0; w-- )
4630 {
4631 for( k = 0; k < nliftgubvars; k++ )
4632 {
4633 liftcoef = liftcoefs[liftgubvars[k]];
4634 weight = weights[liftgubvars[k]];
4635
4636 if( w < liftcoef )
4637 {
4638 min = MIN(minweights[w], weight);
4639 minweights[w] = min;
4640 }
4641 else
4642 {
4643 SCIP_Longint tmpval;
4644
4645 assert(w >= liftcoef);
4646
4647 tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4648 min = MIN(minweights[w], tmpval);
4649 minweights[w] = min;
4650 }
4651 }
4652 }
4653 assert(minweights[0] == 0);
4654 }
4655
4656 /* frees temporary memory */
4657 SCIPfreeBufferArray(scip, &minweights);
4658 SCIPfreeBufferArray(scip, &finished);
4659 SCIPfreeBufferArray(scip, &unfinished);
4660 SCIPfreeBufferArray(scip, &liftgubvars);
4661 SCIPfreeBufferArray(scip, &gubconsGOC1 );
4662 SCIPfreeBufferArray(scip, &gubconsGNC1);
4663
4664 return SCIP_OKAY;
4665}
4666
4667/** lifts given minimal cover inequality
4668 * \f[
4669 * \sum_{j \in C} x_j \leq |C| - 1
4670 * \f]
4671 * valid for
4672 * \f[
4673 * S^0 = \{ x \in {0,1}^{|C|} : \sum_{j \in C} a_j x_j \leq a_0 \}
4674 * \f]
4675 * to a valid inequality
4676 * \f[
4677 * \sum_{j \in C} x_j + \sum_{j \in N \setminus C} \alpha_j x_j \leq |C| - 1
4678 * \f]
4679 * for
4680 * \f[
4681 * S = \{ x \in {0,1}^{|N|} : \sum_{j \in N} a_j x_j \leq a_0 \};
4682 * \f]
4683 * uses superadditive up-lifting for the variables in \f$N \setminus C\f$.
4684 */
4685static
4687 SCIP* scip, /**< SCIP data structure */
4688 SCIP_VAR** vars, /**< variables in knapsack constraint */
4689 int nvars, /**< number of variables in knapsack constraint */
4690 int ntightened, /**< number of variables with tightened upper bound */
4691 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4692 SCIP_Longint capacity, /**< capacity of knapsack */
4693 SCIP_Real* solvals, /**< solution values of all problem variables */
4694 int* covervars, /**< cover variables */
4695 int* noncovervars, /**< noncover variables */
4696 int ncovervars, /**< number of cover variables */
4697 int nnoncovervars, /**< number of noncover variables */
4698 SCIP_Longint coverweight, /**< weight of cover */
4699 SCIP_Real* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
4700 SCIP_Real* cutact /**< pointer to store activity of lifted valid inequality */
4701 )
4702{
4703 SCIP_Longint* maxweightsums;
4704 SCIP_Longint* intervalends;
4705 SCIP_Longint* rhos;
4706 SCIP_Real* sortkeys;
4707 SCIP_Longint lambda;
4708 int j;
4709 int h;
4710
4711 assert(scip != NULL);
4712 assert(vars != NULL);
4713 assert(nvars >= 0);
4714 assert(weights != NULL);
4715 assert(capacity >= 0);
4716 assert(solvals != NULL);
4717 assert(covervars != NULL);
4718 assert(noncovervars != NULL);
4719 assert(ncovervars > 0 && ncovervars <= nvars);
4720 assert(nnoncovervars >= 0 && nnoncovervars <= nvars - ntightened);
4721 assert(ncovervars + nnoncovervars == nvars - ntightened);
4722 assert(liftcoefs != NULL);
4723 assert(cutact != NULL);
4724
4725 /* allocates temporary memory */
4726 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, ncovervars) );
4727 SCIP_CALL( SCIPallocBufferArray(scip, &maxweightsums, ncovervars + 1) );
4728 SCIP_CALL( SCIPallocBufferArray(scip, &intervalends, ncovervars) );
4729 SCIP_CALL( SCIPallocBufferArray(scip, &rhos, ncovervars) );
4730
4731 /* initializes data structures */
4732 BMSclearMemoryArray(liftcoefs, nvars);
4733 *cutact = 0.0;
4734
4735 /* sets lifting coefficient of variables in C, sorts variables in C such that a_1 >= a_2 >= ... >= a_|C|
4736 * and calculates activity of current valid inequality
4737 */
4738 for( j = 0; j < ncovervars; j++ )
4739 {
4740 assert(liftcoefs[covervars[j]] == 0.0);
4741 liftcoefs[covervars[j]] = 1.0;
4742 sortkeys[j] = (SCIP_Real) weights[covervars[j]];
4743 (*cutact) += solvals[covervars[j]];
4744 }
4745 SCIPsortDownRealInt(sortkeys, covervars, ncovervars);
4746
4747 /* calculates weight excess of cover C */
4748 lambda = coverweight - capacity;
4749 assert(lambda > 0);
4750
4751 /* calculates A_h for h = 0,...,|C|, I_h for h = 1,...,|C| and rho_h for h = 1,...,|C| */
4752 maxweightsums[0] = 0;
4753 for( h = 1; h <= ncovervars; h++ )
4754 {
4755 maxweightsums[h] = maxweightsums[h-1] + weights[covervars[h-1]];
4756 intervalends[h-1] = maxweightsums[h] - lambda;
4757 rhos[h-1] = MAX(0, weights[covervars[h-1]] - weights[covervars[0]] + lambda);
4758 }
4759
4760 /* sorts variables in N\C such that a_{j_1} <= a_{j_2} <= ... <= a_{j_t} */
4761 for( j = 0; j < nnoncovervars; j++ )
4762 sortkeys[j] = (SCIP_Real) (weights[noncovervars[j]]);
4763 SCIPsortRealInt(sortkeys, noncovervars, nnoncovervars);
4764
4765 /* calculates lifting coefficient for all variables in N\C */
4766 h = 0;
4767 for( j = 0; j < nnoncovervars; j++ )
4768 {
4769 int liftvar;
4770 SCIP_Longint weight;
4771 SCIP_Real liftcoef;
4772
4773 liftvar = noncovervars[j];
4774 weight = weights[liftvar];
4775
4776 while( intervalends[h] < weight )
4777 h++;
4778
4779 if( h == 0 )
4780 liftcoef = h;
4781 else
4782 {
4783 if( weight <= intervalends[h-1] + rhos[h] )
4784 {
4785 SCIP_Real tmp1;
4786 SCIP_Real tmp2;
4787 tmp1 = (SCIP_Real) (intervalends[h-1] + rhos[h] - weight);
4788 tmp2 = (SCIP_Real) rhos[1];
4789 liftcoef = h - ( tmp1 / tmp2 );
4790 }
4791 else
4792 liftcoef = h;
4793 }
4794
4795 /* sets lifting coefficient */
4796 assert(liftcoefs[liftvar] == 0.0);
4797 liftcoefs[liftvar] = liftcoef;
4798
4799 /* updates activity of current valid inequality */
4800 (*cutact) += liftcoef * solvals[liftvar];
4801 }
4802
4803 /* frees temporary memory */
4804 SCIPfreeBufferArray(scip, &rhos);
4805 SCIPfreeBufferArray(scip, &intervalends);
4806 SCIPfreeBufferArray(scip, &maxweightsums);
4807 SCIPfreeBufferArray(scip, &sortkeys);
4808
4809 return SCIP_OKAY;
4810}
4811
4812
4813/** separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information, if wanted, for
4814 * given knapsack problem
4815*/
4816static
4818 SCIP* scip, /**< SCIP data structure */
4819 SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
4820 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
4821 SCIP_VAR** vars, /**< variables in knapsack constraint */
4822 int nvars, /**< number of variables in knapsack constraint */
4823 int ntightened, /**< number of variables with tightened upper bound */
4824 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4825 SCIP_Longint capacity, /**< capacity of knapsack */
4826 SCIP_Real* solvals, /**< solution values of all problem variables */
4827 int* mincovervars, /**< mincover variables */
4828 int* nonmincovervars, /**< nonmincover variables */
4829 int nmincovervars, /**< number of mincover variables */
4830 int nnonmincovervars, /**< number of nonmincover variables */
4831 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
4832 SCIP_GUBSET* gubset, /**< GUB set data structure, NULL if no GUB information should be used */
4833 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
4834 int* ncuts /**< pointer to add up the number of found cuts */
4835 )
4836{
4837 int* varsC1;
4838 int* varsC2;
4839 int* varsF;
4840 int* varsR;
4841 int nvarsC1;
4842 int nvarsC2;
4843 int nvarsF;
4844 int nvarsR;
4845 SCIP_Real cutact;
4846 int* liftcoefs;
4847 int liftrhs;
4848
4849 assert( cutoff != NULL );
4850 *cutoff = FALSE;
4851
4852 /* allocates temporary memory */
4857 SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
4858
4859 /* 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
4860 * as follows
4861 * C_2 = { j in C : x*_j = 1 } and
4862 * C_1 = C\C_2
4863 */
4864 getPartitionCovervars(scip, solvals, mincovervars, nmincovervars, varsC1, varsC2, &nvarsC1, &nvarsC2);
4865 assert(nvarsC1 + nvarsC2 == nmincovervars);
4866 assert(nmincovervars > 0);
4867 assert(nvarsC1 >= 0); /* nvarsC1 > 0 does not always hold, because relaxed knapsack conss may already be violated */
4868
4869 /* changes partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one variable from C2 to C1 */
4870 if( nvarsC1 < 2 && nvarsC2 > 0)
4871 {
4872 SCIP_CALL( changePartitionCovervars(scip, weights, varsC1, varsC2, &nvarsC1, &nvarsC2) );
4873 assert(nvarsC1 >= 1);
4874 }
4875 assert(nvarsC2 == 0 || nvarsC1 >= 1);
4876
4877 /* gets partition (F,R) of N\C, i.e. F & R = N\C and F cap R = emptyset; chooses partition as follows
4878 * R = { j in N\C : x*_j = 0 } and
4879 * F = (N\C)\F
4880 */
4881 getPartitionNoncovervars(scip, solvals, nonmincovervars, nnonmincovervars, varsF, varsR, &nvarsF, &nvarsR);
4882 assert(nvarsF + nvarsR == nnonmincovervars);
4883 assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4884
4885 /* lift cuts without GUB information */
4886 if( gubset == NULL )
4887 {
4888 /* sorts variables in F, C_2, R according to the second level lifting sequence that will be used in the sequential
4889 * lifting procedure
4890 */
4891 SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsC2, varsR, nvarsF, nvarsC2, nvarsR) );
4892
4893 /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4894 *
4895 * 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 }
4896 *
4897 * 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
4898 *
4899 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
4900 *
4901 * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in C_2 and sequential
4902 * up-lifting for the variables in R according to the second level lifting sequence
4903 */
4904 SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsC1, varsC2,
4905 varsF, varsR, nvarsC1, nvarsC2, nvarsF, nvarsR, nvarsC1 - 1, liftcoefs, &cutact, &liftrhs) );
4906 }
4907 /* lift cuts with GUB information */
4908 else
4909 {
4910 int* gubconsGC1;
4911 int* gubconsGC2;
4912 int* gubconsGFC1;
4913 int* gubconsGR;
4914 int ngubconsGC1;
4915 int ngubconsGC2;
4916 int ngubconsGFC1;
4917 int ngubconsGR;
4918 int ngubconss;
4919 int nconstightened;
4920 int maxgubvarssize;
4921
4922 assert(nvars == gubset->nvars);
4923
4924 ngubconsGC1 = 0;
4925 ngubconsGC2 = 0;
4926 ngubconsGFC1 = 0;
4927 ngubconsGR = 0;
4928 ngubconss = gubset->ngubconss;
4929 nconstightened = 0;
4930 maxgubvarssize = 0;
4931
4932 /* allocates temporary memory */
4933 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC1, ngubconss) );
4934 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC2, ngubconss) );
4935 SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGFC1, ngubconss) );
4937
4938 /* categorizies GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of
4939 * the GUBs for the sequential GUB wise lifting procedure
4940 */
4941 SCIP_CALL( getLiftingSequenceGUB(scip, gubset, solvals, weights, varsC1, varsC2, varsF, varsR, nvarsC1,
4942 nvarsC2, nvarsF, nvarsR, gubconsGC1, gubconsGC2, gubconsGFC1, gubconsGR, &ngubconsGC1, &ngubconsGC2,
4943 &ngubconsGFC1, &ngubconsGR, &nconstightened, &maxgubvarssize) );
4944
4945 /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4946 *
4947 * 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,
4948 * sum_{j in Q_i} x_j <= 1, forall i in I }
4949 *
4950 * 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
4951 *
4952 * 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 },
4953 *
4954 * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
4955 * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
4956 * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
4957 */
4958 SCIP_CALL( sequentialUpAndDownLiftingGUB(scip, gubset, vars, nconstightened, weights, capacity, solvals, gubconsGC1,
4959 gubconsGC2, gubconsGFC1, gubconsGR, ngubconsGC1, ngubconsGC2, ngubconsGFC1, ngubconsGR,
4960 MIN(nvarsC1 - 1, ngubconsGC1), liftcoefs, &cutact, &liftrhs, maxgubvarssize) );
4961
4962 /* frees temporary memory */
4963 SCIPfreeBufferArray(scip, &gubconsGR);
4964 SCIPfreeBufferArray(scip, &gubconsGFC1);
4965 SCIPfreeBufferArray(scip, &gubconsGC2);
4966 SCIPfreeBufferArray(scip, &gubconsGC1);
4967 }
4968
4969 /* checks if lifting yielded a violated cut */
4970 if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
4971 {
4972 SCIP_ROW* row;
4973 char name[SCIP_MAXSTRLEN];
4974 int j;
4975
4976 /* creates LP row */
4977 assert( cons == NULL || sepa == NULL );
4978 if ( cons != NULL )
4979 {
4981 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
4982 cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
4983 cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
4984 }
4985 else if ( sepa != NULL )
4986 {
4987 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
4988 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4989 }
4990 else
4991 {
4992 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcseq_%d", *ncuts);
4994 }
4995
4996 /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
4998 assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4999 for( j = 0; j < nvarsC1; j++ )
5000 {
5001 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC1[j]], 1.0) );
5002 }
5003 for( j = 0; j < nvarsC2; j++ )
5004 {
5005 if( liftcoefs[varsC2[j]] > 0 )
5006 {
5007 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC2[j]], (SCIP_Real)liftcoefs[varsC2[j]]) );
5008 }
5009 }
5010 for( j = 0; j < nvarsF; j++ )
5011 {
5012 if( liftcoefs[varsF[j]] > 0 )
5013 {
5014 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
5015 }
5016 }
5017 for( j = 0; j < nvarsR; j++ )
5018 {
5019 if( liftcoefs[varsR[j]] > 0 )
5020 {
5021 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
5022 }
5023 }
5025
5026 /* checks if cut is violated enough */
5027 if( SCIPisCutEfficacious(scip, sol, row) )
5028 {
5029 if( cons != NULL )
5030 {
5032 }
5034 (*ncuts)++;
5035 }
5036 SCIP_CALL( SCIPreleaseRow(scip, &row) );
5037 }
5038
5039 /* frees temporary memory */
5040 SCIPfreeBufferArray(scip, &liftcoefs);
5041 SCIPfreeBufferArray(scip, &varsR);
5042 SCIPfreeBufferArray(scip, &varsF);
5043 SCIPfreeBufferArray(scip, &varsC2);
5044 SCIPfreeBufferArray(scip, &varsC1);
5045
5046 return SCIP_OKAY;
5047}
5048
5049/** separates lifted extended weight inequalities using sequential up- and down-lifting for given knapsack problem */
5050static
5052 SCIP* scip, /**< SCIP data structure */
5053 SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5054 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5055 SCIP_VAR** vars, /**< variables in knapsack constraint */
5056 int nvars, /**< number of variables in knapsack constraint */
5057 int ntightened, /**< number of variables with tightened upper bound */
5058 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5059 SCIP_Longint capacity, /**< capacity of knapsack */
5060 SCIP_Real* solvals, /**< solution values of all problem variables */
5061 int* feassetvars, /**< variables in feasible set */
5062 int* nonfeassetvars, /**< variables not in feasible set */
5063 int nfeassetvars, /**< number of variables in feasible set */
5064 int nnonfeassetvars, /**< number of variables not in feasible set */
5065 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5066 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5067 int* ncuts /**< pointer to add up the number of found cuts */
5068 )
5069{
5070 int* varsT1;
5071 int* varsT2;
5072 int* varsF;
5073 int* varsR;
5074 int* liftcoefs;
5075 SCIP_Real cutact;
5076 int nvarsT1;
5077 int nvarsT2;
5078 int nvarsF;
5079 int nvarsR;
5080 int liftrhs;
5081 int j;
5082
5083 assert( cutoff != NULL );
5084 *cutoff = FALSE;
5085
5086 /* allocates temporary memory */
5091 SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
5092
5093 /* 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
5094 * as follows
5095 * T_2 = { j in T : x*_j = 1 } and
5096 * T_1 = T\T_2
5097 */
5098 getPartitionCovervars(scip, solvals, feassetvars, nfeassetvars, varsT1, varsT2, &nvarsT1, &nvarsT2);
5099 assert(nvarsT1 + nvarsT2 == nfeassetvars);
5100
5101 /* changes partition (T_1,T_2) of feasible set T, if |T1| = 0, by moving one variable from T2 to T1 */
5102 if( nvarsT1 == 0 && nvarsT2 > 0)
5103 {
5104 SCIP_CALL( changePartitionFeasiblesetvars(scip, weights, varsT1, varsT2, &nvarsT1, &nvarsT2) );
5105 assert(nvarsT1 == 1);
5106 }
5107 assert(nvarsT2 == 0 || nvarsT1 > 0);
5108
5109 /* gets partition (F,R) of N\T, i.e. F & R = N\T and F cap R = emptyset; chooses partition as follows
5110 * R = { j in N\T : x*_j = 0 } and
5111 * F = (N\T)\F
5112 */
5113 getPartitionNoncovervars(scip, solvals, nonfeassetvars, nnonfeassetvars, varsF, varsR, &nvarsF, &nvarsR);
5114 assert(nvarsF + nvarsR == nnonfeassetvars);
5115 assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5116
5117 /* sorts variables in F, T_2, and R according to the second level lifting sequence that will be used in the sequential
5118 * lifting procedure (the variable removed last from the initial cover does not have to be lifted first, therefore it
5119 * is included in the sorting routine)
5120 */
5121 SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsT2, varsR, nvarsF, nvarsT2, nvarsR) );
5122
5123 /* lifts extended weight inequality sum_{j in T_1} x_j <= |T_1| valid for
5124 *
5125 * 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 }
5126 *
5127 * 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
5128 *
5129 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5130 *
5131 * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in T_2 and sequential
5132 * up-lifting for the variabels in R according to the second level lifting sequence
5133 */
5134 SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsT1, varsT2, varsF, varsR,
5135 nvarsT1, nvarsT2, nvarsF, nvarsR, nvarsT1, liftcoefs, &cutact, &liftrhs) );
5136
5137 /* checks if lifting yielded a violated cut */
5138 if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5139 {
5140 SCIP_ROW* row;
5141 char name[SCIP_MAXSTRLEN];
5142
5143 /* creates LP row */
5144 assert( cons == NULL || sepa == NULL );
5145 if( cons != NULL )
5146 {
5149 cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5150 cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5151 }
5152 else if ( sepa != NULL )
5153 {
5154 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5155 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5156 }
5157 else
5158 {
5159 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_ewseq_%d", *ncuts);
5161 }
5162
5163 /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5165 assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5166 for( j = 0; j < nvarsT1; j++ )
5167 {
5168 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT1[j]], 1.0) );
5169 }
5170 for( j = 0; j < nvarsT2; j++ )
5171 {
5172 if( liftcoefs[varsT2[j]] > 0 )
5173 {
5174 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT2[j]], (SCIP_Real)liftcoefs[varsT2[j]]) );
5175 }
5176 }
5177 for( j = 0; j < nvarsF; j++ )
5178 {
5179 if( liftcoefs[varsF[j]] > 0 )
5180 {
5181 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
5182 }
5183 }
5184 for( j = 0; j < nvarsR; j++ )
5185 {
5186 if( liftcoefs[varsR[j]] > 0 )
5187 {
5188 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
5189 }
5190 }
5192
5193 /* checks if cut is violated enough */
5194 if( SCIPisCutEfficacious(scip, sol, row) )
5195 {
5196 if( cons != NULL )
5197 {
5199 }
5201 (*ncuts)++;
5202 }
5203 SCIP_CALL( SCIPreleaseRow(scip, &row) );
5204 }
5205
5206 /* frees temporary memory */
5207 SCIPfreeBufferArray(scip, &liftcoefs);
5208 SCIPfreeBufferArray(scip, &varsR);
5209 SCIPfreeBufferArray(scip, &varsF);
5210 SCIPfreeBufferArray(scip, &varsT2);
5211 SCIPfreeBufferArray(scip, &varsT1);
5212
5213 return SCIP_OKAY;
5214}
5215
5216/** separates lifted minimal cover inequalities using superadditive up-lifting for given knapsack problem */
5217static
5219 SCIP* scip, /**< SCIP data structure */
5220 SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5221 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5222 SCIP_VAR** vars, /**< variables in knapsack constraint */
5223 int nvars, /**< number of variables in knapsack constraint */
5224 int ntightened, /**< number of variables with tightened upper bound */
5225 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5226 SCIP_Longint capacity, /**< capacity of knapsack */
5227 SCIP_Real* solvals, /**< solution values of all problem variables */
5228 int* mincovervars, /**< mincover variables */
5229 int* nonmincovervars, /**< nonmincover variables */
5230 int nmincovervars, /**< number of mincover variables */
5231 int nnonmincovervars, /**< number of nonmincover variables */
5232 SCIP_Longint mincoverweight, /**< weight of minimal cover */
5233 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5234 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5235 int* ncuts /**< pointer to add up the number of found cuts */
5236 )
5237{
5238 SCIP_Real* realliftcoefs;
5239 SCIP_Real cutact;
5240 int liftrhs;
5241
5242 assert( cutoff != NULL );
5243 *cutoff = FALSE;
5244 cutact = 0.0;
5245
5246 /* allocates temporary memory */
5247 SCIP_CALL( SCIPallocBufferArray(scip, &realliftcoefs, nvars) );
5248
5249 /* lifts minimal cover inequality sum_{j in C} x_j <= |C| - 1 valid for
5250 *
5251 * S^0 = { x in {0,1}^|C| : sum_{j in C} a_j x_j <= a_0 }
5252 *
5253 * to a valid inequality sum_{j in C} x_j + sum_{j in N\C} alpha_j x_j <= |C| - 1 for
5254 *
5255 * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5256 *
5257 * uses superadditive up-lifting for the variables in N\C.
5258 */
5259 SCIP_CALL( superadditiveUpLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, mincovervars,
5260 nonmincovervars, nmincovervars, nnonmincovervars, mincoverweight, realliftcoefs, &cutact) );
5261 liftrhs = nmincovervars - 1;
5262
5263 /* checks if lifting yielded a violated cut */
5264 if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5265 {
5266 SCIP_ROW* row;
5267 char name[SCIP_MAXSTRLEN];
5268 int j;
5269
5270 /* creates LP row */
5271 assert( cons == NULL || sepa == NULL );
5272 if ( cons != NULL )
5273 {
5276 cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5277 cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5278 }
5279 else if ( sepa != NULL )
5280 {
5281 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5282 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5283 }
5284 else
5285 {
5286 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcsup_%d", *ncuts);
5288 }
5289
5290 /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5292 assert(nmincovervars + nnonmincovervars == nvars - ntightened);
5293 for( j = 0; j < nmincovervars; j++ )
5294 {
5295 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[mincovervars[j]], 1.0) );
5296 }
5297 for( j = 0; j < nnonmincovervars; j++ )
5298 {
5299 assert(SCIPisFeasGE(scip, realliftcoefs[nonmincovervars[j]], 0.0));
5300 if( SCIPisFeasGT(scip, realliftcoefs[nonmincovervars[j]], 0.0) )
5301 {
5302 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[nonmincovervars[j]], realliftcoefs[nonmincovervars[j]]) );
5303 }
5304 }
5306
5307 /* checks if cut is violated enough */
5308 if( SCIPisCutEfficacious(scip, sol, row) )
5309 {
5310 if( cons != NULL )
5311 {
5313 }
5315 (*ncuts)++;
5316 }
5317 SCIP_CALL( SCIPreleaseRow(scip, &row) );
5318 }
5319
5320 /* frees temporary memory */
5321 SCIPfreeBufferArray(scip, &realliftcoefs);
5322
5323 return SCIP_OKAY;
5324}
5325
5326/** converts given cover C to a minimal cover by removing variables in the reverse order in which the variables were chosen
5327 * 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
5328 * C and in the order of non-increasing (1 - x*_j), if the modified transformed separation problem was used to find C;
5329 * note that all variables with x*_j = 1 will be removed last
5330 */
5331static
5333 SCIP* scip, /**< SCIP data structure */
5334 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5335 SCIP_Longint capacity, /**< capacity of knapsack */
5336 SCIP_Real* solvals, /**< solution values of all problem variables */
5337 int* covervars, /**< pointer to store cover variables */
5338 int* noncovervars, /**< pointer to store noncover variables */
5339 int* ncovervars, /**< pointer to store number of cover variables */
5340 int* nnoncovervars, /**< pointer to store number of noncover variables */
5341 SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5342 SCIP_Bool modtransused /**< TRUE if mod trans sepa prob was used to find cover */
5343 )
5344{
5345 SORTKEYPAIR** sortkeypairs;
5346 SORTKEYPAIR** sortkeypairssorted;
5347 SCIP_Longint minweight;
5348 int nsortkeypairs;
5349 int minweightidx;
5350 int j;
5351 int k;
5352
5353 assert(scip != NULL);
5354 assert(covervars != NULL);
5355 assert(noncovervars != NULL);
5356 assert(ncovervars != NULL);
5357 assert(*ncovervars > 0);
5358 assert(nnoncovervars != NULL);
5359 assert(*nnoncovervars >= 0);
5360 assert(coverweight != NULL);
5361 assert(*coverweight > 0);
5362 assert(*coverweight > capacity);
5363
5364 /* allocates temporary memory; we need two arrays for the keypairs in order to be able to free them in the correct
5365 * order */
5366 nsortkeypairs = *ncovervars;
5367 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairs, nsortkeypairs) );
5368 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairssorted, nsortkeypairs) );
5369
5370 /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5371 * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5372 * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5373 * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5374 */
5375 assert(*ncovervars == nsortkeypairs);
5376 if( modtransused )
5377 {
5378 for( j = 0; j < *ncovervars; j++ )
5379 {
5380 SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5381 sortkeypairssorted[j] = sortkeypairs[j];
5382
5383 sortkeypairs[j]->key1 = solvals[covervars[j]];
5384 sortkeypairs[j]->key2 = (SCIP_Real) weights[covervars[j]];
5385 }
5386 }
5387 else
5388 {
5389 for( j = 0; j < *ncovervars; j++ )
5390 {
5391 SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5392 sortkeypairssorted[j] = sortkeypairs[j];
5393
5394 sortkeypairs[j]->key1 = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5395 sortkeypairs[j]->key2 = (SCIP_Real) (-weights[covervars[j]]);
5396 }
5397 }
5398 SCIPsortPtrInt((void**)sortkeypairssorted, covervars, compSortkeypairs, *ncovervars);
5399
5400 /* gets j' with a_j' = min{ a_j : j in C } */
5401 minweightidx = 0;
5402 minweight = weights[covervars[minweightidx]];
5403 for( j = 1; j < *ncovervars; j++ )
5404 {
5405 if( weights[covervars[j]] <= minweight )
5406 {
5407 minweightidx = j;
5408 minweight = weights[covervars[minweightidx]];
5409 }
5410 }
5411 assert(minweightidx >= 0 && minweightidx < *ncovervars);
5412 assert(minweight > 0 && minweight <= *coverweight);
5413
5414 j = 0;
5415 /* removes variables from C until the remaining variables form a minimal cover */
5416 while( j < *ncovervars && ((*coverweight) - minweight > capacity) )
5417 {
5418 assert(minweightidx >= j);
5419 assert(checkMinweightidx(weights, capacity, covervars, *ncovervars, *coverweight, minweightidx, j));
5420
5421 /* if sum_{i in C} a_i - a_j <= a_0, j cannot be removed from C */
5422 if( (*coverweight) - weights[covervars[j]] <= capacity )
5423 {
5424 ++j;
5425 continue;
5426 }
5427
5428 /* adds j to N\C */
5429 noncovervars[*nnoncovervars] = covervars[j];
5430 (*nnoncovervars)++;
5431
5432 /* removes j from C */
5433 (*coverweight) -= weights[covervars[j]];
5434 for( k = j; k < (*ncovervars) - 1; k++ )
5435 covervars[k] = covervars[k+1];
5436 (*ncovervars)--;
5437
5438 /* updates j' with a_j' = min{ a_j : j in C } */
5439 if( j == minweightidx )
5440 {
5441 minweightidx = 0;
5442 minweight = weights[covervars[minweightidx]];
5443 for( k = 1; k < *ncovervars; k++ )
5444 {
5445 if( weights[covervars[k]] <= minweight )
5446 {
5447 minweightidx = k;
5448 minweight = weights[covervars[minweightidx]];
5449 }
5450 }
5451 assert(minweight > 0 && minweight <= *coverweight);
5452 assert(minweightidx >= 0 && minweightidx < *ncovervars);
5453 }
5454 else
5455 {
5456 assert(minweightidx > j);
5457 minweightidx--;
5458 }
5459 /* j needs to stay the same */
5460 }
5461 assert((*coverweight) > capacity);
5462 assert((*coverweight) - minweight <= capacity);
5463
5464 /* frees temporary memory */
5465 for( j = nsortkeypairs-1; j >= 0; j-- )
5466 SCIPfreeBuffer(scip, &(sortkeypairs[j])); /*lint !e866 */
5467 SCIPfreeBufferArray(scip, &sortkeypairssorted);
5468 SCIPfreeBufferArray(scip, &sortkeypairs);
5469
5470 return SCIP_OKAY;
5471}
5472
5473/** converts given initial cover C_init to a feasible set by removing variables in the reverse order in which
5474 * they were chosen to be in C_init:
5475 * non-increasing (1 - x*_j)/a_j, if transformed separation problem was used to find C_init
5476 * non-increasing (1 - x*_j), if modified transformed separation problem was used to find C_init.
5477 * separates lifted extended weight inequalities using sequential up- and down-lifting for this feasible set
5478 * and all subsequent feasible sets.
5479 */
5480static
5482 SCIP* scip, /**< SCIP data structure */
5483 SCIP_CONS* cons, /**< constraint that originates the knapsack problem */
5484 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5485 SCIP_VAR** vars, /**< variables in knapsack constraint */
5486 int nvars, /**< number of variables in knapsack constraint */
5487 int ntightened, /**< number of variables with tightened upper bound */
5488 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5489 SCIP_Longint capacity, /**< capacity of knapsack */
5490 SCIP_Real* solvals, /**< solution values of all problem variables */
5491 int* covervars, /**< pointer to store cover variables */
5492 int* noncovervars, /**< pointer to store noncover variables */
5493 int* ncovervars, /**< pointer to store number of cover variables */
5494 int* nnoncovervars, /**< pointer to store number of noncover variables */
5495 SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5496 SCIP_Bool modtransused, /**< TRUE if mod trans sepa prob was used to find cover */
5497 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5498 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5499 int* ncuts /**< pointer to add up the number of found cuts */
5500 )
5501{
5502 SCIP_Real* sortkeys;
5503 int j;
5504 int k;
5505
5506 assert(scip != NULL);
5507 assert(covervars != NULL);
5508 assert(noncovervars != NULL);
5509 assert(ncovervars != NULL);
5510 assert(*ncovervars > 0);
5511 assert(nnoncovervars != NULL);
5512 assert(*nnoncovervars >= 0);
5513 assert(coverweight != NULL);
5514 assert(*coverweight > 0);
5515 assert(*coverweight > capacity);
5516 assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5517 assert(cutoff != NULL);
5518
5519 *cutoff = FALSE;
5520
5521 /* allocates temporary memory */
5522 SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, *ncovervars) );
5523
5524 /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5525 * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5526 * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5527 * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5528 */
5529 if( modtransused )
5530 {
5531 for( j = 0; j < *ncovervars; j++ )
5532 {
5533 sortkeys[j] = solvals[covervars[j]];
5534 assert(SCIPisFeasGE(scip, sortkeys[j], 0.0));
5535 }
5536 }
5537 else
5538 {
5539 for( j = 0; j < *ncovervars; j++ )
5540 {
5541 sortkeys[j] = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5542 assert(SCIPisFeasLE(scip, sortkeys[j], 0.0));
5543 }
5544 }
5545 SCIPsortRealInt(sortkeys, covervars, *ncovervars);
5546
5547 /* removes variables from C_init and separates lifted extended weight inequalities using sequential up- and down-lifting;
5548 * in addition to an extended weight inequality this gives cardinality inequalities */
5549 while( *ncovervars >= 2 )
5550 {
5551 /* adds first element of C_init to N\C_init */
5552 noncovervars[*nnoncovervars] = covervars[0];
5553 (*nnoncovervars)++;
5554
5555 /* removes first element from C_init */
5556 (*coverweight) -= weights[covervars[0]];
5557 for( k = 0; k < (*ncovervars) - 1; k++ )
5558 covervars[k] = covervars[k+1];
5559 (*ncovervars)--;
5560
5561 assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5562 if( (*coverweight) <= capacity )
5563 {
5564 SCIP_CALL( separateSequLiftedExtendedWeightInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals,
5565 covervars, noncovervars, *ncovervars, *nnoncovervars, sol, cutoff, ncuts) );
5566 }
5567
5568 /* stop if cover is too large */
5569 if ( *ncovervars >= MAXCOVERSIZEITERLEWI )
5570 break;
5571 }
5572
5573 /* frees temporary memory */
5574 SCIPfreeBufferArray(scip, &sortkeys);
5575
5576 return SCIP_OKAY;
5577}
5578
5579/** separates different classes of valid inequalities for the 0-1 knapsack problem */
5581 SCIP* scip, /**< SCIP data structure */
5582 SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5583 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5584 SCIP_VAR** vars, /**< variables in knapsack constraint */
5585 int nvars, /**< number of variables in knapsack constraint */
5586 SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5587 SCIP_Longint capacity, /**< capacity of knapsack */
5588 SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5589 SCIP_Bool usegubs, /**< should GUB information be used for separation? */
5590 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
5591 int* ncuts /**< pointer to add up the number of found cuts */
5592 )
5593{
5594 SCIP_Real* solvals;
5595 int* covervars;
5596 int* noncovervars;
5597 SCIP_Bool coverfound;
5598 SCIP_Bool fractional;
5599 SCIP_Bool modtransused;
5600 SCIP_Longint coverweight;
5601 int ncovervars;
5602 int nnoncovervars;
5603 int ntightened;
5604
5605 assert(scip != NULL);
5606 assert(capacity >= 0);
5607 assert(cutoff != NULL);
5608 assert(ncuts != NULL);
5609
5610 *cutoff = FALSE;
5611
5612 if( nvars == 0 )
5613 return SCIP_OKAY;
5614
5615 assert(vars != NULL);
5616 assert(nvars > 0);
5617 assert(weights != NULL);
5618
5619 /* increase age of constraint (age is reset to zero, if a cut was found) */
5620 if( cons != NULL )
5621 {
5622 SCIP_CALL( SCIPincConsAge(scip, cons) );
5623 }
5624
5625 /* allocates temporary memory */
5627 SCIP_CALL( SCIPallocBufferArray(scip, &covervars, nvars) );
5628 SCIP_CALL( SCIPallocBufferArray(scip, &noncovervars, nvars) );
5629
5630 /* gets solution values of all problem variables */
5631 SCIP_CALL( SCIPgetSolVals(scip, sol, nvars, vars, solvals) );
5632
5633#ifdef SCIP_DEBUG
5634 {
5635 int i;
5636
5637 SCIPdebugMsg(scip, "separate cuts for knapsack constraint originated by cons <%s>:\n",
5638 cons == NULL ? "-" : SCIPconsGetName(cons));
5639 for( i = 0; i < nvars; ++i )
5640 {
5641 SCIPdebugMsgPrint(scip, "%+" SCIP_LONGINT_FORMAT "<%s>(%g)", weights[i], SCIPvarGetName(vars[i]), solvals[i]);
5642 }
5643 SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT "\n", capacity);
5644 }
5645#endif
5646
5647 /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting) using GUB information
5648 */
5649 if( usegubs )
5650 {
5651 SCIP_GUBSET* gubset;
5652
5653 SCIPdebugMsg(scip, "separate LMCI1-GUB cuts:\n");
5654
5655 /* initializes partion of knapsack variables into nonoverlapping GUB constraints */
5656 SCIP_CALL( GUBsetCreate(scip, &gubset, nvars, weights, capacity) );
5657
5658 /* constructs sophisticated partition of knapsack variables into nonoverlapping GUBs */
5659 SCIP_CALL( GUBsetGetCliquePartition(scip, gubset, vars, solvals) );
5660 assert(gubset->ngubconss <= nvars);
5661
5662 /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5663 * MODIFIED transformed separation problem and taking into account the following fixing:
5664 * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5665 * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5666 * if one exists
5667 */
5668 modtransused = TRUE;
5669 SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5670 &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5671
5672 assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5673
5674 /* if x* is not fractional we stop the separation routine */
5675 if( !fractional )
5676 {
5677 SCIPdebugMsg(scip, " LMCI1-GUB terminated by no variable with fractional LP value.\n");
5678
5679 /* frees memory for GUB set data structure */
5680 GUBsetFree(scip, &gubset);
5681
5682 goto TERMINATE;
5683 }
5684
5685 /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5686 if( coverfound )
5687 {
5688 /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5689 * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5690 */
5691 SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5692 &nnoncovervars, &coverweight, modtransused) );
5693
5694 /* only separate with GUB information if we have at least one nontrivial GUB (with more than one variable) */
5695 if( gubset->ngubconss < nvars )
5696 {
5697 /* separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information */
5698 SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5699 solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, gubset, cutoff, ncuts) );
5700 }
5701 else
5702 {
5703 /* separates lifted minimal cover inequalities using sequential up- and down-lifting, but do not use trivial
5704 * GUB information
5705 */
5706 SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5707 solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5708 }
5709 }
5710
5711 /* frees memory for GUB set data structure */
5712 GUBsetFree(scip, &gubset);
5713 }
5714 else
5715 {
5716 /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting)
5717 * (and LMCI2 (lifted minimal cover inequalities using superadditive up-lifting))
5718 */
5719
5720 /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5721 * MODIFIED transformed separation problem and taking into account the following fixing:
5722 * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5723 * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5724 * if one exists
5725 */
5726 SCIPdebugMsg(scip, "separate LMCI1 cuts:\n");
5727 modtransused = TRUE;
5728 SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5729 &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5730 assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5731
5732 /* if x* is not fractional we stop the separation routine */
5733 if( !fractional )
5734 goto TERMINATE;
5735
5736 /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5737 if( coverfound )
5738 {
5739 /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5740 * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5741 */
5742 SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5743 &nnoncovervars, &coverweight, modtransused) );
5744
5745 /* separates lifted minimal cover inequalities using sequential up- and down-lifting */
5746 SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5747 solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5748
5749 if( USESUPADDLIFT ) /*lint !e506 !e774*/
5750 {
5751 SCIPdebugMsg(scip, "separate LMCI2 cuts:\n");
5752 /* separates lifted minimal cover inequalities using superadditive up-lifting */
5753 SCIP_CALL( separateSupLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5754 solvals, covervars, noncovervars, ncovervars, nnoncovervars, coverweight, sol, cutoff, ncuts) );
5755 }
5756 }
5757 }
5758
5759 /* LEWI (lifted extended weight inequalities using sequential up- and down-lifting) */
5760 if ( ! (*cutoff) )
5761 {
5762 /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5763 * transformed separation problem and taking into account the following fixing:
5764 * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5765 * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5766 * if one exists
5767 */
5768 SCIPdebugMsg(scip, "separate LEWI cuts:\n");
5769 modtransused = FALSE;
5770 SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5771 &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5772 assert(fractional);
5773 assert(!coverfound || ncovervars + nnoncovervars == nvars - ntightened);
5774
5775 /* if no cover was found we stop the separation routine */
5776 if( coverfound )
5777 {
5778 /* converts initial cover C_init to a feasible set by removing variables in the reverse order in which
5779 * they were chosen to be in C_init and separates lifted extended weight inequalities using sequential
5780 * up- and down-lifting for this feasible set and all subsequent feasible sets.
5781 */
5782 SCIP_CALL( getFeasibleSet(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals, covervars, noncovervars,
5783 &ncovervars, &nnoncovervars, &coverweight, modtransused, sol, cutoff, ncuts) );
5784 }
5785 }
5786
5787 TERMINATE:
5788 /* frees temporary memory */
5789 SCIPfreeBufferArray(scip, &noncovervars);
5790 SCIPfreeBufferArray(scip, &covervars);
5791 SCIPfreeBufferArray(scip, &solvals);
5792
5793 return SCIP_OKAY;
5794}
5795
5796/* relaxes given general linear constraint into a knapsack constraint and separates lifted knapsack cover inequalities */
5798 SCIP* scip, /**< SCIP data structure */
5799 SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5800 SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5801 int nknapvars, /**< number of variables in the continuous knapsack constraint */
5802 SCIP_VAR** knapvars, /**< variables in the continuous knapsack constraint */
5803 SCIP_Real* knapvals, /**< coefficients of the variables in the continuous knapsack constraint */
5804 SCIP_Real valscale, /**< -1.0 if lhs of row is used as rhs of c. k. constraint, +1.0 otherwise */
5805 SCIP_Real rhs, /**< right hand side of the continuous knapsack constraint */
5806 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
5807 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff was found */
5808 int* ncuts /**< pointer to add up the number of found cuts */
5809 )
5810{
5811 SCIP_VAR** binvars;
5812 SCIP_VAR** consvars;
5813 SCIP_Real* binvals;
5814 SCIP_Longint* consvals;
5815 SCIP_Longint minact;
5816 SCIP_Longint maxact;
5817 SCIP_Real intscalar;
5818 SCIP_Bool success;
5819 int nbinvars;
5820 int nconsvars;
5821 int i;
5822
5823 int* tmpindices;
5824 int tmp;
5825 SCIP_CONSHDLR* conshdlr;
5826 SCIP_CONSHDLRDATA* conshdlrdata;
5827 SCIP_Bool noknapsackconshdlr;
5828 SCIP_Bool usegubs;
5829
5830 assert(nknapvars > 0);
5831 assert(knapvars != NULL);
5832 assert(cutoff != NULL);
5833
5834 tmpindices = NULL;
5835
5836 SCIPdebugMsg(scip, "separate linear constraint <%s> relaxed to knapsack\n", cons != NULL ? SCIPconsGetName(cons) : "-");
5837 SCIPdebug( if( cons != NULL ) { SCIPdebugPrintCons(scip, cons, NULL); } );
5838
5839 binvars = SCIPgetVars(scip);
5840
5841 /* all variables which are of integral type can be potentially of binary type; this can be checked via the method SCIPvarIsBinary(var) */
5842 nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
5843
5844 *cutoff = FALSE;
5845
5846 if( nbinvars == 0 )
5847 return SCIP_OKAY;
5848
5849 /* set up data structures */
5850 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nbinvars) );
5851 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nbinvars) );
5852
5853 /* get conshdlrdata to use cleared memory */
5854 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
5855 if( conshdlr == NULL )
5856 {
5857 noknapsackconshdlr = TRUE;
5858 usegubs = DEFAULT_USEGUBS;
5859
5860 SCIP_CALL( SCIPallocBufferArray(scip, &binvals, nbinvars) );
5861 BMSclearMemoryArray(binvals, nbinvars);
5862 }
5863 else
5864 {
5865 noknapsackconshdlr = FALSE;
5866 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5867 assert(conshdlrdata != NULL);
5868 usegubs = conshdlrdata->usegubs;
5869
5870 SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, nknapvars) );
5871
5872 /* increase array size to avoid an endless loop in the next block; this might happen if continuous variables
5873 * change their types to SCIP_VARTYPE_BINARY during presolving
5874 */
5875 if( conshdlrdata->reals1size == 0 )
5876 {
5877 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, conshdlrdata->reals1size, 1) );
5878 conshdlrdata->reals1size = 1;
5879 conshdlrdata->reals1[0] = 0.0;
5880 }
5881
5882 assert(conshdlrdata->reals1size > 0);
5883
5884 /* next if condition should normally not be true, because it means that presolving has created more binary
5885 * variables than binary + integer variables existed at the constraint initialization method, but for example if you would
5886 * transform all integers into their binary representation then it maybe happens
5887 */
5888 if( conshdlrdata->reals1size < nbinvars )
5889 {
5890 int oldsize = conshdlrdata->reals1size;
5891
5892 conshdlrdata->reals1size = nbinvars;
5893 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, oldsize, conshdlrdata->reals1size) );
5894 BMSclearMemoryArray(&(conshdlrdata->reals1[oldsize]), conshdlrdata->reals1size - oldsize); /*lint !e866 */
5895 }
5896 binvals = conshdlrdata->reals1;
5897
5898 /* check for cleared array, all entries have to be zero */
5899#ifndef NDEBUG
5900 for( tmp = nbinvars - 1; tmp >= 0; --tmp )
5901 {
5902 assert(binvals[tmp] == 0);
5903 }
5904#endif
5905 }
5906
5907 tmp = 0;
5908
5909 /* relax continuous knapsack constraint:
5910 * 1. make all variables binary:
5911 * if x_j is continuous or integer variable substitute:
5912 * - a_j < 0: x_j = lb or x_j = b*z + d with variable lower bound b*z + d with binary variable z
5913 * - a_j > 0: x_j = ub or x_j = b*z + d with variable upper bound b*z + d with binary variable z
5914 * 2. convert coefficients of all variables to positive integers:
5915 * - scale all coefficients a_j to a~_j integral
5916 * - substitute x~_j = 1 - x_j if a~_j < 0
5917 */
5918
5919 /* replace integer and continuous variables with binary variables */
5920 for( i = 0; i < nknapvars; i++ )
5921 {
5922 SCIP_VAR* var;
5923
5924 var = knapvars[i];
5925
5927 {
5928 SCIP_Real solval;
5930
5931 solval = SCIPgetSolVal(scip, sol, var);
5932
5933 /* knapsack relaxation assumes solution values between 0.0 and 1.0 for binary variables */
5934 if( SCIPisFeasLT(scip, solval, 0.0 )
5935 || SCIPisFeasGT(scip, solval, 1.0) )
5936 {
5937 SCIPdebugMsg(scip, "Solution value %.15g <%s> outside domain [0.0, 1.0]\n",
5938 solval, SCIPvarGetName(var));
5939 goto TERMINATE;
5940 }
5941
5942 binvals[SCIPvarGetProbindex(var)] += valscale * knapvals[i];
5943 if( !noknapsackconshdlr )
5944 {
5945 assert(tmpindices != NULL);
5946
5947 tmpindices[tmp] = SCIPvarGetProbindex(var);
5948 ++tmp;
5949 }
5950 SCIPdebugMsg(scip, " -> binary variable %+.15g<%s>(%.15g)\n", valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var));
5951 }
5952 else if( valscale * knapvals[i] > 0.0 )
5953 {
5954 SCIP_VAR** zvlb;
5955 SCIP_Real* bvlb;
5956 SCIP_Real* dvlb;
5957 SCIP_Real bestlbsol;
5958 int bestlbtype;
5959 int nvlb;
5960 int j;
5961
5962 /* a_j > 0: substitution with lb or vlb */
5963 nvlb = SCIPvarGetNVlbs(var);
5964 zvlb = SCIPvarGetVlbVars(var);
5965 bvlb = SCIPvarGetVlbCoefs(var);
5967
5968 /* search for lb or vlb with maximal bound value */
5969 bestlbsol = SCIPvarGetLbGlobal(var);
5970 bestlbtype = -1;
5971 for( j = 0; j < nvlb; j++ )
5972 {
5973 /* use only numerical stable vlb with binary variable z */
5974 if( SCIPvarIsBinary(zvlb[j]) && SCIPvarIsActive(zvlb[j]) && REALABS(bvlb[j]) <= MAXABSVBCOEF )
5975 {
5976 SCIP_Real vlbsol;
5977
5978 if( (bvlb[j] >= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetLbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) ||
5979 (bvlb[j] <= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetUbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) )
5980 {
5981 *cutoff = TRUE;
5982 SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] >= %g<%s>[%g,%g] + %g implies local cutoff\n",
5984 bvlb[j], SCIPvarGetName(zvlb[j]), SCIPvarGetLbLocal(zvlb[j]), SCIPvarGetUbLocal(zvlb[j]), dvlb[j]);
5985 goto TERMINATE;
5986 }
5987
5988 assert(0 <= SCIPvarGetProbindex(zvlb[j]) && SCIPvarGetProbindex(zvlb[j]) < nbinvars);
5989 vlbsol = bvlb[j] * SCIPgetSolVal(scip, sol, zvlb[j]) + dvlb[j];
5990 if( SCIPisGE(scip, vlbsol, bestlbsol) )
5991 {
5992 bestlbsol = vlbsol;
5993 bestlbtype = j;
5994 }
5995 }
5996 }
5997
5998 /* if no lb or vlb with binary variable was found, we have to abort */
5999 if( SCIPisInfinity(scip, -bestlbsol) )
6000 goto TERMINATE;
6001
6002 if( bestlbtype == -1 )
6003 {
6004 rhs -= valscale * knapvals[i] * bestlbsol;
6005 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with lower bound %.15g (rhs=%.15g)\n",
6006 valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetLbGlobal(var), rhs);
6007 }
6008 else
6009 {
6010 assert(0 <= SCIPvarGetProbindex(zvlb[bestlbtype]) && SCIPvarGetProbindex(zvlb[bestlbtype]) < nbinvars);
6011 rhs -= valscale * knapvals[i] * dvlb[bestlbtype];
6012 binvals[SCIPvarGetProbindex(zvlb[bestlbtype])] += valscale * knapvals[i] * bvlb[bestlbtype];
6013
6014 if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvlb[bestlbtype])])) )
6015 goto TERMINATE;
6016
6017 if( !noknapsackconshdlr )
6018 {
6019 assert(tmpindices != NULL);
6020
6021 tmpindices[tmp] = SCIPvarGetProbindex(zvlb[bestlbtype]);
6022 ++tmp;
6023 }
6024 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable lower bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
6025 valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
6026 bvlb[bestlbtype], SCIPvarGetName(zvlb[bestlbtype]),
6027 SCIPgetSolVal(scip, sol, zvlb[bestlbtype]), dvlb[bestlbtype], rhs);
6028 }
6029 }
6030 else
6031 {
6032 SCIP_VAR** zvub;
6033 SCIP_Real* bvub;
6034 SCIP_Real* dvub;
6035 SCIP_Real bestubsol;
6036 int bestubtype;
6037 int nvub;
6038 int j;
6039
6040 assert(valscale * knapvals[i] < 0.0);
6041
6042 /* a_j < 0: substitution with ub or vub */
6043 nvub = SCIPvarGetNVubs(var);
6044 zvub = SCIPvarGetVubVars(var);
6045 bvub = SCIPvarGetVubCoefs(var);
6047
6048 /* search for ub or vub with minimal bound value */
6049 bestubsol = SCIPvarGetUbGlobal(var);
6050 bestubtype = -1;
6051 for( j = 0; j < nvub; j++ )
6052 {
6053 /* use only numerical stable vub with active binary variable z */
6054 if( SCIPvarIsBinary(zvub[j]) && SCIPvarIsActive(zvub[j]) && REALABS(bvub[j]) <= MAXABSVBCOEF )
6055 {
6056 SCIP_Real vubsol;
6057
6058 if( (bvub[j] >= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetUbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) ||
6059 (bvub[j] <= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetLbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) )
6060 {
6061 *cutoff = TRUE;
6062 SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] <= %g<%s>[%g,%g] + %g implies local cutoff\n",
6064 bvub[j], SCIPvarGetName(zvub[j]), SCIPvarGetLbLocal(zvub[j]), SCIPvarGetUbLocal(zvub[j]), dvub[j]);
6065 goto TERMINATE;
6066 }
6067
6068 assert(0 <= SCIPvarGetProbindex(zvub[j]) && SCIPvarGetProbindex(zvub[j]) < nbinvars);
6069 vubsol = bvub[j] * SCIPgetSolVal(scip, sol, zvub[j]) + dvub[j];
6070 if( SCIPisLE(scip, vubsol, bestubsol) )
6071 {
6072 bestubsol = vubsol;
6073 bestubtype = j;
6074 }
6075 }
6076 }
6077
6078 /* if no ub or vub with binary variable was found, we have to abort */
6079 if( SCIPisInfinity(scip, bestubsol) )
6080 goto TERMINATE;
6081
6082 if( bestubtype == -1 )
6083 {
6084 rhs -= valscale * knapvals[i] * bestubsol;
6085 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with upper bound %.15g (rhs=%.15g)\n",
6086 valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetUbGlobal(var), rhs);
6087 }
6088 else
6089 {
6090 assert(0 <= SCIPvarGetProbindex(zvub[bestubtype]) && SCIPvarGetProbindex(zvub[bestubtype]) < nbinvars);
6091 rhs -= valscale * knapvals[i] * dvub[bestubtype];
6092 binvals[SCIPvarGetProbindex(zvub[bestubtype])] += valscale * knapvals[i] * bvub[bestubtype];
6093
6094 if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvub[bestubtype])])) )
6095 goto TERMINATE;
6096
6097 if( !noknapsackconshdlr )
6098 {
6099 assert(tmpindices != NULL);
6100
6101 tmpindices[tmp] = SCIPvarGetProbindex(zvub[bestubtype]);
6102 ++tmp;
6103 }
6104 SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable upper bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
6105 valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
6106 bvub[bestubtype], SCIPvarGetName(zvub[bestubtype]),
6107 SCIPgetSolVal(scip, sol, zvub[bestubtype]), dvub[bestubtype], rhs);
6108 }
6109 }
6110 }
6111
6112 /* convert coefficients of all (now binary) variables to positive integers:
6113 * - make all coefficients integral
6114 * - make all coefficients positive (substitute negated variable)
6115 */
6116 nconsvars = 0;
6117
6118 /* calculate scalar which makes all coefficients integral in relative allowed difference in between
6119 * -SCIPepsilon(scip) and KNAPSACKRELAX_MAXDELTA
6120 */
6122 KNAPSACKRELAX_MAXDNOM, KNAPSACKRELAX_MAXSCALE, &intscalar, &success) );
6123 SCIPdebugMsg(scip, " -> intscalar = %.15g\n", intscalar);
6124
6125 /* if coefficients cannot be made integral, we have to use a scalar of 1.0 and only round fractional coefficients down */
6126 if( !success )
6127 intscalar = 1.0;
6128
6129 /* make all coefficients integral and positive:
6130 * - scale a~_j = a_j * intscalar
6131 * - substitute x~_j = 1 - x_j if a~_j < 0
6132 */
6133 rhs = rhs * intscalar;
6134
6135 SCIPdebugMsg(scip, " -> rhs = %.15g\n", rhs);
6136 minact = 0;
6137 maxact = 0;
6138 for( i = 0; i < nbinvars; i++ )
6139 {
6140 SCIP_VAR* var;
6141 SCIP_Longint val;
6142
6143 val = (SCIP_Longint)SCIPfloor(scip, binvals[i] * intscalar);
6144 if( val == 0 )
6145 continue;
6146
6147 if( val > 0 )
6148 {
6149 var = binvars[i];
6150 SCIPdebugMsg(scip, " -> positive scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): not changed (rhs=%.15g)\n",
6151 val, SCIPvarGetName(var), binvals[i], rhs);
6152 }
6153 else
6154 {
6155 assert(val < 0);
6156
6157 SCIP_CALL( SCIPgetNegatedVar(scip, binvars[i], &var) );
6158 val = -val; /*lint !e2704*/
6159 rhs += val;
6160 SCIPdebugMsg(scip, " -> negative scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): substituted by (1 - <%s>) (rhs=%.15g)\n",
6161 -val, SCIPvarGetName(binvars[i]), binvals[i], SCIPvarGetName(var), rhs);
6162 }
6163
6164 if( SCIPvarGetLbLocal(var) > 0.5 )
6165 minact += val;
6166 if( SCIPvarGetUbLocal(var) > 0.5 )
6167 maxact += val;
6168 consvals[nconsvars] = val;
6169 consvars[nconsvars] = var;
6170 nconsvars++;
6171 }
6172
6173 if( nconsvars > 0 )
6174 {
6175 SCIP_Longint capacity;
6176
6177 assert(consvars != NULL);
6178 assert(consvals != NULL);
6179 capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
6180
6181#ifdef SCIP_DEBUG
6182 {
6183 SCIP_Real act;
6184
6185 SCIPdebugMsg(scip, " -> linear constraint <%s> relaxed to knapsack:", cons != NULL ? SCIPconsGetName(cons) : "-");
6186 act = 0.0;
6187 for( i = 0; i < nconsvars; ++i )
6188 {
6189 SCIPdebugMsgPrint(scip, " %+" SCIP_LONGINT_FORMAT "<%s>(%.15g)", consvals[i], SCIPvarGetName(consvars[i]),
6190 SCIPgetSolVal(scip, sol, consvars[i]));
6191 act += consvals[i] * SCIPgetSolVal(scip, sol, consvars[i]);
6192 }
6193 SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT " (%.15g) [act: %.15g, min: %" SCIP_LONGINT_FORMAT " max: %" SCIP_LONGINT_FORMAT "]\n",
6194 capacity, rhs, act, minact, maxact);
6195 }
6196#endif
6197
6198 if( minact > capacity )
6199 {
6200 SCIPdebugMsg(scip, "minactivity of knapsack relaxation implies local cutoff\n");
6201 *cutoff = TRUE;
6202 goto TERMINATE;
6203 }
6204
6205 if( maxact > capacity )
6206 {
6207 /* separate lifted cut from relaxed knapsack constraint */
6208 SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, sepa, consvars, nconsvars, consvals, capacity, sol, usegubs, cutoff, ncuts) );
6209 }
6210 }
6211
6212 TERMINATE:
6213 /* free data structures */
6214 if( noknapsackconshdlr)
6215 {
6216 SCIPfreeBufferArray(scip, &binvals);
6217 }
6218 else
6219 {
6220 /* clear binvals */
6221 for( --tmp; tmp >= 0; --tmp)
6222 {
6223 assert(tmpindices != NULL);
6224 binvals[tmpindices[tmp]] = 0;
6225 }
6226 SCIPfreeBufferArray(scip, &tmpindices);
6227 }
6228 SCIPfreeBufferArray(scip, &consvals);
6229 SCIPfreeBufferArray(scip, &consvars);
6230
6231 return SCIP_OKAY;
6232}
6233
6234/** separates given knapsack constraint */
6235static
6237 SCIP* scip, /**< SCIP data structure */
6238 SCIP_CONS* cons, /**< knapsack constraint */
6239 SCIP_SOL* sol, /**< primal SCIP solution, NULL for current LP solution */
6240 SCIP_Bool sepacuts, /**< should knapsack cuts be separated? */
6241 SCIP_Bool usegubs, /**< should GUB information be used for separation? */
6242 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
6243 int* ncuts /**< pointer to add up the number of found cuts */
6244 )
6245{
6246 SCIP_CONSDATA* consdata;
6247 SCIP_Bool violated;
6248
6249 assert(ncuts != NULL);
6250 assert(cutoff != NULL);
6251 *cutoff = FALSE;
6252
6253 consdata = SCIPconsGetData(cons);
6254 assert(consdata != NULL);
6255
6256 SCIPdebugMsg(scip, "separating knapsack constraint <%s>\n", SCIPconsGetName(cons));
6257
6258 /* check knapsack constraint itself for feasibility */
6259 SCIP_CALL( checkCons(scip, cons, sol, (sol != NULL), FALSE, &violated) );
6260
6261 if( violated )
6262 {
6263 /* add knapsack constraint as LP row to the LP */
6265 (*ncuts)++;
6266 }
6267 else if( sepacuts )
6268 {
6269 SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, NULL, consdata->vars, consdata->nvars, consdata->weights,
6270 consdata->capacity, sol, usegubs, cutoff, ncuts) );
6271 }
6272
6273 return SCIP_OKAY;
6274}
6275
6276/** adds coefficient to constraint data */
6277static
6279 SCIP* scip, /**< SCIP data structure */
6280 SCIP_CONS* cons, /**< knapsack constraint */
6281 SCIP_VAR* var, /**< variable to add to knapsack */
6282 SCIP_Longint weight /**< weight of variable in knapsack */
6283 )
6284{
6285 SCIP_CONSDATA* consdata;
6286
6287 consdata = SCIPconsGetData(cons);
6288 assert(consdata != NULL);
6290 assert(weight > 0);
6291
6292 /* add the new coefficient to the LP row */
6293 if( consdata->row != NULL )
6294 {
6295 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, (SCIP_Real)weight) );
6296 }
6297
6298 /* check for fixed variable */
6299 if( SCIPvarGetLbGlobal(var) > 0.5 )
6300 {
6301 /* variable is fixed to one: reduce capacity */
6302 consdata->capacity -= weight;
6303 }
6304 else if( SCIPvarGetUbGlobal(var) > 0.5 )
6305 {
6306 SCIP_Bool negated;
6307
6308 /* get binary representative of variable */
6310
6311 /* insert coefficient */
6312 SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1, SCIPconsIsTransformed(cons)) );
6313 consdata->vars[consdata->nvars] = var;
6314 consdata->weights[consdata->nvars] = weight;
6315 consdata->nvars++;
6316
6317 /* capture variable */
6319
6320 /* install the rounding locks of variable */
6321 SCIP_CALL( lockRounding(scip, cons, var) );
6322
6323 /* catch events */
6324 if( SCIPconsIsTransformed(cons) )
6325 {
6326 SCIP_CONSHDLRDATA* conshdlrdata;
6327
6328 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6329 assert(conshdlrdata != NULL);
6330 SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[consdata->nvars-1], cons, weight) );
6332 conshdlrdata->eventhdlr, consdata->eventdata[consdata->nvars-1],
6333 &consdata->eventdata[consdata->nvars-1]->filterpos) );
6334
6335 if( !consdata->existmultaggr && SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR )
6336 consdata->existmultaggr = TRUE;
6337
6338 /* mark constraint to be propagated and presolved */
6340 consdata->presolvedtiming = 0;
6341 consdata->cliquesadded = FALSE; /* new coefficient might lead to larger cliques */
6342 }
6343
6344 /* update weight sums */
6345 updateWeightSums(consdata, var, weight);
6346
6347 consdata->sorted = FALSE;
6348 consdata->cliquepartitioned = FALSE;
6349 consdata->negcliquepartitioned = FALSE;
6350 consdata->merged = FALSE;
6351 }
6352
6353 return SCIP_OKAY;
6354}
6355
6356/** deletes coefficient at given position from constraint data */
6357static
6359 SCIP* scip, /**< SCIP data structure */
6360 SCIP_CONS* cons, /**< knapsack constraint */
6361 int pos /**< position of coefficient to delete */
6362 )
6363{
6364 SCIP_CONSDATA* consdata;
6365 SCIP_VAR* var;
6366
6367 consdata = SCIPconsGetData(cons);
6368 assert(consdata != NULL);
6369 assert(0 <= pos && pos < consdata->nvars);
6370
6371 var = consdata->vars[pos];
6372 assert(var != NULL);
6374
6375 /* delete the coefficient from the LP row */
6376 if( consdata->row != NULL )
6377 {
6378 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, -(SCIP_Real)consdata->weights[pos]) );
6379 }
6380
6381 /* remove the rounding locks of variable */
6382 SCIP_CALL( unlockRounding(scip, cons, var) );
6383
6384 /* drop events and mark constraint to be propagated and presolved */
6385 if( SCIPconsIsTransformed(cons) )
6386 {
6387 SCIP_CONSHDLRDATA* conshdlrdata;
6388
6389 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6390 assert(conshdlrdata != NULL);
6392 conshdlrdata->eventhdlr, consdata->eventdata[pos], consdata->eventdata[pos]->filterpos) );
6393 SCIP_CALL( eventdataFree(scip, &consdata->eventdata[pos]) );
6394
6396 consdata->presolvedtiming = 0;
6397 consdata->sorted = (consdata->sorted && pos == consdata->nvars - 1);
6398 }
6399
6400 /* decrease weight sums */
6401 updateWeightSums(consdata, var, -consdata->weights[pos]);
6402
6403 /* move the last variable to the free slot */
6404 consdata->vars[pos] = consdata->vars[consdata->nvars-1];
6405 consdata->weights[pos] = consdata->weights[consdata->nvars-1];
6406 if( consdata->eventdata != NULL )
6407 consdata->eventdata[pos] = consdata->eventdata[consdata->nvars-1];
6408
6409 /* release variable */
6411
6412 /* try to use old clique partitions */
6413 if( consdata->cliquepartitioned )
6414 {
6415 assert(consdata->cliquepartition != NULL);
6416 /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6417 * change the clique number */
6418 if( consdata->cliquepartition[consdata->nvars - 1] != consdata->nvars - 1 )
6419 {
6420 int oldcliqenum;
6421
6422 oldcliqenum = consdata->cliquepartition[pos];
6423 consdata->cliquepartition[pos] = consdata->cliquepartition[consdata->nvars-1];
6424
6425 /* the following if and else cases assure that we have increasing clique numbers */
6426 if( consdata->cliquepartition[pos] > pos )
6427 consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6428 else
6429 {
6430 int i;
6431 int cliquenumbefore;
6432
6433 /* if the old clique number was greater than the new one we have to check that before a bigger clique number
6434 * occurs the same as the old one is still in the cliquepartition */
6435 if( oldcliqenum > consdata->cliquepartition[pos] )
6436 {
6437 for( i = 0; i < consdata->nvars; ++i )
6438 if( oldcliqenum == consdata->cliquepartition[i] )
6439 break;
6440 else if( oldcliqenum < consdata->cliquepartition[i] )
6441 {
6442 consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6443 break;
6444 }
6445 /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6446 * the biggest index, so decrease the number of cliques
6447 */
6448 if( i == consdata->nvars )
6449 --(consdata->ncliques);
6450 }
6451 /* if the old clique number was smaller than the new one we have to check the front for an element with
6452 * clique number minus 1 */
6453 else if( oldcliqenum < consdata->cliquepartition[pos] )
6454 {
6455 cliquenumbefore = consdata->cliquepartition[pos] - 1;
6456 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6457
6458 if( i < cliquenumbefore )
6459 consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6460 }
6461 /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6462 else if( pos == consdata->nvars - 1)
6463 {
6464 cliquenumbefore = consdata->cliquepartition[pos];
6465 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6466
6467 if( i < cliquenumbefore )
6468 --(consdata->ncliques);
6469 }
6470 /* if the old clique number is equal to the new one the cliquepartition should be ok */
6471 }
6472 }
6473 else
6474 --(consdata->ncliques);
6475 }
6476
6477 if( consdata->negcliquepartitioned )
6478 {
6479 assert(consdata->negcliquepartition != NULL);
6480 /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6481 * change the clique number */
6482 if( consdata->negcliquepartition[consdata->nvars-1] != consdata->nvars - 1 )
6483 {
6484 int oldcliqenum;
6485
6486 oldcliqenum = consdata->negcliquepartition[pos];
6487 consdata->negcliquepartition[pos] = consdata->negcliquepartition[consdata->nvars-1];
6488
6489 /* the following if and else cases assure that we have increasing clique numbers */
6490 if( consdata->negcliquepartition[pos] > pos )
6491 consdata->negcliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6492 else
6493 {
6494 int i;
6495 int cliquenumbefore;
6496
6497 /* if the old clique number was greater than the new one we have to check that, before a bigger clique number
6498 * occurs, the same as the old one occurs */
6499 if( oldcliqenum > consdata->negcliquepartition[pos] )
6500 {
6501 for( i = 0; i < consdata->nvars; ++i )
6502 if( oldcliqenum == consdata->negcliquepartition[i] )
6503 break;
6504 else if( oldcliqenum < consdata->negcliquepartition[i] )
6505 {
6506 consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6507 break;
6508 }
6509 /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6510 * the biggest index, so decrease the number of negated cliques
6511 */
6512 if( i == consdata->nvars )
6513 --(consdata->nnegcliques);
6514 }
6515 /* if the old clique number was smaller than the new one we have to check the front for an element with
6516 * clique number minus 1 */
6517 else if( oldcliqenum < consdata->negcliquepartition[pos] )
6518 {
6519 cliquenumbefore = consdata->negcliquepartition[pos] - 1;
6520 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6521
6522 if( i < cliquenumbefore )
6523 consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6524 }
6525 /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6526 else if( pos == consdata->nvars - 1)
6527 {
6528 cliquenumbefore = consdata->negcliquepartition[pos];
6529 for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6530
6531 if( i < cliquenumbefore )
6532 --(consdata->nnegcliques);
6533 }
6534 /* otherwise if the old clique number is equal to the new one the cliquepartition should be ok */
6535 }
6536 }
6537 else
6538 --(consdata->nnegcliques);
6539 }
6540
6541 --(consdata->nvars);
6542
6543 return SCIP_OKAY;
6544}
6545
6546/** removes all items with weight zero from knapsack constraint */
6547static
6549 SCIP* scip, /**< SCIP data structure */
6550 SCIP_CONS* cons /**< knapsack constraint */
6551 )
6552{
6553 SCIP_CONSDATA* consdata;
6554 int v;
6555
6556 consdata = SCIPconsGetData(cons);
6557 assert(consdata != NULL);
6558
6559 for( v = consdata->nvars-1; v >= 0; --v )
6560 {
6561 if( consdata->weights[v] == 0 )
6562 {
6563 SCIP_CALL( delCoefPos(scip, cons, v) );
6564 }
6565 }
6566
6567 return SCIP_OKAY;
6568}
6569
6570/* perform deletion of variables in all constraints of the constraint handler */
6571static
6573 SCIP* scip, /**< SCIP data structure */
6574 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6575 SCIP_CONS** conss, /**< array of constraints */
6576 int nconss /**< number of constraints */
6577 )
6578{
6579 SCIP_CONSDATA* consdata;
6580 int i;
6581 int v;
6582
6583 assert(scip != NULL);
6584 assert(conshdlr != NULL);
6585 assert(conss != NULL);
6586 assert(nconss >= 0);
6587
6589
6590 /* iterate over all constraints */
6591 for( i = 0; i < nconss; i++ )
6592 {
6593 consdata = SCIPconsGetData(conss[i]);
6594
6595 /* constraint is marked, that some of its variables were deleted */
6596 if( consdata->varsdeleted )
6597 {
6598 /* iterate over all variables of the constraint and delete them from the constraint */
6599 for( v = consdata->nvars - 1; v >= 0; --v )
6600 {
6601 if( SCIPvarIsDeleted(consdata->vars[v]) )
6602 {
6603 SCIP_CALL( delCoefPos(scip, conss[i], v) );
6604 }
6605 }
6606 consdata->varsdeleted = FALSE;
6607 }
6608 }
6609
6610 return SCIP_OKAY;
6611}
6612
6613/** replaces multiple occurrences of a variable or its negation by a single coefficient */
6614static
6616 SCIP* scip, /**< SCIP data structure */
6617 SCIP_CONS* cons, /**< knapsack constraint */
6618 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
6619 )
6620{
6621 SCIP_CONSDATA* consdata;
6622 int v;
6623 int prev;
6624
6625 assert(scip != NULL);
6626 assert(cons != NULL);
6627 assert(cutoff != NULL);
6628
6629 consdata = SCIPconsGetData(cons);
6630 assert(consdata != NULL);
6631
6632 *cutoff = FALSE;
6633
6634 if( consdata->merged )
6635 return SCIP_OKAY;
6636
6637 if( consdata->nvars <= 1 )
6638 {
6639 consdata->merged = TRUE;
6640 return SCIP_OKAY;
6641 }
6642
6643 assert(consdata->vars != NULL || consdata->nvars == 0);
6644
6645 /* sorting array after indices of variables, that's only for faster merging */
6646 SCIPsortPtrPtrLongIntInt((void**)consdata->vars, (void**)consdata->eventdata, consdata->weights,
6647 consdata->cliquepartition, consdata->negcliquepartition, SCIPvarCompActiveAndNegated, consdata->nvars);
6648
6649 /* knapsack-sorting (decreasing weights) now lost */
6650 consdata->sorted = FALSE;
6651
6652 v = consdata->nvars - 1;
6653 prev = v - 1;
6654 /* loop backwards through the items: deletion only affects rear items */
6655 while( prev >= 0 )
6656 {
6657 SCIP_VAR* var1;
6658 SCIP_VAR* var2;
6659 SCIP_Bool negated1;
6660 SCIP_Bool negated2;
6661
6662 negated1 = FALSE;
6663 negated2 = FALSE;
6664
6665 var1 = consdata->vars[v];
6666 assert(SCIPvarIsBinary(var1));
6669 {
6670 var1 = SCIPvarGetNegatedVar(var1);
6671 negated1 = TRUE;
6672 }
6673 assert(var1 != NULL);
6674
6675 var2 = consdata->vars[prev];
6676 assert(SCIPvarIsBinary(var2));
6679 {
6680 var2 = SCIPvarGetNegatedVar(var2);
6681 negated2 = TRUE;
6682 }
6683 assert(var2 != NULL);
6684
6685 if( var1 == var2 )
6686 {
6687 /* both variables are either active or negated */
6688 if( negated1 == negated2 )
6689 {
6690 /* variables var1 and var2 are equal: add weight of var1 to var2, and delete var1 */
6691 consdataChgWeight(consdata, prev, consdata->weights[v] + consdata->weights[prev]);
6692 SCIP_CALL( delCoefPos(scip, cons, v) );
6693 }
6694 /* variables var1 and var2 are opposite: subtract smaller weight from larger weight, reduce capacity,
6695 * and delete item of smaller weight
6696 */
6697 else if( consdata->weights[v] == consdata->weights[prev] )
6698 {
6699 /* both variables eliminate themselves: w*x + w*(1-x) == w */
6700 consdata->capacity -= consdata->weights[v];
6701 SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6702 SCIP_CALL( delCoefPos(scip, cons, prev) );
6703
6704 --prev;
6705 }
6706 else if( consdata->weights[v] < consdata->weights[prev] )
6707 {
6708 consdata->capacity -= consdata->weights[v];
6709 consdataChgWeight(consdata, prev, consdata->weights[prev] - consdata->weights[v]);
6710 assert(consdata->weights[prev] > 0);
6711 SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6712 }
6713 else
6714 {
6715 consdata->capacity -= consdata->weights[prev];
6716 consdataChgWeight(consdata, v, consdata->weights[v] - consdata->weights[prev]);
6717 assert(consdata->weights[v] > 0);
6718 SCIP_CALL( delCoefPos(scip, cons, prev) ); /* attention: normally we lose our order */
6719 /* restore order iff necessary */
6720 if( consdata->nvars != v ) /* otherwise the order still stands */
6721 {
6722 assert(prev == 0 || ((prev > 0) && (SCIPvarIsActive(consdata->vars[prev - 1]) || SCIPvarGetStatus(consdata->vars[prev - 1]) == SCIP_VARSTATUS_NEGATED)) );
6723 /* either that was the last pair or both, the negated and "normal" variable in front doesn't match var1, so the order is irrelevant */
6724 if( prev == 0 || (var1 != consdata->vars[prev - 1] && var1 != SCIPvarGetNegatedVar(consdata->vars[prev - 1])) )
6725 --prev;
6726 else /* we need to let v at the same position*/
6727 {
6728 consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6729 /* don't decrease v, the same variable may exist up front */
6730 --prev;
6731 continue;
6732 }
6733 }
6734 }
6735 consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6736 }
6737 v = prev;
6738 --prev;
6739 }
6740
6741 consdata->merged = TRUE;
6742
6743 /* check infeasibility */
6744 if( consdata->onesweightsum > consdata->capacity )
6745 {
6746 SCIPdebugMsg(scip, "merge multiples detected cutoff.\n");
6747 *cutoff = TRUE;
6748 return SCIP_OKAY;
6749 }
6750
6751 return SCIP_OKAY;
6752}
6753
6754/** in case the knapsack constraint is independent of every else, solve the knapsack problem (exactly) and apply the
6755 * fixings (dual reductions)
6756 */
6757static
6759 SCIP* scip, /**< SCIP data structure */
6760 SCIP_CONS* cons, /**< knapsack constraint */
6761 int* nfixedvars, /**< pointer to count number of fixings */
6762 int* ndelconss, /**< pointer to count number of deleted constraints */
6763 SCIP_Bool* deleted /**< pointer to store if the constraint is deleted */
6764 )
6765{
6766 SCIP_CONSDATA* consdata;
6767 SCIP_VAR** vars;
6768 SCIP_Real* profits;
6769 int* solitems;
6770 int* nonsolitems;
6771 int* items;
6772 SCIP_Real solval;
6773 SCIP_Bool infeasible;
6774 SCIP_Bool tightened;
6775 SCIP_Bool applicable;
6776 int nsolitems;
6777 int nnonsolitems;
6778 int nvars;
6779 int v;
6780
6782
6783 /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
6784 * use the locks to decide for a dual reduction using this constraint; for example after a restart the cuts which are
6785 * added to the problems have the check flag set to FALSE
6786 */
6787 if( !SCIPconsIsChecked(cons) )
6788 return SCIP_OKAY;
6789
6790 consdata = SCIPconsGetData(cons);
6791 assert(consdata != NULL);
6792
6793 nvars = consdata->nvars;
6794 vars = consdata->vars;
6795
6798 SCIP_CALL( SCIPallocBufferArray(scip, &solitems, nvars) );
6799 SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, nvars) );
6800
6801 applicable = TRUE;
6802
6803 /* check if we can apply the dual reduction; this can be done if the knapsack has the only locks on this constraint;
6804 * collect object values which are the profits of the knapsack problem
6805 */
6806 for( v = 0; v < nvars; ++v )
6807 {
6808 SCIP_VAR* var;
6809 SCIP_Bool negated;
6810
6811 var = vars[v];
6812 assert(var != NULL);
6813
6814 /* the variable should not be (globally) fixed */
6816
6819 {
6820 applicable = FALSE;
6821 break;
6822 }
6823
6824 negated = FALSE;
6825
6826 /* get the active variable */
6827 SCIP_CALL( SCIPvarGetProbvarBinary(&var, &negated) );
6829
6830 if( negated )
6831 profits[v] = SCIPvarGetObj(var);
6832 else
6833 profits[v] = -SCIPvarGetObj(var);
6834
6835 SCIPdebugMsg(scip, "variable <%s> -> item size %" SCIP_LONGINT_FORMAT ", profit <%g>\n",
6836 SCIPvarGetName(vars[v]), consdata->weights[v], profits[v]);
6837 items[v] = v;
6838 }
6839
6840 if( applicable )
6841 {
6842 SCIP_Bool success;
6843
6844 SCIPdebugMsg(scip, "the knapsack constraint <%s> is independent to rest of the problem\n", SCIPconsGetName(cons));
6846
6847 /* solve knapsack problem exactly */
6848 SCIP_CALL( SCIPsolveKnapsackExactly(scip, consdata->nvars, consdata->weights, profits, consdata->capacity,
6849 items, solitems, nonsolitems, &nsolitems, &nnonsolitems, &solval, &success) );
6850
6851 if( success )
6852 {
6853 SCIP_VAR* var;
6854
6855 /* apply solution of the knapsack as dual reductions */
6856 for( v = 0; v < nsolitems; ++v )
6857 {
6858 var = vars[solitems[v]];
6859 assert(var != NULL);
6860
6861 SCIPdebugMsg(scip, "variable <%s> only locked up in knapsack constraints: dual presolve <%s>[%.15g,%.15g] >= 1.0\n",
6863 SCIP_CALL( SCIPtightenVarLb(scip, var, 1.0, TRUE, &infeasible, &tightened) );
6864 assert(!infeasible);
6865 assert(tightened);
6866 (*nfixedvars)++;
6867 }
6868
6869 for( v = 0; v < nnonsolitems; ++v )
6870 {
6871 var = vars[nonsolitems[v]];
6872 assert(var != NULL);
6873
6874 SCIPdebugMsg(scip, "variable <%s> has no down locks: dual presolve <%s>[%.15g,%.15g] <= 0.0\n",
6876 SCIP_CALL( SCIPtightenVarUb(scip, var, 0.0, TRUE, &infeasible, &tightened) );
6877 assert(!infeasible);
6878 assert(tightened);
6879 (*nfixedvars)++;
6880 }
6881
6882 SCIP_CALL( SCIPdelCons(scip, cons) );
6883 (*ndelconss)++;
6884 (*deleted) = TRUE;
6885 }
6886 }
6887
6888 SCIPfreeBufferArray(scip, &nonsolitems);
6889 SCIPfreeBufferArray(scip, &solitems);
6890 SCIPfreeBufferArray(scip, &items);
6891 SCIPfreeBufferArray(scip, &profits);
6892
6893 return SCIP_OKAY;
6894}
6895
6896/** check if the knapsack constraint is parallel to objective function; if so update the cutoff bound and avoid that the
6897 * constraint enters the LP by setting the initial and separated flag to FALSE
6898 */
6899static
6901 SCIP* scip, /**< SCIP data structure */
6902 SCIP_CONS* cons, /**< knapsack constraint */
6903 SCIP_CONSHDLRDATA* conshdlrdata /**< knapsack constraint handler data */
6904 )
6905{
6906 SCIP_CONSDATA* consdata;
6907 SCIP_VAR** vars;
6908 SCIP_VAR* var;
6909 SCIP_Real offset;
6910 SCIP_Real scale;
6912 SCIP_Bool applicable;
6913 SCIP_Bool negated;
6914 int nobjvars;
6915 int nvars;
6916 int v;
6917
6918 assert(scip != NULL);
6919 assert(cons != NULL);
6920 assert(conshdlrdata != NULL);
6921
6922 consdata = SCIPconsGetData(cons);
6923 assert(consdata != NULL);
6924
6925 nvars = consdata->nvars;
6926 nobjvars = SCIPgetNObjVars(scip);
6927
6928 /* check if the knapsack constraints has the same number of variables as the objective function and if the initial
6929 * and/or separated flag is set to FALSE
6930 */
6931 if( nvars != nobjvars || (!SCIPconsIsInitial(cons) && !SCIPconsIsSeparated(cons)) )
6932 return SCIP_OKAY;
6933
6934 /* There are no variables in the ojective function and in the constraint. Thus, the constraint is redundant. Since we
6935 * have a pure feasibility problem, we do not want to set a cutoff or lower bound.
6936 */
6937 if( nobjvars == 0 )
6938 return SCIP_OKAY;
6939
6940 vars = consdata->vars;
6941 assert(vars != NULL);
6942
6943 applicable = TRUE;
6944 offset = 0.0;
6945 scale = 1.0;
6946
6947 for( v = 0; v < nvars && applicable; ++v )
6948 {
6949 negated = FALSE;
6950 var = vars[v];
6951 assert(var != NULL);
6952
6953 if( SCIPvarIsNegated(var) )
6954 {
6955 negated = TRUE;
6957 assert(var != NULL);
6958 }
6959
6961
6962 /* if a variable has a zero objective coefficient the knapsack constraint is not parallel to objective function */
6963 if( SCIPisZero(scip, objval) )
6964 applicable = FALSE;
6965 else
6966 {
6967 SCIP_Real weight;
6968
6969 weight = (SCIP_Real)consdata->weights[v];
6970
6971 if( negated )
6972 {
6973 if( v == 0 )
6974 {
6975 /* the first variable defines the scale */
6976 scale = weight / -objval;
6977
6978 offset += weight;
6979 }
6980 else if( SCIPisEQ(scip, -objval * scale, weight) )
6981 offset += weight;
6982 else
6983 applicable = FALSE;
6984 }
6985 else if( v == 0 )
6986 {
6987 /* the first variable define the scale */
6988 scale = weight / objval;
6989 }
6990 else if( !SCIPisEQ(scip, objval * scale, weight) )
6991 applicable = FALSE;
6992 }
6993 }
6994
6995 if( applicable )
6996 {
6997 if( SCIPisPositive(scip, scale) && conshdlrdata->detectcutoffbound )
6998 {
6999 SCIP_Real cutoffbound;
7000
7001 /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
7004
7005 cutoffbound = (consdata->capacity - offset) / scale;
7006
7007 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
7008 SCIPconsGetName(cons), cutoffbound);
7009
7010 /* increase the cutoff bound value by an epsilon to ensue that solution with the value of the cutoff bound are
7011 * still excepted
7012 */
7013 cutoffbound += SCIPcutoffbounddelta(scip);
7014
7015 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
7016 SCIPconsGetName(cons), cutoffbound);
7017
7018 if( cutoffbound < SCIPgetCutoffbound(scip) )
7019 {
7020 SCIPdebugMsg(scip, "update cutoff bound <%g>\n", cutoffbound);
7021
7022 SCIP_CALL( SCIPupdateCutoffbound(scip, cutoffbound) );
7023 }
7024 else
7025 {
7026 /* in case the cutoff bound is worse then currently known one we avoid additionaly enforcement and
7027 * propagation
7028 */
7031 }
7032 }
7033 else if( SCIPisNegative(scip, scale) && conshdlrdata->detectlowerbound )
7034 {
7035 SCIP_Real lowerbound;
7036
7037 /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
7040
7041 lowerbound = (consdata->capacity - offset) / scale;
7042
7043 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a lower bound <%g>\n",
7044 SCIPconsGetName(cons), lowerbound);
7045
7047 }
7048 }
7049
7050 return SCIP_OKAY;
7051}
7052
7053/** sort the variables and weights w.r.t. the clique partition; thereby ensure the current order of the variables when a
7054 * weight of one variable is greater or equal another weight and both variables are in the same cliques */
7055static
7057 SCIP* scip, /**< SCIP data structure */
7058 SCIP_CONSDATA* consdata, /**< knapsack constraint data */
7059 SCIP_VAR** vars, /**< array for sorted variables */
7060 SCIP_Longint* weights, /**< array for sorted weights */
7061 int* cliquestartposs, /**< starting position array for each clique */
7062 SCIP_Bool usenegatedclique /**< should negated or normal clique partition be used */
7063 )
7064{
7065 SCIP_VAR** origvars;
7066 int norigvars;
7067 SCIP_Longint* origweights;
7068 int* cliquepartition;
7069 int ncliques;
7070
7071 SCIP_VAR*** varpointers;
7072 SCIP_Longint** weightpointers;
7073 int* cliquecount;
7074
7075 int nextpos;
7076 int c;
7077 int v;
7078
7079 assert(scip != NULL);
7080 assert(consdata != NULL);
7081 assert(vars != NULL);
7082 assert(weights != NULL);
7083 assert(cliquestartposs != NULL);
7084
7085 origweights = consdata->weights;
7086 origvars = consdata->vars;
7087 norigvars = consdata->nvars;
7088
7089 assert(origvars != NULL || norigvars == 0);
7090 assert(origweights != NULL || norigvars == 0);
7091
7092 if( norigvars == 0 )
7093 return SCIP_OKAY;
7094
7095 if( usenegatedclique )
7096 {
7097 assert(consdata->negcliquepartitioned);
7098
7099 cliquepartition = consdata->negcliquepartition;
7100 ncliques = consdata->nnegcliques;
7101 }
7102 else
7103 {
7104 assert(consdata->cliquepartitioned);
7105
7106 cliquepartition = consdata->cliquepartition;
7107 ncliques = consdata->ncliques;
7108 }
7109
7110 assert(cliquepartition != NULL);
7111 assert(ncliques > 0);
7112
7113 /* we first count all clique items and alloc temporary memory for a bucket sort */
7114 SCIP_CALL( SCIPallocBufferArray(scip, &cliquecount, ncliques) );
7115 BMSclearMemoryArray(cliquecount, ncliques);
7116
7117 /* first we count for each clique the number of elements */
7118 for( v = norigvars - 1; v >= 0; --v )
7119 {
7120 assert(0 <= cliquepartition[v] && cliquepartition[v] < ncliques);
7121 ++(cliquecount[cliquepartition[v]]);
7122 }
7123
7124 /*@todo: maybe it is better to put largest cliques up front */
7125
7126#ifndef NDEBUG
7127 BMSclearMemoryArray(vars, norigvars);
7128 BMSclearMemoryArray(weights, norigvars);
7129#endif
7130 SCIP_CALL( SCIPallocBufferArray(scip, &varpointers, ncliques) );
7131 SCIP_CALL( SCIPallocBufferArray(scip, &weightpointers, ncliques) );
7132
7133 nextpos = 0;
7134 /* now we initialize all start pointers for each clique, so they will be ordered */
7135 for( c = 0; c < ncliques; ++c )
7136 {
7137 /* to reach the goal that all variables of each clique will be standing next to each other we will initialize the
7138 * starting pointers for each clique by adding the number of each clique to the last clique starting pointer
7139 * e.g. clique1 has 4 elements and clique2 has 3 elements the the starting pointer for clique1 will be the pointer
7140 * to vars[0], the starting pointer to clique2 will be the pointer to vars[4] and to clique3 it will be
7141 * vars[7]
7142 *
7143 */
7144 varpointers[c] = (SCIP_VAR**) (vars + nextpos);
7145 cliquestartposs[c] = nextpos;
7146 weightpointers[c] = (SCIP_Longint*) (weights + nextpos);
7147 assert(cliquecount[c] > 0);
7148 nextpos += cliquecount[c];
7149 assert(nextpos > 0);
7150 }
7151 assert(nextpos == norigvars);
7152 cliquestartposs[c] = nextpos;
7153
7154 /* now we copy all variable and weights to the right order */
7155 for( v = 0; v < norigvars; ++v )
7156 {
7157 *(varpointers[cliquepartition[v]]) = origvars[v]; /*lint !e613*/
7158 ++(varpointers[cliquepartition[v]]);
7159 *(weightpointers[cliquepartition[v]]) = origweights[v]; /*lint !e613*/
7160 ++(weightpointers[cliquepartition[v]]);
7161 }
7162#ifndef NDEBUG
7163 for( v = 0; v < norigvars; ++v )
7164 {
7165 assert(vars[v] != NULL);
7166 assert(weights[v] > 0);
7167 }
7168#endif
7169
7170 /* free temporary memory */
7171 SCIPfreeBufferArray(scip, &weightpointers);
7172 SCIPfreeBufferArray(scip, &varpointers);
7173 SCIPfreeBufferArray(scip, &cliquecount);
7174
7175 return SCIP_OKAY;
7176}
7177
7178/** deletes all fixed variables from knapsack constraint, and replaces variables with binary representatives */
7179static
7181 SCIP* scip, /**< SCIP data structure */
7182 SCIP_CONS* cons, /**< knapsack constraint */
7183 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off, or NULL if this
7184 * information is not needed; in this case, we apply all fixings
7185 * instead of stopping after the first infeasible one */
7186 )
7187{
7188 SCIP_CONSDATA* consdata;
7189 int v;
7190
7191 assert(scip != NULL);
7192 assert(cons != NULL);
7193
7194 consdata = SCIPconsGetData(cons);
7195 assert(consdata != NULL);
7196 assert(consdata->nvars == 0 || consdata->vars != NULL);
7197
7198 if( cutoff != NULL )
7199 *cutoff = FALSE;
7200
7201 SCIPdebugMsg(scip, "apply fixings:\n");
7203
7204 /* check infeasibility */
7205 if ( consdata->onesweightsum > consdata->capacity )
7206 {
7207 SCIPdebugMsg(scip, "apply fixings detected cutoff.\n");
7208
7209 if( cutoff != NULL )
7210 *cutoff = TRUE;
7211
7212 return SCIP_OKAY;
7213 }
7214
7215 /* all multi-aggregations should be resolved */
7216 consdata->existmultaggr = FALSE;
7217
7218 v = 0;
7219 while( v < consdata->nvars )
7220 {
7221 SCIP_VAR* var;
7222
7223 var = consdata->vars[v];
7225
7226 if( SCIPvarGetLbGlobal(var) > 0.5 )
7227 {
7229 consdata->capacity -= consdata->weights[v];
7230 SCIP_CALL( delCoefPos(scip, cons, v) );
7231 consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
7232 }
7233 else if( SCIPvarGetUbGlobal(var) < 0.5 )
7234 {
7236 SCIP_CALL( delCoefPos(scip, cons, v) );
7237 }
7238 else
7239 {
7240 SCIP_VAR* repvar;
7241 SCIP_VAR* negvar;
7242 SCIP_VAR* workvar;
7243 SCIP_Longint weight;
7244 SCIP_Bool negated;
7245
7246 weight = consdata->weights[v];
7247
7248 /* get binary representative of variable */
7249 SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &repvar, &negated) );
7250 assert(repvar != NULL);
7251
7252 /* check for multi-aggregation */
7253 if( SCIPvarIsNegated(repvar) )
7254 {
7255 workvar = SCIPvarGetNegatedVar(repvar);
7256 assert(workvar != NULL);
7257 negated = TRUE;
7258 }
7259 else
7260 {
7261 workvar = repvar;
7262 negated = FALSE;
7263 }
7264
7265 /* @todo maybe resolve the problem that the eliminating of the multi-aggregation leads to a non-knapsack
7266 * constraint (converting into a linear constraint), for example the multi-aggregation consist of a non-binary
7267 * variable or due to resolving now their are non-integral coefficients or a non-integral capacity
7268 *
7269 * If repvar is not negated so workvar = repvar, otherwise workvar = 1 - repvar. This means,
7270 * weight * workvar = weight * (a_1*y_1 + ... + a_n*y_n + c)
7271 *
7272 * The explanation for the following block:
7273 * 1a) If repvar is a multi-aggregated variable weight * repvar should be replaced by
7274 * weight * (a_1*y_1 + ... + a_n*y_n + c).
7275 * 1b) If repvar is a negated variable of a multi-aggregated variable weight * repvar should be replaced by
7276 * weight - weight * (a_1*y_1 + ... + a_n*y_n + c), for better further use here we switch the sign of weight
7277 * so now we have the replacement -weight + weight * (a_1*y_1 + ... + a_n*y_n + c).
7278 * 2) For all replacement variable we check:
7279 * 2a) weight * a_i < 0 than we add -weight * a_i * y_i_neg to the constraint and adjust the capacity through
7280 * capacity -= weight * a_i caused by the negation of y_i.
7281 * 2b) weight * a_i >= 0 than we add weight * a_i * y_i to the constraint.
7282 * 3a) If repvar was not negated we need to subtract weight * c from capacity.
7283 * 3b) If repvar was negated we need to subtract weight * (c - 1) from capacity(note we switched the sign of
7284 * weight in this case.
7285 */
7287 {
7288 SCIP_VAR** aggrvars;
7289 SCIP_Real* aggrscalars;
7290 SCIP_Real aggrconst;
7291 int naggrvars;
7292 int i;
7293
7295 naggrvars = SCIPvarGetMultaggrNVars(workvar);
7296 aggrvars = SCIPvarGetMultaggrVars(workvar);
7297 aggrscalars = SCIPvarGetMultaggrScalars(workvar);
7298 aggrconst = SCIPvarGetMultaggrConstant(workvar);
7299 assert((aggrvars != NULL && aggrscalars != NULL) || naggrvars == 0);
7300
7301 if( !SCIPisIntegral(scip, weight * aggrconst) )
7302 {
7303 SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrconst = %g\n", weight*aggrconst);
7304 return SCIP_ERROR;
7305 }
7306
7307 /* if workvar was negated, we have to flip the weight */
7308 if( negated )
7309 weight *= -1;
7310
7311 for( i = naggrvars - 1; i >= 0; --i )
7312 {
7313 assert(aggrvars != NULL);
7314 assert(aggrscalars != NULL);
7315
7316 if( !SCIPvarIsBinary(aggrvars[i]) )
7317 {
7318 SCIPerrorMessage("try to resolve a multi-aggregation with a non-binary %svariable <%s> with bounds [%g,%g]\n",
7319 SCIPvarIsIntegral(aggrvars[i]) ? "integral " : "", SCIPvarGetName(aggrvars[i]), SCIPvarGetLbGlobal(aggrvars[i]), SCIPvarGetUbGlobal(aggrvars[i]));
7320 return SCIP_ERROR;
7321 }
7322 if( !SCIPisIntegral(scip, weight * aggrscalars[i]) )
7323 {
7324 SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrscalars = %g\n", weight*aggrscalars[i]);
7325 return SCIP_ERROR;
7326 }
7327 /* if the new coefficient is smaller than zero, we need to add the negated variable instead and adjust the capacity */
7328 if( SCIPisNegative(scip, weight * aggrscalars[i]) )
7329 {
7330 SCIP_CALL( SCIPgetNegatedVar(scip, aggrvars[i], &negvar) );
7331 assert(negvar != NULL);
7332 SCIP_CALL( addCoef(scip, cons, negvar, (SCIP_Longint)(SCIPfloor(scip, -weight * aggrscalars[i] + 0.5))) );
7333 consdata->capacity -= (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5));
7334 }
7335 else
7336 {
7337 SCIP_CALL( addCoef(scip, cons, aggrvars[i], (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5))) );
7338 }
7339 }
7340 /* delete old coefficient */
7341 SCIP_CALL( delCoefPos(scip, cons, v) );
7342
7343 /* adjust the capacity with the aggregation constant and if necessary the extra weight through the negation */
7344 if( negated )
7345 consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * (aggrconst - 1) + 0.5);
7346 else
7347 consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * aggrconst + 0.5);
7348
7349 if( consdata->capacity < 0 )
7350 {
7351 if( cutoff != NULL )
7352 {
7353 *cutoff = TRUE;
7354 break;
7355 }
7356 }
7357 }
7358 /* check, if the variable should be replaced with the representative */
7359 else if( repvar != var )
7360 {
7361 /* delete old (aggregated) variable */
7362 SCIP_CALL( delCoefPos(scip, cons, v) );
7363
7364 /* add representative instead */
7365 SCIP_CALL( addCoef(scip, cons, repvar, weight) );
7366 }
7367 else
7368 ++v;
7369 }
7370 }
7371 assert(consdata->onesweightsum == 0);
7372
7373 SCIPdebugMsg(scip, "after applyFixings, before merging:\n");
7375
7376 /* if aggregated variables have been replaced, multiple entries of the same variable are possible and we have to
7377 * clean up the constraint
7378 */
7379 if( cutoff != NULL && !(*cutoff) )
7380 {
7382 SCIPdebugMsg(scip, "after applyFixings and merging:\n");
7384 }
7385
7386 return SCIP_OKAY;
7387}
7388
7389
7390/** propagation method for knapsack constraints */
7391static
7393 SCIP* scip, /**< SCIP data structure */
7394 SCIP_CONS* cons, /**< knapsack constraint */
7395 SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
7396 SCIP_Bool* redundant, /**< pointer to store whether constraint is redundant */
7397 int* nfixedvars, /**< pointer to count number of fixings */
7398 SCIP_Bool usenegatedclique /**< should negated clique information be used */
7399 )
7400{
7401 SCIP_CONSDATA* consdata;
7402 SCIP_Bool infeasible;
7403 SCIP_Bool tightened;
7404 SCIP_Longint* secondmaxweights;
7405 SCIP_Longint minweightsum;
7406 SCIP_Longint residualcapacity;
7407
7408 int nvars;
7409 int i;
7410 int nnegcliques;
7411
7412 SCIP_VAR** myvars;
7413 SCIP_Longint* myweights;
7414 int* cliquestartposs;
7415 int* cliqueendposs;
7416 SCIP_Longint localminweightsum;
7417 SCIP_Bool foundmax;
7418 int c;
7419
7420 assert(scip != NULL);
7421 assert(cons != NULL);
7422 assert(cutoff != NULL);
7423 assert(redundant != NULL);
7424 assert(nfixedvars != NULL);
7425
7426 consdata = SCIPconsGetData(cons);
7427 assert(consdata != NULL);
7428
7429 *cutoff = FALSE;
7430 *redundant = FALSE;
7431
7432 SCIPdebugMsg(scip, "propagating knapsack constraint <%s>\n", SCIPconsGetName(cons));
7433
7434 /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */
7436 {
7437 SCIP_CALL( SCIPincConsAge(scip, cons) );
7438 }
7439
7440#ifndef NDEBUG
7441 /* assert that only active or negated variables are present */
7442 for( i = 0; i < consdata->nvars && consdata->merged; ++i )
7443 {
7444 assert(SCIPvarIsActive(consdata->vars[i]) || SCIPvarIsNegated(consdata->vars[i]) || SCIPvarGetStatus(consdata->vars[i]) == SCIP_VARSTATUS_FIXED);
7445 }
7446#endif
7447
7448 usenegatedclique = usenegatedclique && consdata->merged;
7449
7450 /* init for debugging */
7451 myvars = NULL;
7452 myweights = NULL;
7453 cliquestartposs = NULL;
7454 secondmaxweights = NULL;
7455 minweightsum = 0;
7456 nvars = consdata->nvars;
7457 /* make sure, the items are sorted by non-increasing weight */
7458 sortItems(consdata);
7459
7460 do
7461 {
7462 localminweightsum = 0;
7463
7464 /* (1) compute the minimum weight of the knapsack constraint using negated clique information;
7465 * a negated clique means, that at most one of the clique variables can be zero
7466 * - minweightsum = sum_{negated cliques C} ( sum(wi : i \in C) - W_max(C) ), where W_max(C) is the maximal weight of C
7467 *
7468 * if for i \in C (a negated clique) oneweightsum + minweightsum - wi + W_max(C) > capacity => xi = 1
7469 * since replacing i with the element of maximal weight leads to infeasibility
7470 */
7471 if( usenegatedclique && nvars > 0 )
7472 {
7473 SCIP_CONSHDLRDATA* conshdlrdata;
7474 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7475 assert(conshdlrdata != NULL);
7476
7477 /* compute clique partitions */
7478 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
7479 nnegcliques = consdata->nnegcliques;
7480
7481 /* if we have no real negated cliques we can stop here */
7482 if( nnegcliques == nvars )
7483 {
7484 /* run the standard algorithm that does not involve cliques */
7485 usenegatedclique = FALSE;
7486 break;
7487 }
7488
7489 /* allocate temporary memory and initialize it */
7490 SCIP_CALL( SCIPduplicateBufferArray(scip, &myvars, consdata->vars, nvars) );
7491 SCIP_CALL( SCIPduplicateBufferArray(scip, &myweights, consdata->weights, nvars) ) ;
7492 SCIP_CALL( SCIPallocBufferArray(scip, &cliquestartposs, nnegcliques + 1) );
7493 SCIP_CALL( SCIPallocBufferArray(scip, &cliqueendposs, nnegcliques) );
7494 SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
7495 BMSclearMemoryArray(secondmaxweights, nnegcliques);
7496
7497 /* resort variables to avoid quadratic algorithm later on */
7498 SCIP_CALL( stableSort(scip, consdata, myvars, myweights, cliquestartposs, TRUE) );
7499
7500 /* save the end positions of the cliques because start positions are moved in the following loop */
7501 for( c = 0; c < nnegcliques; ++c )
7502 {
7503 cliqueendposs[c] = cliquestartposs[c+1] - 1;
7504 assert(cliqueendposs[c] - cliquestartposs[c] >= 0);
7505 }
7506
7507 c = 0;
7508 foundmax = FALSE;
7509 i = 0;
7510
7511 while( i < nvars )
7512 {
7513 /* ignore variables of the negated clique which are fixed to one since these are counted in
7514 * consdata->onesweightsum
7515 */
7516
7517 /* if there are only one variable negated cliques left we can stop */
7518 if( nnegcliques - c == nvars - i )
7519 {
7520 minweightsum += localminweightsum;
7521 localminweightsum = 0;
7522 break;
7523 }
7524
7525 /* for summing up the minimum active weights due to cliques we have to omit the biggest weights of each
7526 * clique, we can only skip this clique if this variables is not fixed to zero, otherwise we have to fix all
7527 * other clique variables to one
7528 */
7529 if( cliquestartposs[c] == i )
7530 {
7531 assert(myweights[i] > 0);
7532 ++c;
7533 minweightsum += localminweightsum;
7534 localminweightsum = 0;
7535 foundmax = TRUE;
7536
7537 if( SCIPvarGetLbLocal(myvars[i]) > 0.5 )
7538 foundmax = FALSE;
7539
7540 if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7541 {
7542 ++i;
7543 continue;
7544 }
7545 }
7546
7547 if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7548 {
7549 assert(myweights[i] > 0);
7550
7551 if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7552 {
7553 assert(myweights[i] <= myweights[cliquestartposs[c - 1]]);
7554
7555 if( !foundmax )
7556 {
7557 foundmax = TRUE;
7558
7559 /* overwrite cliquestartpos to the position of the first unfixed variable in this clique */
7560 cliquestartposs[c - 1] = i;
7561 ++i;
7562
7563 continue;
7564 }
7565 /* memorize second max weight for each clique */
7566 if( secondmaxweights[c - 1] == 0 )
7567 secondmaxweights[c - 1] = myweights[i];
7568
7569 localminweightsum += myweights[i];
7570 }
7571 /* we found a fixed variable to zero so all other variables in this negated clique have to be fixed to one */
7572 else
7573 {
7574 int v;
7575 /* fix all other variables of the negated clique to 1 */
7576 for( v = cliquestartposs[c - 1]; v < cliquestartposs[c]; ++v )
7577 {
7578 if( v != i && SCIPvarGetLbLocal(myvars[v]) < 0.5 )
7579 {
7580 SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[v]));
7581 SCIP_CALL( SCIPinferBinvarCons(scip, myvars[v], TRUE, cons, SCIPvarGetIndex(myvars[i]), &infeasible, &tightened) );
7582
7583 if( infeasible )
7584 {
7585 assert( SCIPvarGetUbLocal(myvars[v]) < 0.5 );
7586
7587 /* analyze the infeasibility if conflict analysis is applicable */
7589 {
7590 /* conflict analysis can only be applied in solving stage */
7592
7593 /* initialize the conflict analysis */
7595
7596 /* add the two variables which are fixed to zero within a negated clique */
7598 SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[v]) );
7599
7600 /* start the conflict analysis */
7602 }
7603 *cutoff = TRUE;
7604 break;
7605 }
7606 assert(tightened);
7607 ++(*nfixedvars);
7609 }
7610 }
7611
7612 /* reset local minweightsum for clique because all fixed to one variables are now counted in consdata->onesweightsum */
7613 localminweightsum = 0;
7614 /* we can jump to the end of this clique */
7615 i = cliqueendposs[c - 1];
7616
7617 if( *cutoff )
7618 break;
7619 }
7620 }
7621 ++i;
7622 }
7623 /* add last clique minweightsum */
7624 minweightsum += localminweightsum;
7625
7626 SCIPdebugMsg(scip, "knapsack constraint <%s> has minimum weight sum of <%" SCIP_LONGINT_FORMAT ">\n",
7627 SCIPconsGetName(cons), minweightsum + consdata->onesweightsum );
7628
7629 /* check, if weights of fixed variables don't exceeds knapsack capacity */
7630 if( !(*cutoff) && consdata->capacity >= minweightsum + consdata->onesweightsum )
7631 {
7632 SCIP_Longint maxcliqueweight = -1LL;
7633
7634 /* loop over cliques */
7635 for( c = 0; c < nnegcliques; ++c )
7636 {
7637 SCIP_VAR* maxvar;
7638 SCIP_Bool maxvarfixed;
7639 int endvarposclique;
7640 int startvarposclique;
7641
7642 assert(myvars != NULL);
7643 assert(nnegcliques == consdata->nnegcliques);
7644 assert(myweights != NULL);
7645 assert(secondmaxweights != NULL);
7646 assert(cliquestartposs != NULL);
7647
7648 endvarposclique = cliqueendposs[c];
7649 startvarposclique = cliquestartposs[c];
7650
7651 maxvar = myvars[startvarposclique];
7652
7653 /* no need to process this negated clique because all variables are already fixed (which we detect from a fixed maxvar) */
7654 if( SCIPvarGetUbLocal(maxvar) - SCIPvarGetLbLocal(maxvar) < 0.5 )
7655 continue;
7656
7657 maxcliqueweight = myweights[startvarposclique];
7658 maxvarfixed = FALSE;
7659 /* if the sum of all weights of fixed variables to one plus the minimalweightsum (minimal weight which is already
7660 * used in this knapsack due to negated cliques) plus any weight minus the second largest weight in this clique
7661 * exceeds the capacity the maximum weight variable can be fixed to zero.
7662 */
7663 if( consdata->onesweightsum + minweightsum + (maxcliqueweight - secondmaxweights[c]) > consdata->capacity )
7664 {
7665#ifndef NDEBUG
7666 SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7667#endif
7668 assert(maxcliqueweight >= secondmaxweights[c]);
7669 assert(SCIPvarGetLbLocal(maxvar) < 0.5 && SCIPvarGetUbLocal(maxvar) > 0.5);
7670
7671 SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(maxvar));
7673 SCIP_CALL( SCIPinferBinvarCons(scip, maxvar, FALSE, cons, cliquestartposs[c], &infeasible, &tightened) );
7674 assert(consdata->onesweightsum == oldonesweightsum);
7675 assert(!infeasible);
7676 assert(tightened);
7677 (*nfixedvars)++;
7678 maxvarfixed = TRUE;
7679 }
7680 /* the remaining cliques are singletons such that all subsequent variables have a weight that
7681 * fits into the knapsack
7682 */
7683 else if( nnegcliques - c == nvars - startvarposclique )
7684 break;
7685 /* early termination of the remaining loop because no further variable fixings are possible:
7686 *
7687 * the gain in any of the following negated cliques (the additional term if the maximum weight variable was set to 1, and the second
7688 * largest was set to 0) does not suffice to infer additional variable fixings because
7689 *
7690 * - the cliques are sorted by decreasing maximum weight -> for all c' >= c: maxweights[c'] <= maxcliqueweight
7691 * - their second largest elements are at least as large as the smallest weight of the knapsack
7692 */
7693 else if( consdata->onesweightsum + minweightsum + (maxcliqueweight - consdata->weights[nvars - 1]) <= consdata->capacity )
7694 break;
7695
7696 /* loop over items with non-maximal weight (omitting the first position) */
7697 for( i = endvarposclique; i > startvarposclique; --i )
7698 {
7699 /* there should be no variable fixed to 0 between startvarposclique + 1 and endvarposclique unless we
7700 * messed up the clique preprocessing in the previous loop to filter those variables out */
7701 assert(SCIPvarGetUbLocal(myvars[i]) > 0.5);
7702
7703 /* only check variables of negated cliques for which no variable is locally fixed */
7704 if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7705 {
7706 assert(maxcliqueweight >= myweights[i]);
7707 assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
7708
7709 /* we fix the members of this clique with non-maximal weight in two cases to 1:
7710 *
7711 * the maxvar was already fixed to 0 because it has a huge gain.
7712 *
7713 * if for i \in C (a negated clique) onesweightsum - wi + W_max(c) > capacity => xi = 1
7714 * since replacing i with the element of maximal weight leads to infeasibility */
7715 if( maxvarfixed || consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity )
7716 {
7717#ifndef NDEBUG
7718 SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7719#endif
7720 SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[i]));
7721 SCIP_CALL( SCIPinferBinvarCons(scip, myvars[i], TRUE, cons, -i, &infeasible, &tightened) );
7722 assert(consdata->onesweightsum == oldonesweightsum + myweights[i]);
7723 assert(!infeasible);
7724 assert(tightened);
7725 ++(*nfixedvars);
7727
7728 /* update minweightsum because now the variable is fixed to one and its weight is counted by
7729 * consdata->onesweightsum
7730 */
7731 minweightsum -= myweights[i];
7732 assert(minweightsum >= 0);
7733 }
7734 else
7735 break;
7736 }
7737 }
7738#ifndef NDEBUG
7739 /* in debug mode, we assert that we did not miss possible fixings by the break above */
7740 for( ; i > startvarposclique; --i )
7741 {
7742 SCIP_Bool varisfixed = SCIPvarGetUbLocal(myvars[i]) - SCIPvarGetLbLocal(myvars[i]) < 0.5;
7743 SCIP_Bool exceedscapacity = consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity;
7744
7745 assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
7746 assert(varisfixed || !exceedscapacity);
7747 }
7748#endif
7749 }
7750 }
7751 SCIPfreeBufferArray(scip, &secondmaxweights);
7752 SCIPfreeBufferArray(scip, &cliqueendposs);
7753 SCIPfreeBufferArray(scip, &cliquestartposs);
7754 SCIPfreeBufferArray(scip, &myweights);
7755 SCIPfreeBufferArray(scip, &myvars);
7756 }
7757
7758 assert(consdata->negcliquepartitioned || minweightsum == 0);
7759 }
7760 while( FALSE );
7761
7762 assert(usenegatedclique || minweightsum == 0);
7763 /* check, if weights of fixed variables already exceed knapsack capacity */
7764 if( consdata->capacity < minweightsum + consdata->onesweightsum )
7765 {
7766 SCIPdebugMsg(scip, " -> cutoff - fixed weight: %" SCIP_LONGINT_FORMAT ", capacity: %" SCIP_LONGINT_FORMAT " \n",
7767 consdata->onesweightsum, consdata->capacity);
7768
7770 *cutoff = TRUE;
7771
7772 /* analyze the cutoff in SOLVING stage and if conflict analysis is turned on */
7774 {
7775 /* start conflict analysis with the fixed-to-one variables, add only as many as needed to exceed the capacity */
7776 SCIP_Longint weight;
7777
7778 weight = 0;
7779
7781
7782 for( i = 0; i < nvars && weight <= consdata->capacity; i++ )
7783 {
7784 if( SCIPvarGetLbLocal(consdata->vars[i]) > 0.5)
7785 {
7786 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
7787 weight += consdata->weights[i];
7788 }
7789 }
7790
7792 }
7793
7794 return SCIP_OKAY;
7795 }
7796
7797 /* the algorithm below is a special case of propagation involving negated cliques */
7798 if( !usenegatedclique )
7799 {
7800 assert(consdata->sorted);
7801 residualcapacity = consdata->capacity - consdata->onesweightsum;
7802
7803 /* fix all variables to zero, that don't fit into the knapsack anymore */
7804 for( i = 0; i < nvars && consdata->weights[i] > residualcapacity; ++i )
7805 {
7806 /* if all weights of fixed variables to one plus any weight exceeds the capacity the variables have to be fixed
7807 * to zero
7808 */
7809 if( SCIPvarGetLbLocal(consdata->vars[i]) < 0.5 )
7810 {
7811 if( SCIPvarGetUbLocal(consdata->vars[i]) > 0.5 )
7812 {
7813 assert(consdata->onesweightsum + consdata->weights[i] > consdata->capacity);
7814 SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(consdata->vars[i]));
7816 SCIP_CALL( SCIPinferBinvarCons(scip, consdata->vars[i], FALSE, cons, i, &infeasible, &tightened) );
7817 assert(!infeasible);
7818 assert(tightened);
7819 (*nfixedvars)++;
7820 }
7821 }
7822 }
7823 }
7824
7825 /* check if the knapsack is now redundant */
7826 if( !SCIPconsIsModifiable(cons) )
7827 {
7828 SCIP_Longint unfixedweightsum = consdata->onesweightsum;
7829
7830 /* sum up the weights of all unfixed variables, plus the weight sum of all variables fixed to one already */
7831 for( i = 0; i < nvars; ++i )
7832 {
7833 if( SCIPvarGetLbLocal(consdata->vars[i]) + 0.5 < SCIPvarGetUbLocal(consdata->vars[i]) )
7834 {
7835 unfixedweightsum += consdata->weights[i];
7836
7837 /* the weight sum is larger than the capacity, so the constraint is not redundant */
7838 if( unfixedweightsum > consdata->capacity )
7839 return SCIP_OKAY;
7840 }
7841 }
7842 /* we summed up all (unfixed and fixed to one) weights and did not exceed the capacity, so the constraint is redundant */
7843 SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", unfixedweightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
7844 SCIPconsGetName(cons), consdata->weightsum, unfixedweightsum, consdata->capacity);
7846 *redundant = TRUE;
7847 }
7848
7849 return SCIP_OKAY;
7850}
7851
7852/** all but one variable fit into the knapsack constraint, so we can upgrade this constraint to an logicor constraint
7853 * containing all negated variables of this knapsack constraint
7854 */
7855static
7857 SCIP* scip, /**< SCIP data structure */
7858 SCIP_CONS* cons, /**< knapsack constraint */
7859 int* ndelconss, /**< pointer to store the amount of deleted constraints */
7860 int* naddconss /**< pointer to count number of added constraints */
7861 )
7862{
7863 SCIP_CONS* newcons;
7864 SCIP_CONSDATA* consdata;
7865
7866 assert(scip != NULL);
7867 assert(cons != NULL);
7868 assert(ndelconss != NULL);
7869 assert(naddconss != NULL);
7870
7871 consdata = SCIPconsGetData(cons);
7872 assert(consdata != NULL);
7873 assert(consdata->nvars > 1);
7874
7875 /* if the knapsack constraint consists only of two variables, we can upgrade it to a set-packing constraint */
7876 if( consdata->nvars == 2 )
7877 {
7878 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
7879
7880 SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
7884 SCIPconsIsStickingAtNode(cons)) );
7885 }
7886 /* if the knapsack constraint consists of at least three variables, we can upgrade it to a logicor constraint
7887 * containing all negated variables of the knapsack
7888 */
7889 else
7890 {
7891 SCIP_VAR** consvars;
7892
7893 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a logicor constraint", SCIPconsGetName(cons));
7894
7895 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, consdata->nvars) );
7896 SCIP_CALL( SCIPgetNegatedVars(scip, consdata->nvars, consdata->vars, consvars) );
7897
7898 SCIP_CALL( SCIPcreateConsLogicor(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consvars,
7902 SCIPconsIsStickingAtNode(cons)) );
7903
7904 SCIPfreeBufferArray(scip, &consvars);
7905 }
7906
7907 /* add the upgraded constraint to the problem */
7908 SCIP_CALL( SCIPaddConsUpgrade(scip, cons, &newcons) );
7909 ++(*naddconss);
7910
7911 /* remove the underlying constraint from the problem */
7912 SCIP_CALL( SCIPdelCons(scip, cons) );
7913 ++(*ndelconss);
7914
7915 return SCIP_OKAY;
7916}
7917
7918/** delete redundant variables
7919 *
7920 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
7921 *
7922 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
7923 * => x4, x5 always fits into the knapsack, so we can delete them
7924 *
7925 * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
7926 * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
7927 */
7928static
7930 SCIP* scip, /**< SCIP data structure */
7931 SCIP_CONS* cons, /**< knapsack constraint */
7932 SCIP_Longint frontsum, /**< sum of front items which fit if we try to take from the first till the last */
7933 int splitpos, /**< split position till when all front items are fitting, splitpos is the
7934 * first which did not fit */
7935 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
7936 int* nchgsides, /**< pointer to store the amount of changed sides */
7937 int* naddconss /**< pointer to count number of added constraints */
7938 )
7939{
7940 SCIP_CONSHDLRDATA* conshdlrdata;
7941 SCIP_CONSDATA* consdata;
7942 SCIP_VAR** vars;
7943 SCIP_Longint* weights;
7944 SCIP_Longint capacity;
7945 SCIP_Longint gcd;
7946 int nvars;
7947 int w;
7948
7949 assert(scip != NULL);
7950 assert(cons != NULL);
7951 assert(nchgcoefs != NULL);
7952 assert(nchgsides != NULL);
7953 assert(naddconss != NULL);
7954
7955 consdata = SCIPconsGetData(cons);
7956 assert(consdata != NULL);
7957 assert(0 < frontsum && frontsum < consdata->weightsum);
7958 assert(0 < splitpos && splitpos < consdata->nvars);
7959
7960 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7961 assert(conshdlrdata != NULL);
7962
7963 vars = consdata->vars;
7964 weights = consdata->weights;
7965 nvars = consdata->nvars;
7966 capacity = consdata->capacity;
7967
7968 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
7969 * weight must not be sorted by their index
7970 */
7971#ifndef NDEBUG
7972 for( w = nvars - 1; w > 0; --w )
7973 assert(weights[w] <= weights[w-1]);
7974#endif
7975
7976 /* if there are no variables rear to splitpos, the constraint has no redundant variables */
7977 if( consdata->nvars - 1 == splitpos )
7978 return SCIP_OKAY;
7979
7980 assert(frontsum + weights[splitpos] > capacity);
7981
7982 /* detect redundant variables */
7983 if( consdata->weightsum - weights[splitpos] <= capacity )
7984 {
7985 /* all rear items are redundant, because leaving one item in front and incl. of splitpos out the rear itmes always
7986 * fit
7987 */
7988 SCIPdebugMsg(scip, "Found redundant variables in constraint <%s>.\n", SCIPconsGetName(cons));
7989
7990 /* delete items and update capacity */
7991 for( w = nvars - 1; w > splitpos; --w )
7992 {
7993 consdata->capacity -= weights[w];
7994 SCIP_CALL( delCoefPos(scip, cons, w) );
7995 }
7996 assert(w == splitpos);
7997
7998 ++(*nchgsides);
7999 *nchgcoefs += (nvars - splitpos);
8000
8001 /* division by greatest common divisor */
8002 gcd = weights[w];
8003 for( ; w >= 0 && gcd > 1; --w )
8004 {
8005 gcd = SCIPcalcGreComDiv(gcd, weights[w]);
8006 }
8007
8008 /* normalize if possible */
8009 if( gcd > 1 )
8010 {
8011 for( w = splitpos; w >= 0; --w )
8012 {
8013 consdataChgWeight(consdata, w, weights[w]/gcd);
8014 }
8015 (*nchgcoefs) += nvars;
8016
8017 consdata->capacity /= gcd;
8018 ++(*nchgsides);
8019 }
8020
8021 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8022 * weight must not be sorted by their index
8023 */
8024#ifndef NDEBUG
8025 for( w = consdata->nvars - 1; w > 0; --w )
8026 assert(weights[w] <= weights[w - 1]);
8027#endif
8028 }
8029 /* rear items can only be redundant, when the sum is smaller to the weight at splitpos and all rear items would
8030 * always fit into the knapsack, therefor the item directly after splitpos needs to be smaller than the one at
8031 * splitpos and needs to fit into the knapsack
8032 */
8033 else if( conshdlrdata->disaggregation && frontsum + weights[splitpos + 1] <= capacity )
8034 {
8035 int* clqpart;
8036 int nclq;
8037 int len;
8038
8039 len = nvars - (splitpos + 1);
8040 /* allocate temporary memory */
8041 SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
8042
8043 /* calculate clique partition */
8044 SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[splitpos+1]), len, &conshdlrdata->probtoidxmap, &conshdlrdata->probtoidxmapsize, clqpart, &nclq) );
8045
8046 /* check if we found at least one clique */
8047 if( nclq < len )
8048 {
8049 SCIP_Longint maxactduetoclq;
8050 int cliquenum;
8051
8052 maxactduetoclq = 0;
8053 cliquenum = 0;
8054
8055 /* calculate maximum activity due to cliques */
8056 for( w = 0; w < len; ++w )
8057 {
8058 assert(clqpart[w] >= 0 && clqpart[w] <= w);
8059 if( clqpart[w] == cliquenum )
8060 {
8061 maxactduetoclq += weights[w + splitpos + 1];
8062 ++cliquenum;
8063 }
8064 }
8065
8066 /* all rear items are redundant due to clique information, if maxactduetoclq is smaller than the weight before,
8067 * so delete them and create for all clique the corresponding clique constraints and update the capacity
8068 */
8069 if( frontsum + maxactduetoclq <= capacity )
8070 {
8071 SCIP_VAR** clqvars;
8072 int nclqvars;
8073 int c;
8074
8075 assert(maxactduetoclq < weights[splitpos]);
8076
8077 SCIPdebugMsg(scip, "Found redundant variables in constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8078
8079 /* allocate temporary memory */
8080 SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, len - nclq + 1) );
8081
8082 for( c = 0; c < nclq; ++c )
8083 {
8084 nclqvars = 0;
8085 for( w = 0; w < len; ++w )
8086 {
8087 if( clqpart[w] == c )
8088 {
8089 clqvars[nclqvars] = vars[w + splitpos + 1];
8090 ++nclqvars;
8091 }
8092 }
8093
8094 /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8095 if( nclqvars > 1 )
8096 {
8097 SCIP_CONS* cliquecons;
8098 char name[SCIP_MAXSTRLEN];
8099
8100 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8101 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8105 SCIPconsIsStickingAtNode(cons)) );
8106
8107 /* add the special constraint to the problem */
8108 SCIPdebugMsg(scip, " -> adding clique constraint: ");
8109 SCIPdebugPrintCons(scip, cliquecons, NULL);
8110 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8111 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8112 ++(*naddconss);
8113 }
8114 }
8115
8116 /* delete items and update capacity */
8117 for( w = nvars - 1; w > splitpos; --w )
8118 {
8119 SCIP_CALL( delCoefPos(scip, cons, w) );
8120 ++(*nchgcoefs);
8121 }
8122 consdata->capacity -= maxactduetoclq;
8123 assert(frontsum <= consdata->capacity);
8124 ++(*nchgsides);
8125
8126 assert(w == splitpos);
8127
8128 /* renew weights pointer */
8129 weights = consdata->weights;
8130
8131 /* division by greatest common divisor */
8132 gcd = weights[w];
8133 for( ; w >= 0 && gcd > 1; --w )
8134 {
8135 gcd = SCIPcalcGreComDiv(gcd, weights[w]);
8136 }
8137
8138 /* normalize if possible */
8139 if( gcd > 1 )
8140 {
8141 for( w = splitpos; w >= 0; --w )
8142 {
8143 consdataChgWeight(consdata, w, weights[w]/gcd);
8144 }
8145 (*nchgcoefs) += nvars;
8146
8147 consdata->capacity /= gcd;
8148 ++(*nchgsides);
8149 }
8150
8151 /* free temporary memory */
8152 SCIPfreeBufferArray(scip, &clqvars);
8153
8154 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8155 * weight must not be sorted by their index
8156 */
8157#ifndef NDEBUG
8158 for( w = consdata->nvars - 1; w > 0; --w )
8159 assert(weights[w] <= weights[w - 1]);
8160#endif
8161 }
8162 }
8163
8164 /* free temporary memory */
8165 SCIPfreeBufferArray(scip, &clqpart);
8166 }
8167
8168 return SCIP_OKAY;
8169}
8170
8171/* detect redundant variables which always fits into the knapsack
8172 *
8173 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
8174 *
8175 * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
8176 * => x4, x5 always fits into the knapsack, so we can delete them
8177 *
8178 * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
8179 * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
8180 */
8181static
8183 SCIP* scip, /**< SCIP data structure */
8184 SCIP_CONS* cons, /**< knapsack constraint */
8185 int* ndelconss, /**< pointer to store the amount of deleted constraints */
8186 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8187 int* nchgsides, /**< pointer to store the amount of changed sides */
8188 int* naddconss /**< pointer to count number of added constraints */
8189 )
8190{
8191 SCIP_CONSHDLRDATA* conshdlrdata;
8192 SCIP_CONSDATA* consdata;
8193 SCIP_VAR** vars;
8194 SCIP_Longint* weights;
8195 SCIP_Longint capacity;
8196 SCIP_Longint sum;
8197 int nvars;
8198 int v;
8199 int w;
8200
8201 assert(scip != NULL);
8202 assert(cons != NULL);
8203 assert(ndelconss != NULL);
8204 assert(nchgcoefs != NULL);
8205 assert(nchgsides != NULL);
8206 assert(naddconss != NULL);
8207
8208 consdata = SCIPconsGetData(cons);
8209 assert(consdata != NULL);
8210 assert(consdata->nvars >= 2);
8211 assert(consdata->weightsum > consdata->capacity);
8212
8213 vars = consdata->vars;
8214 weights = consdata->weights;
8215 nvars = consdata->nvars;
8216 capacity = consdata->capacity;
8217 sum = 0;
8218
8219 /* search for maximal fitting items */
8220 for( v = 0; v < nvars && sum + weights[v] <= capacity; ++v )
8221 sum += weights[v];
8222
8223 assert(v < nvars);
8224
8225 /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8226 if( SCIPconsGetNUpgradeLocks(cons) == 0 && v == nvars - 1 )
8227 {
8228 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8230
8231 return SCIP_OKAY;
8232 }
8233
8234 if( v < nvars - 1 )
8235 {
8236 /* try to delete variables */
8237 SCIP_CALL( deleteRedundantVars(scip, cons, sum, v, nchgcoefs, nchgsides, naddconss) );
8238 assert(consdata->nvars > 1);
8239
8240 /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8241 if( SCIPconsGetNUpgradeLocks(cons) == 0 && v == consdata->nvars - 1 )
8242 {
8243 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8245 }
8246
8247 return SCIP_OKAY;
8248 }
8249
8250 assert(vars == consdata->vars);
8251 assert(weights == consdata->weights);
8252 assert(nvars == consdata->nvars);
8253 assert(capacity == consdata->capacity);
8254
8255 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
8256 assert(conshdlrdata != NULL);
8257 /* calculate clique partition */
8258 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
8259
8260 /* check for real existing cliques */
8261 if( consdata->cliquepartition[v] < v )
8262 {
8263 SCIP_Longint sumfront;
8264 SCIP_Longint maxactduetoclqfront;
8265 int* clqpart;
8266 int cliquenum;
8267
8268 sumfront = 0;
8269 maxactduetoclqfront = 0;
8270
8271 clqpart = consdata->cliquepartition;
8272 cliquenum = 0;
8273
8274 /* calculate maximal activity due to cliques */
8275 for( w = 0; w < nvars; ++w )
8276 {
8277 assert(clqpart[w] >= 0 && clqpart[w] <= w);
8278 if( clqpart[w] == cliquenum )
8279 {
8280 if( maxactduetoclqfront + weights[w] <= capacity )
8281 {
8282 maxactduetoclqfront += weights[w];
8283 ++cliquenum;
8284 }
8285 else
8286 break;
8287 }
8288 sumfront += weights[w];
8289 }
8290 assert(w >= v);
8291
8292 /* if all items fit, then delete the whole constraint but create clique constraints which led to this
8293 * information
8294 */
8295 if( conshdlrdata->disaggregation && SCIPconsGetNUpgradeLocks(cons) == 0 && w == nvars )
8296 {
8297 SCIP_VAR** clqvars;
8298 int nclqvars;
8299 int c;
8300 int ncliques;
8301
8302 assert(maxactduetoclqfront <= capacity);
8303
8304 SCIPdebugMsg(scip, "Found redundant constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8305
8306 ncliques = consdata->ncliques;
8307
8308 /* allocate temporary memory */
8309 SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, nvars - ncliques + 1) );
8310
8311 for( c = 0; c < ncliques; ++c )
8312 {
8313 nclqvars = 0;
8314 for( w = 0; w < nvars; ++w )
8315 {
8316 if( clqpart[w] == c )
8317 {
8318 clqvars[nclqvars] = vars[w];
8319 ++nclqvars;
8320 }
8321 }
8322
8323 /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8324 if( nclqvars > 1 )
8325 {
8326 SCIP_CONS* cliquecons;
8327 char name[SCIP_MAXSTRLEN];
8328
8329 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8330 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8334 SCIPconsIsStickingAtNode(cons)) );
8335
8336 /* add the special constraint to the problem */
8337 SCIPdebugMsg(scip, " -> adding clique constraint: ");
8338 SCIPdebugPrintCons(scip, cliquecons, NULL);
8339 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8340 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8341 ++(*naddconss);
8342 }
8343 }
8344
8345 /* delete old constraint */
8346 SCIP_CALL( SCIPdelCons(scip, cons) );
8347 ++(*ndelconss);
8348
8349 SCIPfreeBufferArray(scip, &clqvars);
8350
8351 return SCIP_OKAY;
8352 }
8353
8354 if( w > v && w < nvars - 1 )
8355 {
8356 /* try to delete variables */
8357 SCIP_CALL( deleteRedundantVars(scip, cons, sumfront, w, nchgcoefs, nchgsides, naddconss) );
8358 }
8359 }
8360
8361 return SCIP_OKAY;
8362}
8363
8364/** divides weights by their greatest common divisor and divides capacity by the same value, rounding down the result */
8365static
8367 SCIP_CONS* cons, /**< knapsack constraint */
8368 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
8369 int* nchgsides /**< pointer to count number of side changes */
8370 )
8371{
8372 SCIP_CONSDATA* consdata;
8373 SCIP_Longint gcd;
8374 int i;
8375
8376 assert(nchgcoefs != NULL);
8377 assert(nchgsides != NULL);
8379
8380 consdata = SCIPconsGetData(cons);
8381 assert(consdata != NULL);
8382 assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
8383 assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
8384 assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
8385 assert(consdata->nvars >= 1);
8386
8387 /* sort items, because we can stop earlier if the smaller weights are evaluated first */
8388 sortItems(consdata);
8389
8390 gcd = consdata->weights[consdata->nvars-1];
8391 for( i = consdata->nvars-2; i >= 0 && gcd >= 2; --i )
8392 {
8393 assert(SCIPvarGetLbLocal(consdata->vars[i]) < 0.5);
8394 assert(SCIPvarGetUbLocal(consdata->vars[i]) > 0.5); /* all fixed variables should have been removed */
8395
8396 gcd = SCIPcalcGreComDiv(gcd, consdata->weights[i]);
8397 }
8398
8399 if( gcd >= 2 )
8400 {
8401 SCIPdebugMessage("knapsack constraint <%s>: dividing weights by %" SCIP_LONGINT_FORMAT "\n", SCIPconsGetName(cons), gcd);
8402
8403 for( i = 0; i < consdata->nvars; ++i )
8404 {
8405 consdataChgWeight(consdata, i, consdata->weights[i]/gcd);
8406 }
8407 consdata->capacity /= gcd;
8408 (*nchgcoefs) += consdata->nvars;
8409 (*nchgsides)++;
8410
8411 /* weight should still be sorted, because the reduction preserves this */
8412#ifndef NDEBUG
8413 for( i = consdata->nvars - 1; i > 0; --i )
8414 assert(consdata->weights[i] <= consdata->weights[i - 1]);
8415#endif
8416 consdata->sorted = TRUE;
8417 }
8418}
8419
8420/** dual weights tightening for knapsack constraints
8421 *
8422 * 1. a) check if all two pairs exceed the capacity, then we can upgrade this constraint to a set-packing constraint
8423 * b) check if all but the smallest weight fit into the knapsack, then we can upgrade this constraint to a logicor
8424 * constraint
8425 *
8426 * 2. check if besides big coefficients, that fit only by itself, for a certain amount of variables all combination of
8427 * these are a minimal cover, then might reduce the weights and the capacity, e.g.
8428 *
8429 * +219y1 + 180y2 + 74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8430 *
8431 * 3. use the duality between a^Tx <= capacity <=> a^T~x >= weightsum - capacity to tighten weights, e.g.
8432 *
8433 * 11x1 + 10x2 + 7x3 + 7x4 + 5x5 <= 27 <=> 11~x1 + 10~x2 + 7~x3 + 7~x4 + 5~x5 >= 13
8434 *
8435 * the above constraint can be changed to 8~x1 + 8~x2 + 6.5~x3 + 6.5~x4 + 5~x5 >= 13
8436 *
8437 * 16~x1 + 16~x2 + 13~x3 + 13~x4 + 10~x5 >= 26 <=> 16x1 + 16x2 + 13x3 + 13x4 + 10x5 <= 42
8438 */
8439static
8441 SCIP* scip, /**< SCIP data structure */
8442 SCIP_CONS* cons, /**< knapsack constraint */
8443 int* ndelconss, /**< pointer to store the amount of deleted constraints */
8444 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8445 int* nchgsides, /**< pointer to store the amount of changed sides */
8446 int* naddconss /**< pointer to count number of added constraints */
8447 )
8448{
8449 SCIP_CONSDATA* consdata;
8450 SCIP_Longint* weights;
8451 SCIP_Longint dualcapacity;
8452 SCIP_Longint reductionsum;
8453 SCIP_Longint capacity;
8454 SCIP_Longint exceedsum;
8455 int oldnchgcoefs;
8456 int nvars;
8457 int vbig;
8458 int v;
8459 int w;
8460#ifndef NDEBUG
8461 int oldnchgsides;
8462#endif
8463
8464 assert(scip != NULL);
8465 assert(cons != NULL);
8466 assert(ndelconss != NULL);
8467 assert(nchgcoefs != NULL);
8468 assert(nchgsides != NULL);
8469 assert(naddconss != NULL);
8470
8471 if( SCIPconsGetNUpgradeLocks(cons) >= 1 )
8472 return SCIP_OKAY;
8473
8474#ifndef NDEBUG
8475 oldnchgsides = *nchgsides;
8476#endif
8477
8478 consdata = SCIPconsGetData(cons);
8479 assert(consdata != NULL);
8480 assert(consdata->weightsum > consdata->capacity);
8481 assert(consdata->nvars >= 2);
8482 assert(consdata->sorted);
8483
8484 /* constraint should be merged */
8485 assert(consdata->merged);
8486
8487 nvars = consdata->nvars;
8488 weights = consdata->weights;
8489 capacity = consdata->capacity;
8490
8491 oldnchgcoefs = *nchgcoefs;
8492
8493 /* case 1. */
8494 if( weights[nvars - 1] + weights[nvars - 2] > capacity )
8495 {
8496 SCIP_CONS* newcons;
8497
8498 /* two variable are enough to exceed the constraint, so we can update it to a set-packing
8499 *
8500 * e.g. 5x1 + 4x2 + 3x3 <= 5 <=> x1 + x2 + x3 <= 1
8501 */
8502 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
8503
8504 SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
8508 SCIPconsIsStickingAtNode(cons)) );
8509
8510 /* add the upgraded constraint to the problem */
8511 SCIP_CALL( SCIPaddConsUpgrade(scip, cons, &newcons) );
8512 ++(*naddconss);
8513
8514 /* remove the underlying constraint from the problem */
8515 SCIP_CALL( SCIPdelCons(scip, cons) );
8516 ++(*ndelconss);
8517
8518 return SCIP_OKAY;
8519 }
8520
8521 /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8522 if( consdata->weightsum - weights[nvars - 1] <= consdata->capacity )
8523 {
8524 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8526
8527 return SCIP_OKAY;
8528 }
8529
8530 /* early termination, if the pair with biggest coeffcients together does not exceed the dualcapacity */
8531 /* @todo might be changed/removed when improving the coeffcients tightening */
8532 if( consdata->weightsum - capacity > weights[0] + weights[1] )
8533 return SCIP_OKAY;
8534
8535 /* case 2. */
8536
8537 v = 0;
8538
8539 /* @todo generalize the following algorithm for several parts of the knapsack
8540 *
8541 * the following is done without looking at the dualcapacity; it is enough to check whether for a certain amount of
8542 * variables each combination is a minimal cover, some examples
8543 *
8544 * +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 74~x1 + 70~x2 + 63~x3 + 62~x4 + 53~x5 >= 103
8545 * <=> ~x1 + ~x2 + ~x3 + ~x4 + ~x5 >= 2
8546 * <=> x1 + x2 + x3 + x4 + x5 <= 3
8547 *
8548 * +219y1 + 180y_2 +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8549 *
8550 */
8551
8552 /* determine big weights that fit only by itself */
8553 while( v < nvars && weights[v] + weights[nvars - 1] > capacity )
8554 ++v;
8555
8556 vbig = v;
8557 assert(vbig < nvars - 1);
8558 exceedsum = 0;
8559
8560 /* determine the amount needed to exceed the capacity */
8561 while( v < nvars && exceedsum <= capacity )
8562 {
8563 exceedsum += weights[v];
8564 ++v;
8565 }
8566
8567 /* if we exceeded the capacity we might reduce the weights */
8568 if( exceedsum > capacity )
8569 {
8570 assert(vbig > 0 || v < nvars);
8571
8572 /* all small weights were needed to exceed the capacity */
8573 if( v == nvars )
8574 {
8575 SCIP_Longint newweight = (SCIP_Longint)nvars - vbig - 1;
8576 assert(newweight > 0);
8577
8578 /* reduce big weights */
8579 for( v = 0; v < vbig; ++v )
8580 {
8581 if( weights[v] > newweight )
8582 {
8583 consdataChgWeight(consdata, v, newweight);
8584 ++(*nchgcoefs);
8585 }
8586 }
8587
8588 /* reduce small weights */
8589 for( ; v < nvars; ++v )
8590 {
8591 if( weights[v] > 1 )
8592 {
8593 consdataChgWeight(consdata, v, 1LL);
8594 ++(*nchgcoefs);
8595 }
8596 }
8597
8598 consdata->capacity = newweight;
8599
8600 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8601 * weight must not be sorted by their index
8602 */
8603#ifndef NDEBUG
8604 for( v = nvars - 1; v > 0; --v )
8605 assert(weights[v] <= weights[v-1]);
8606#endif
8607
8608 return SCIP_OKAY;
8609 }
8610 /* a certain amount of small variables exceed the capacity, so check if this holds for all combinations of the
8611 * small weights
8612 */
8613 else
8614 {
8615 SCIP_Longint exceedsumback = 0;
8616 int nexceed = v - vbig;
8617
8618 assert(nexceed > 1);
8619
8620 /* determine weightsum of the same amount as before but of the smallest weight */
8621 for( w = nvars - 1; w >= nvars - nexceed; --w )
8622 exceedsumback += weights[w];
8623
8624 assert(w >= 0);
8625
8626 /* if the same amount but with the smallest possible weights also exceed the capacity, it holds for all
8627 * combinations of all small weights
8628 */
8629 if( exceedsumback > capacity )
8630 {
8631 SCIP_Longint newweight = nexceed - 1;
8632
8633 /* taking out the smallest element needs to fit */
8634 assert(exceedsumback - weights[nvars - 1] <= capacity);
8635
8636 /* reduce big weights */
8637 for( v = 0; v < vbig; ++v )
8638 {
8639 if( weights[v] > newweight )
8640 {
8641 consdataChgWeight(consdata, v, newweight);
8642 ++(*nchgcoefs);
8643 }
8644 }
8645
8646 /* reduce small weights */
8647 for( ; v < nvars; ++v )
8648 {
8649 if( weights[v] > 1 )
8650 {
8651 consdataChgWeight(consdata, v, 1LL);
8652 ++(*nchgcoefs);
8653 }
8654 }
8655
8656 consdata->capacity = newweight;
8657
8658 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8659 * weight must not be sorted by their index
8660 */
8661#ifndef NDEBUG
8662 for( v = nvars - 1; v > 0; --v )
8663 assert(weights[v] <= weights[v-1]);
8664#endif
8665 return SCIP_OKAY;
8666 }
8667 }
8668 }
8669 else
8670 {
8671 /* if the following assert fails we have either a redundant constraint or a set-packing constraint, this should
8672 * not happen here
8673 */
8674 assert(vbig > 0 && vbig < nvars);
8675
8676 /* either choose a big coefficients or all other variables
8677 *
8678 * 973x1 + 189x2 + 189x3 + 145x4 + 110x5 + 104x6 + 93x7 + 71x8 + 68x9 + 10x10 <= 979
8679 *
8680 * either choose x1, or all other variables (weightsum of x2 to x10 is 979 above), so we can tighten this
8681 * constraint to
8682 *
8683 * 9x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 <= 9
8684 */
8685
8686 if( weights[vbig - 1] > (SCIP_Longint)nvars - vbig || weights[vbig] > 1 )
8687 {
8688 SCIP_Longint newweight = (SCIP_Longint)nvars - vbig;
8689#ifndef NDEBUG
8690 SCIP_Longint resweightsum = consdata->weightsum;
8691
8692 for( v = 0; v < vbig; ++v )
8693 resweightsum -= weights[v];
8694
8695 assert(exceedsum == resweightsum);
8696#endif
8697 assert(newweight > 0);
8698
8699 /* reduce big weights */
8700 for( v = 0; v < vbig; ++v )
8701 {
8702 if( weights[v] > newweight )
8703 {
8704 consdataChgWeight(consdata, v, newweight);
8705 ++(*nchgcoefs);
8706 }
8707 }
8708
8709 /* reduce small weights */
8710 for( ; v < nvars; ++v )
8711 {
8712 if( weights[v] > 1 )
8713 {
8714 consdataChgWeight(consdata, v, 1LL);
8715 ++(*nchgcoefs);
8716 }
8717 }
8718
8719 consdata->capacity = newweight;
8720
8721 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8722 * weight must not be sorted by their index
8723 */
8724#ifndef NDEBUG
8725 for( v = nvars - 1; v > 0; --v )
8726 assert(weights[v] <= weights[v-1]);
8727#endif
8728 return SCIP_OKAY;
8729 }
8730 }
8731
8732 /* case 3. */
8733
8734 dualcapacity = consdata->weightsum - capacity;
8735 reductionsum = 0;
8736 v = 0;
8737
8738 /* reduce big weights
8739 *
8740 * e.g. 11x0 + 11x1 + 10x2 + 10x3 <= 32 <=> 11~x0 + 11~x1 + 10~x2 + 10~x3 >= 10
8741 * <=> 10~x0 + 10~x1 + 10~x2 + 10~x3 >= 10
8742 * <=> x0 + x1 + x2 + x3 <= 3
8743 */
8744 while( weights[v] > dualcapacity )
8745 {
8746 reductionsum += (weights[v] - dualcapacity);
8747 consdataChgWeight(consdata, v, dualcapacity);
8748 ++v;
8749 assert(v < nvars);
8750 }
8751 (*nchgcoefs) += v;
8752
8753 /* skip weights equal to the dualcapacity, because we cannot change them */
8754 while( v < nvars && weights[v] == dualcapacity )
8755 ++v;
8756
8757 /* any negated variable out of the first n - 1 items is enough to fulfill the constraint, so we can update it to a logicor
8758 * after a possible removal of the last, redundant item
8759 *
8760 * e.g. 10x1 + 10x2 + 10x3 <= 20 <=> 10~x1 + 10~x2 + 10~x3 >= 10 <=> ~x1 + ~x2 + ~x3 >= 1
8761 */
8762 if( v >= nvars - 1 )
8763 {
8764 /* the last weight is not enough to satisfy the dual capacity -> remove this redundant item */
8765 if( v == nvars - 1 )
8766 {
8767 SCIP_CALL( delCoefPos(scip, cons, nvars - 1) );
8768 }
8769 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8771
8772 return SCIP_OKAY;
8773 }
8774 /* at least two items with weight smaller than the dual capacity */
8775 else
8776 {
8777 /* @todo generalize the following algorithm for more than two variables */
8778
8779 if( weights[nvars - 1] + weights[nvars - 2] >= dualcapacity )
8780 {
8781 /* we have a dual-knapsack constraint where we either need to choose one variable out of a subset (big
8782 * coefficients) of all or two variables of the rest
8783 *
8784 * e.g. 9x1 + 9x2 + 6x3 + 4x4 <= 19 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 >= 9
8785 * <=> 2~x1 + 2~x2 + ~x3 + ~x4 >= 2
8786 * <=> 2x1 + 2x2 + x3 + x4 <= 4
8787 *
8788 * 3x1 + 3x2 + 2x3 + 2x4 + 2x5 + 2x6 + x7 <= 12 <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + 2~x5 + 2~x6 + ~x7 >= 3
8789 * <=> 2~x1 + 2~x2 + ~x3 + ~x4 + ~x5 + ~x6 + ~x7 >= 2
8790 * <=> 2 x1 + 2 x2 + x3 + x4 + x5 + x6 + x7 <= 7
8791 *
8792 */
8793 if( v > 0 && weights[nvars - 2] > 1 )
8794 {
8795 int ncoefchg = 0;
8796
8797 /* reduce all bigger weights */
8798 for( w = 0; w < v; ++w )
8799 {
8800 if( weights[w] > 2 )
8801 {
8802 consdataChgWeight(consdata, w, 2LL);
8803 ++ncoefchg;
8804 }
8805 else
8806 {
8807 assert(weights[0] == 2);
8808 assert(weights[v - 1] == 2);
8809 break;
8810 }
8811 }
8812
8813 /* reduce all smaller weights */
8814 for( w = v; w < nvars; ++w )
8815 {
8816 if( weights[w] > 1 )
8817 {
8818 consdataChgWeight(consdata, w, 1LL);
8819 ++ncoefchg;
8820 }
8821 }
8822 assert(ncoefchg > 0);
8823
8824 (*nchgcoefs) += ncoefchg;
8825
8826 /* correct the capacity */
8827 consdata->capacity = (-2 + v * 2 + nvars - v); /*lint !e647*/
8828 assert(consdata->capacity > 0);
8829 assert(weights[0] <= consdata->capacity);
8830 assert(consdata->weightsum > consdata->capacity);
8831 /* reset the reductionsum */
8832 reductionsum = 0;
8833 }
8834 else if( v == 0 )
8835 {
8836 assert(weights[nvars - 2] == 1);
8837 }
8838 }
8839 else
8840 {
8841 SCIP_Longint minweight = weights[nvars - 1];
8842 SCIP_Longint newweight = dualcapacity - minweight;
8843 SCIP_Longint restsumweights = 0;
8844 SCIP_Longint sumcoef;
8845 SCIP_Bool sumcoefcase = FALSE;
8846 int startv = v;
8847 int end;
8848 int k;
8849
8850 assert(weights[nvars - 1] + weights[nvars - 2] <= capacity);
8851
8852 /* reduce big weights of pairs that exceed the dualcapacity
8853 *
8854 * e.g. 9x1 + 9x2 + 6x3 + 4x4 + 4x5 + 4x6 <= 27 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8855 * <=> 9~x1 + 9~x2 + 5~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8856 * <=> 9x1 + 9x2 + 5x3 + 4x4 + 4x5 + 4x6 <= 27
8857 */
8858 while( weights[v] > newweight )
8859 {
8860 reductionsum += (weights[v] - newweight);
8861 consdataChgWeight(consdata, v, newweight);
8862 ++v;
8863 assert(v < nvars);
8864 }
8865 (*nchgcoefs) += (v - startv);
8866
8867 /* skip equal weights */
8868 while( weights[v] == newweight )
8869 ++v;
8870
8871 if( v > 0 )
8872 {
8873 for( w = v; w < nvars; ++w )
8874 restsumweights += weights[w];
8875 }
8876 else
8877 restsumweights = consdata->weightsum;
8878
8879 if( restsumweights < dualcapacity )
8880 {
8881 /* we found redundant variables, which does not influence the feasibility of any integral solution, e.g.
8882 *
8883 * +61x1 + 61x2 + 61x3 + 61x4 + 61x5 + 61x6 + 35x7 + 10x8 <= 350 <=>
8884 * +61~x1 + 61~x2 + 61~x3 + 61~x4 + 61~x5 + 61~x6 + 35~x7 + 10~x8 >= 61
8885 */
8886 if( startv == v )
8887 {
8888 /* remove redundant variables */
8889 for( w = nvars - 1; w >= v; --w )
8890 {
8891 SCIP_CALL( delCoefPos(scip, cons, v) );
8892 ++(*nchgcoefs);
8893 }
8894
8895#ifndef NDEBUG
8896 /* each coefficients should exceed the dualcapacity by itself */
8897 for( ; w >= 0; --w )
8898 assert(weights[w] == dualcapacity);
8899#endif
8900 /* for performance reasons we do not update the capacity(, i.e. reduce it by reductionsum) and directly
8901 * upgrade this constraint
8902 */
8903 SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8905
8906 return SCIP_OKAY;
8907 }
8908
8909 /* special case where we have three different coefficient types
8910 *
8911 * e.g. 9x1 + 9x2 + 6x3 + 6x4 + 4x5 + 4x6 <= 29 <=> 9~x1 + 9~x2 + 6~x3 + 6~x4 + 4~x5 + 4~x6 >= 9
8912 * <=> 9~x1 + 9~x2 + 5~x3 + 5~x4 + 4~x5 + 4~x6 >= 9
8913 * <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + ~x5 + ~x6 >= 3
8914 * <=> 3x1 + 3x2 + 2x3 + 2x4 + x5 + x6 <= 9
8915 */
8916 if( weights[v] > 1 || (weights[startv] > (SCIP_Longint)nvars - v) || (startv > 0 && weights[0] == (SCIP_Longint)nvars - v + 1) )
8917 {
8918 SCIP_Longint newcap;
8919
8920 /* adjust smallest coefficients, which all together do not exceed the dualcapacity */
8921 for( w = nvars - 1; w >= v; --w )
8922 {
8923 if( weights[w] > 1 )
8924 {
8925 consdataChgWeight(consdata, w, 1LL);
8926 ++(*nchgcoefs);
8927 }
8928 }
8929
8930 /* adjust middle sized coefficients, which when choosing also one small coefficients exceed the
8931 * dualcapacity
8932 */
8933 newweight = (SCIP_Longint)nvars - v;
8934 assert(newweight > 1);
8935 for( ; w >= startv; --w )
8936 {
8937 if( weights[w] > newweight )
8938 {
8939 consdataChgWeight(consdata, w, newweight);
8940 ++(*nchgcoefs);
8941 }
8942 else
8943 assert(weights[w] == newweight);
8944 }
8945
8946 /* adjust big sized coefficients, where each of them exceeds the dualcapacity by itself */
8947 ++newweight;
8948 assert(newweight > 2);
8949 for( ; w >= 0; --w )
8950 {
8951 if( weights[w] > newweight )
8952 {
8953 consdataChgWeight(consdata, w, newweight);
8954 ++(*nchgcoefs);
8955 }
8956 else
8957 assert(weights[w] == newweight);
8958 }
8959
8960 /* update the capacity */
8961 newcap = ((SCIP_Longint)startv - 1) * newweight + ((SCIP_Longint)v - startv) * (newweight - 1) + ((SCIP_Longint)nvars - v);
8962 if( consdata->capacity > newcap )
8963 {
8964 consdata->capacity = newcap;
8965 ++(*nchgsides);
8966 }
8967 else
8968 assert(consdata->capacity == newcap);
8969 }
8970 assert(weights[v] == 1 && (weights[startv] == (SCIP_Longint)nvars - v) && (startv == 0 || weights[0] == (SCIP_Longint)nvars - v + 1));
8971
8972 /* the new dualcapacity should still be equal to the (nvars - v + 1) */
8973 assert(consdata->weightsum - consdata->capacity == (SCIP_Longint)nvars - v + 1);
8974
8975 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8976 * weight must not be sorted by their index
8977 */
8978#ifndef NDEBUG
8979 for( w = nvars - 1; w > 0; --w )
8980 assert(weights[w] <= weights[w - 1]);
8981#endif
8982 return SCIP_OKAY;
8983 }
8984
8985 /* check if all rear items have the same weight as the last one, so we cannot tighten the constraint further */
8986 end = nvars - 2;
8987 while( end >= 0 && weights[end] == weights[end + 1] )
8988 {
8989 assert(end >= v);
8990 --end;
8991 }
8992
8993 if( v >= end )
8994 goto TERMINATE;
8995
8996 end = nvars - 2;
8997
8998 /* can we stop early, another special reduction case might exist */
8999 if( 2 * weights[end] > dualcapacity )
9000 {
9001 restsumweights = 0;
9002
9003 /* determine capacity of the small items */
9004 for( w = end + 1; w < nvars; ++w )
9005 restsumweights += weights[w];
9006
9007 if( restsumweights * 2 <= dualcapacity )
9008 {
9009 /* check for further posssible reductions in the middle */
9010 while( v < end && restsumweights + weights[v] >= dualcapacity )
9011 ++v;
9012
9013 if( v >= end )
9014 goto TERMINATE;
9015
9016 /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
9017 if( (dualcapacity & 1) == 0 )
9018 {
9019 newweight = dualcapacity / 2;
9020
9021 /* set all middle coefficients */
9022 for( ; v <= end; ++v )
9023 {
9024 if( weights[v] > newweight )
9025 {
9026 reductionsum += (weights[v] - newweight);
9027 consdataChgWeight(consdata, v, newweight);
9028 ++(*nchgcoefs);
9029 }
9030 }
9031 }
9032 /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
9033 * other coefficients by 2
9034 */
9035 else
9036 {
9037 /* correct the reductionsum */
9038 reductionsum *= 2;
9039
9040 /* multiply big coefficients by 2 */
9041 for( w = 0; w < v; ++w )
9042 {
9043 consdataChgWeight(consdata, w, weights[w] * 2);
9044 }
9045
9046 newweight = dualcapacity;
9047 /* set all middle coefficients */
9048 for( ; v <= end; ++v )
9049 {
9050 reductionsum += (2 * weights[v] - newweight);
9051 consdataChgWeight(consdata, v, newweight);
9052 }
9053
9054 /* multiply small coefficients by 2 */
9055 for( w = end + 1; w < nvars; ++w )
9056 {
9057 consdataChgWeight(consdata, w, weights[w] * 2);
9058 }
9059 (*nchgcoefs) += nvars;
9060
9061 dualcapacity *= 2;
9062 consdata->capacity *= 2;
9063 ++(*nchgsides);
9064 }
9065 }
9066
9067 goto TERMINATE;
9068 }
9069
9070 /* further reductions using the next possible coefficient sum
9071 *
9072 * e.g. 9x1 + 8x2 + 7x3 + 3x4 + x5 <= 19 <=> 9~x1 + 8~x2 + 7~x3 + 3~x4 + ~x5 >= 9
9073 * <=> 9~x1 + 8~x2 + 6~x3 + 3~x4 + ~x5 >= 9
9074 * <=> 9x1 + 8x2 + 6x3 + 3x4 + x5 <= 18
9075 */
9076 /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
9077 for( k = 0; k < 4; ++k )
9078 {
9079 /* determine next minimal coefficient sum */
9080 switch( k )
9081 {
9082 case 0:
9083 sumcoef = weights[nvars - 1] + weights[nvars - 2];
9084 break;
9085 case 1:
9086 assert(nvars >= 3);
9087 sumcoef = weights[nvars - 1] + weights[nvars - 3];
9088 break;
9089 case 2:
9090 assert(nvars >= 4);
9091 if( weights[nvars - 1] + weights[nvars - 4] < weights[nvars - 2] + weights[nvars - 3] )
9092 {
9093 sumcoefcase = TRUE;
9094 sumcoef = weights[nvars - 1] + weights[nvars - 4];
9095 }
9096 else
9097 {
9098 sumcoefcase = FALSE;
9099 sumcoef = weights[nvars - 2] + weights[nvars - 3];
9100 }
9101 break;
9102 case 3:
9103 assert(nvars >= 5);
9104 if( sumcoefcase )
9105 {
9106 sumcoef = MIN(weights[nvars - 1] + weights[nvars - 5], weights[nvars - 2] + weights[nvars - 3]);
9107 }
9108 else
9109 {
9110 sumcoef = MIN(weights[nvars - 1] + weights[nvars - 4], weights[nvars - 1] + weights[nvars - 2] + weights[nvars - 3]);
9111 }
9112 break;
9113 default:
9114 return SCIP_ERROR;
9115 }
9116
9117 /* tighten next coefficients that, pair with the current small coefficient, exceed the dualcapacity */
9118 minweight = weights[end];
9119 while( minweight <= sumcoef )
9120 {
9121 newweight = dualcapacity - minweight;
9122 startv = v;
9123 assert(v < nvars);
9124
9125 /* @todo check for further reductions, when two times the minweight exceeds the dualcapacity */
9126 /* shrink big coefficients */
9127 while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9128 {
9129 reductionsum += (weights[v] - newweight);
9130 consdataChgWeight(consdata, v, newweight);
9131 ++v;
9132 assert(v < nvars);
9133 }
9134 (*nchgcoefs) += (v - startv);
9135
9136 /* skip unchangable weights */
9137 while( weights[v] + minweight == dualcapacity )
9138 {
9139 assert(v < nvars);
9140 ++v;
9141 }
9142
9143 --end;
9144 /* skip same end weights */
9145 while( end >= 0 && weights[end] == weights[end + 1] )
9146 --end;
9147
9148 if( v >= end )
9149 goto TERMINATE;
9150
9151 minweight = weights[end];
9152 }
9153
9154 if( v >= end )
9155 goto TERMINATE;
9156
9157 /* now check if a combination of small coefficients allows us to tighten big coefficients further */
9158 if( sumcoef < minweight )
9159 {
9160 minweight = sumcoef;
9161 newweight = dualcapacity - minweight;
9162 startv = v;
9163 assert(v < nvars);
9164
9165 /* shrink big coefficients */
9166 while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9167 {
9168 reductionsum += (weights[v] - newweight);
9169 consdataChgWeight(consdata, v, newweight);
9170 ++v;
9171 assert(v < nvars);
9172 }
9173 (*nchgcoefs) += (v - startv);
9174
9175 /* skip unchangable weights */
9176 while( weights[v] + minweight == dualcapacity )
9177 {
9178 assert(v < nvars);
9179 ++v;
9180 }
9181 }
9182
9183 if( v >= end )
9184 goto TERMINATE;
9185
9186 /* can we stop early, another special reduction case might exist */
9187 if( 2 * weights[end] > dualcapacity )
9188 {
9189 restsumweights = 0;
9190
9191 /* determine capacity of the small items */
9192 for( w = end + 1; w < nvars; ++w )
9193 restsumweights += weights[w];
9194
9195 if( restsumweights * 2 <= dualcapacity )
9196 {
9197 /* check for further posssible reductions in the middle */
9198 while( v < end && restsumweights + weights[v] >= dualcapacity )
9199 ++v;
9200
9201 if( v >= end )
9202 goto TERMINATE;
9203
9204 /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
9205 if( (dualcapacity & 1) == 0 )
9206 {
9207 newweight = dualcapacity / 2;
9208
9209 /* set all middle coefficients */
9210 for( ; v <= end; ++v )
9211 {
9212 if( weights[v] > newweight )
9213 {
9214 reductionsum += (weights[v] - newweight);
9215 consdataChgWeight(consdata, v, newweight);
9216 ++(*nchgcoefs);
9217 }
9218 }
9219 }
9220 /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
9221 * other coefficients by 2
9222 */
9223 else
9224 {
9225 /* correct the reductionsum */
9226 reductionsum *= 2;
9227
9228 /* multiply big coefficients by 2 */
9229 for( w = 0; w < v; ++w )
9230 {
9231 consdataChgWeight(consdata, w, weights[w] * 2);
9232 }
9233
9234 newweight = dualcapacity;
9235 /* set all middle coefficients */
9236 for( ; v <= end; ++v )
9237 {
9238 reductionsum += (2 * weights[v] - newweight);
9239 consdataChgWeight(consdata, v, newweight);
9240 }
9241
9242 /* multiply small coefficients by 2 */
9243 for( w = end + 1; w < nvars; ++w )
9244 {
9245 consdataChgWeight(consdata, w, weights[w] * 2);
9246 }
9247 (*nchgcoefs) += nvars;
9248
9249 dualcapacity *= 2;
9250 consdata->capacity *= 2;
9251 ++(*nchgsides);
9252 }
9253 }
9254
9255 goto TERMINATE;
9256 }
9257
9258 /* cannot tighten any further */
9259 if( 2 * sumcoef > dualcapacity )
9260 goto TERMINATE;
9261 }
9262 }
9263 }
9264
9265 TERMINATE:
9266 /* correct capacity */
9267 if( reductionsum > 0 )
9268 {
9269 assert(v > 0);
9270
9271 consdata->capacity -= reductionsum;
9272 ++(*nchgsides);
9273
9274 assert(consdata->weightsum - dualcapacity == consdata->capacity);
9275 }
9276 assert(weights[0] <= consdata->capacity);
9277
9278 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
9279 * weight must not be sorted by their index
9280 */
9281#ifndef NDEBUG
9282 for( w = nvars - 1; w > 0; --w )
9283 assert(weights[w] <= weights[w - 1]);
9284#endif
9285
9286 if( oldnchgcoefs < *nchgcoefs )
9287 {
9288 assert(!SCIPconsIsDeleted(cons));
9289
9290 /* it might be that we can divide the weights by their greatest common divisor */
9291 normalizeWeights(cons, nchgcoefs, nchgsides);
9292 }
9293 else
9294 {
9295 assert(oldnchgcoefs == *nchgcoefs);
9296 assert(oldnchgsides == *nchgsides);
9297 }
9298
9299 return SCIP_OKAY;
9300}
9301
9302
9303/** fixes variables with weights bigger than the capacity and delete redundant constraints, also sort weights */
9304static
9306 SCIP* scip, /**< SCIP data structure */
9307 SCIP_CONS* cons, /**< knapsack constraint */
9308 int* nfixedvars, /**< pointer to store the amount of fixed variables */
9309 int* ndelconss, /**< pointer to store the amount of deleted constraints */
9310 int* nchgcoefs /**< pointer to store the amount of changed coefficients */
9311 )
9312{
9313 SCIP_VAR** vars;
9314 SCIP_CONSDATA* consdata;
9315 SCIP_Longint* weights;
9316 SCIP_Longint capacity;
9317 SCIP_Bool infeasible;
9318 SCIP_Bool fixed;
9319 int nvars;
9320 int v;
9321
9322 assert(scip != NULL);
9323 assert(cons != NULL);
9324 assert(nfixedvars != NULL);
9325 assert(ndelconss != NULL);
9326 assert(nchgcoefs != NULL);
9327
9328 consdata = SCIPconsGetData(cons);
9329 assert(consdata != NULL);
9330
9331 nvars = consdata->nvars;
9332
9333 /* no variables left, then delete constraint */
9334 if( nvars == 0 )
9335 {
9336 assert(consdata->capacity >= 0);
9337
9338 SCIP_CALL( SCIPdelCons(scip, cons) );
9339 ++(*ndelconss);
9340
9341 return SCIP_OKAY;
9342 }
9343
9344 /* sort items */
9345 sortItems(consdata);
9346
9347 vars = consdata->vars;
9348 weights = consdata->weights;
9349 capacity = consdata->capacity;
9350 v = 0;
9351
9352 /* check for weights bigger than the capacity */
9353 while( v < nvars && weights[v] > capacity )
9354 {
9355 SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, &infeasible, &fixed) );
9356 assert(!infeasible);
9357
9358 if( fixed )
9359 ++(*nfixedvars);
9360
9361 ++v;
9362 }
9363
9364 /* if we fixed at least one variable we need to delete them from the constraint */
9365 if( v > 0 )
9366 {
9367 if( v == nvars )
9368 {
9369 SCIP_CALL( SCIPdelCons(scip, cons) );
9370 ++(*ndelconss);
9371
9372 return SCIP_OKAY;
9373 }
9374
9375 /* delete all position from back to front */
9376 for( --v; v >= 0; --v )
9377 {
9378 SCIP_CALL( delCoefPos(scip, cons, v) );
9379 ++(*nchgcoefs);
9380 }
9381
9382 /* sort items again because of deletion */
9383 sortItems(consdata);
9384 assert(vars == consdata->vars);
9385 assert(weights == consdata->weights);
9386 }
9387 assert(consdata->sorted);
9388 assert(weights[0] <= capacity);
9389
9390 if( !SCIPisHugeValue(scip, (SCIP_Real) capacity) && consdata->weightsum <= capacity )
9391 {
9392 SCIP_CALL( SCIPdelCons(scip, cons) );
9393 ++(*ndelconss);
9394 }
9395
9396 return SCIP_OKAY;
9397}
9398
9399
9400/** tries to simplify weights and delete redundant variables in knapsack a^Tx <= capacity
9401 *
9402 * 1. use the duality between a^Tx <= capacity <=> -a^T~x <= capacity - weightsum to tighten weights, e.g.
9403 *
9404 * 11x1 + 10x2 + 7x3 + 5x4 + 5x5 <= 25 <=> -10~x1 - 10~x2 - 7~x3 - 5~x4 - 5~x5 <= -13
9405 *
9406 * the above constraint can be changed to
9407 *
9408 * -8~x1 - 8~x2 - 7~x3 - 5~x4 - 5~x5 <= -12 <=> 8x1 + 8x2 + 7x3 + 5x4 + 5x5 <= 20
9409 *
9410 * 2. if variables in a constraint do not affect the (in-)feasibility of the constraint, we can delete them, e.g.
9411 *
9412 * 7x1 + 6x2 + 5x3 + 5x4 + x5 + x6 <= 20 => x5 and x6 are redundant and can be removed
9413 *
9414 * 3. Tries to use gcd information an all but one weight to change this not-included weight and normalize the
9415 * constraint further, e.g.
9416 *
9417 * 9x1 + 6x2 + 6x3 + 5x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => 3x1 + 2x2 + 2x3 + 2x4 <= 4 => 4x1 + 2x2 + 2x3 + 2x4 <= 4
9418 * => 2x1 + x2 + x3 + x4 <= 2
9419 * 9x1 + 6x2 + 6x3 + 7x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => see above
9420 */
9421static
9423 SCIP* scip, /**< SCIP data structure */
9424 SCIP_CONS* cons, /**< knapsack constraint */
9425 int* nfixedvars, /**< pointer to store the amount of fixed variables */
9426 int* ndelconss, /**< pointer to store the amount of deleted constraints */
9427 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
9428 int* nchgsides, /**< pointer to store the amount of changed sides */
9429 int* naddconss, /**< pointer to count number of added constraints */
9430 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9431 )
9432{
9433 SCIP_VAR** vars;
9434 SCIP_CONSDATA* consdata;
9435 SCIP_Longint* weights;
9436 SCIP_Longint restweight;
9437 SCIP_Longint newweight;
9438 SCIP_Longint weight;
9439 SCIP_Longint oldgcd;
9440 SCIP_Longint rest;
9441 SCIP_Longint gcd;
9442 int oldnchgcoefs; /* cppcheck-suppress unassignedVariable */
9443 int oldnchgsides; /* cppcheck-suppress unassignedVariable */
9444 int candpos;
9445 int candpos2;
9446 int offsetv;
9447 int nvars;
9448 int v;
9449
9450 assert(scip != NULL);
9451 assert(cons != NULL);
9452 assert(nfixedvars != NULL);
9453 assert(ndelconss != NULL);
9454 assert(nchgcoefs != NULL);
9455 assert(nchgsides != NULL);
9456 assert(naddconss != NULL);
9457 assert(cutoff != NULL);
9459
9460 consdata = SCIPconsGetData(cons);
9461 assert( consdata != NULL );
9462
9463 *cutoff = FALSE;
9464
9465 /* remove double enties and also combinations of active and negated variables */
9467 assert(consdata->merged);
9468 if( *cutoff )
9469 return SCIP_OKAY;
9470
9471 assert(consdata->capacity >= 0);
9472
9473 /* fix variables with big coefficients and remove redundant constraints, sort weights */
9474 SCIP_CALL( prepareCons(scip, cons, nfixedvars, ndelconss, nchgcoefs) );
9475
9476 if( SCIPconsIsDeleted(cons) )
9477 return SCIP_OKAY;
9478
9479 if( !SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
9480 {
9481 /* 1. dual weights tightening */
9482 SCIP_CALL( dualWeightsTightening(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9483
9484 if( SCIPconsIsDeleted(cons) )
9485 return SCIP_OKAY;
9486 /* 2. delete redundant variables */
9487 SCIP_CALL( detectRedundantVars(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9488
9489 if( SCIPconsIsDeleted(cons) )
9490 return SCIP_OKAY;
9491 }
9492
9493 weights = consdata->weights;
9494 nvars = consdata->nvars;
9495
9496#ifndef NDEBUG
9497 /* constraint might not be sorted, but the weights are already sorted */
9498 for( v = nvars - 1; v > 0; --v )
9499 assert(weights[v] <= weights[v-1]);
9500#endif
9501
9502 /* determine greatest common divisor */
9503 gcd = weights[nvars - 1];
9504 for( v = nvars - 2; v >= 0 && gcd > 1; --v )
9505 {
9506 gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9507 }
9508
9509 /* divide the constraint by their greatest common divisor */
9510 if( gcd >= 2 )
9511 {
9512 for( v = nvars - 1; v >= 0; --v )
9513 {
9514 consdataChgWeight(consdata, v, weights[v]/gcd);
9515 }
9516 (*nchgcoefs) += nvars;
9517
9518 consdata->capacity /= gcd;
9519 (*nchgsides)++;
9520 }
9521 assert(consdata->nvars == nvars);
9522
9523 /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal weight
9524 * must not be sorted by their index
9525 */
9526#ifndef NDEBUG
9527 for( v = nvars - 1; v > 0; --v )
9528 assert(weights[v] <= weights[v-1]);
9529#endif
9530
9531 /* 3. start gcd procedure for all variables */
9532 do
9533 {
9534 SCIPdebug( oldnchgcoefs = *nchgcoefs; )
9535 SCIPdebug( oldnchgsides = *nchgsides; )
9536
9537 vars = consdata->vars;
9538 weights = consdata->weights;
9539 nvars = consdata->nvars;
9540
9541 /* stop if we have two coefficients which are one in absolute value */
9542 if( weights[nvars - 1] == 1 && weights[nvars - 2] == 1 )
9543 return SCIP_OKAY;
9544
9545 v = 0;
9546 /* determine coefficients as big as the capacity, these we do not need to take into account when calculating the
9547 * gcd
9548 */
9549 while( weights[v] == consdata->capacity )
9550 {
9551 ++v;
9552 assert(v < nvars);
9553 }
9554
9555 /* all but one variable are as big as the capacity, this is handled elsewhere */
9556 if( v == nvars - 1 )
9557 return SCIP_OKAY;
9558
9559 offsetv = v;
9560
9561 gcd = -1;
9562 candpos = -1;
9563 candpos2 = -1;
9564
9565 /* calculate greatest common divisor over all integer and binary variables and determine the candidate where we might
9566 * change the coefficient
9567 */
9568 for( v = nvars - 1; v >= offsetv; --v )
9569 {
9570 weight = weights[v];
9571 assert(weight >= 1);
9572
9573 oldgcd = gcd;
9574
9575 if( gcd == -1 )
9576 {
9577 gcd = weights[v];
9578 assert(gcd >= 1);
9579 }
9580 else
9581 {
9582 /* calculate greatest common divisor for all variables */
9583 gcd = SCIPcalcGreComDiv(gcd, weight);
9584 }
9585
9586 /* if the greatest commmon divisor has become 1, we might have found the possible coefficient to change or we
9587 * can terminate
9588 */
9589 if( gcd == 1 )
9590 {
9591 /* found candidate */
9592 if( candpos == -1 )
9593 {
9594 gcd = oldgcd;
9595 candpos = v;
9596
9597 /* if both first coefficients have a gcd of 1, both are candidates for the coefficient change */
9598 if( v == nvars - 2 )
9599 candpos2 = v + 1;
9600 }
9601 /* two different variables lead to a gcd of one, so we cannot change a coefficient */
9602 else
9603 {
9604 if( candpos == v + 1 && candpos2 == v + 2 )
9605 {
9606 assert(candpos2 == nvars - 1);
9607
9608 /* take new candidates */
9609 candpos = candpos2;
9610
9611 /* recalculate gcd from scratch */
9612 gcd = weights[v+1];
9613 assert(gcd >= 1);
9614
9615 /* calculate greatest common divisor for variables */
9616 gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9617 if( gcd == 1 )
9618 return SCIP_OKAY;
9619 }
9620 else
9621 /* cannot determine a possible coefficient for reduction */
9622 return SCIP_OKAY;
9623 }
9624 }
9625 }
9626 assert(gcd >= 2);
9627
9628 /* we should have found one coefficient, that led to a gcd of 1, otherwise we could normalize the constraint
9629 * further
9630 */
9631 assert(((candpos >= offsetv) || (candpos == -1 && offsetv > 0)) && candpos < nvars);
9632
9633 /* determine the remainder of the capacity and the gcd */
9634 rest = consdata->capacity % gcd;
9635 assert(rest >= 0);
9636 assert(rest < gcd);
9637
9638 if( candpos == -1 )
9639 {
9640 /* we assume that the constraint was normalized */
9641 assert(rest > 0);
9642
9643 /* replace old with new capacity */
9644 consdata->capacity -= rest;
9645 ++(*nchgsides);
9646
9647 /* replace old big coefficients with new capacity */
9648 for( v = 0; v < offsetv; ++v )
9649 {
9650 consdataChgWeight(consdata, v, consdata->capacity);
9651 }
9652
9653 *nchgcoefs += offsetv;
9654 goto CONTINUE;
9655 }
9656
9657 /* determine the remainder of the coefficient candidate and the gcd */
9658 restweight = weights[candpos] % gcd;
9659 assert(restweight >= 1);
9660 assert(restweight < gcd);
9661
9662 /* calculate new coefficient */
9663 if( restweight > rest )
9664 newweight = weights[candpos] - restweight + gcd;
9665 else
9666 newweight = weights[candpos] - restweight;
9667
9668 assert(newweight == 0 || SCIPcalcGreComDiv(gcd, newweight) == gcd);
9669
9670 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);
9671
9672 /* must not change weights and capacity if one variable would be removed and we have a big coefficient,
9673 * e.g., 11x1 + 6x2 + 6x3 + 5x4 <= 11 => gcd = 6, offsetv = 1 => newweight = 0, but we would lose x1 = 1 => x4 = 0
9674 */
9675 if( newweight == 0 && offsetv > 0 )
9676 return SCIP_OKAY;
9677
9678 if( rest > 0 )
9679 {
9680 /* replace old with new capacity */
9681 consdata->capacity -= rest;
9682 ++(*nchgsides);
9683
9684 /* replace old big coefficients with new capacity */
9685 for( v = 0; v < offsetv; ++v )
9686 {
9687 consdataChgWeight(consdata, v, consdata->capacity);
9688 }
9689
9690 *nchgcoefs += offsetv;
9691 }
9692
9693 if( newweight == 0 )
9694 {
9695 /* delete redundant coefficient */
9696 SCIP_CALL( delCoefPos(scip, cons, candpos) );
9697 assert(consdata->nvars == nvars - 1);
9698 --nvars;
9699 }
9700 else
9701 {
9702 /* replace old with new coefficient */
9703 consdataChgWeight(consdata, candpos, newweight);
9704 }
9705 ++(*nchgcoefs);
9706
9707 assert(consdata->vars == vars);
9708 assert(consdata->nvars == nvars);
9709 assert(consdata->weights == weights);
9710
9711 CONTINUE:
9712 /* now constraint can be normalized, dividing it by the gcd */
9713 for( v = nvars - 1; v >= 0; --v )
9714 {
9715 consdataChgWeight(consdata, v, weights[v]/gcd);
9716 }
9717 (*nchgcoefs) += nvars;
9718
9719 consdata->capacity /= gcd;
9720 ++(*nchgsides);
9721
9723
9724 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));
9725 }
9726 while( nvars >= 2 );
9727
9728 return SCIP_OKAY;
9729}
9730
9731
9732/** inserts an element into the list of binary zero implications */
9733static
9735 SCIP* scip, /**< SCIP data structure */
9736 int** liftcands, /**< array of the lifting candidates */
9737 int* nliftcands, /**< number of lifting candidates */
9738 int** firstidxs, /**< array of first zeroitems indices */
9739 SCIP_Longint** zeroweightsums, /**< array of sums of weights of the implied-to-zero items */
9740 int** zeroitems, /**< pointer to zero items array */
9741 int** nextidxs, /**< pointer to array of next zeroitems indeces */
9742 int* zeroitemssize, /**< pointer to size of zero items array */
9743 int* nzeroitems, /**< pointer to length of zero items array */
9744 int probindex, /**< problem index of variable y in implication y == v -> x == 0 */
9745 SCIP_Bool value, /**< value v of variable y in implication */
9746 int knapsackidx, /**< index of variable x in knapsack */
9747 SCIP_Longint knapsackweight, /**< weight of variable x in knapsack */
9748 SCIP_Bool* memlimitreached /**< pointer to store whether the memory limit was reached */
9749 )
9750{
9751 int nzeros;
9752
9753 assert(liftcands != NULL);
9754 assert(liftcands[value] != NULL);
9755 assert(nliftcands != NULL);
9756 assert(firstidxs != NULL);
9757 assert(firstidxs[value] != NULL);
9758 assert(zeroweightsums != NULL);
9759 assert(zeroweightsums[value] != NULL);
9760 assert(zeroitems != NULL);
9761 assert(nextidxs != NULL);
9762 assert(zeroitemssize != NULL);
9763 assert(nzeroitems != NULL);
9764 assert(*nzeroitems <= *zeroitemssize);
9765 assert(0 <= probindex && probindex < SCIPgetNVars(scip) - SCIPgetNContVars(scip));
9766 assert(memlimitreached != NULL);
9767
9768 nzeros = *nzeroitems;
9769
9770 /* allocate enough memory */
9771 if( nzeros == *zeroitemssize )
9772 {
9773 /* we explicitly construct the complete implication graph where the knapsack variables are involved;
9774 * this can be too huge - abort on memory limit
9775 */
9776 if( *zeroitemssize >= MAX_ZEROITEMS_SIZE )
9777 {
9778 SCIPdebugMsg(scip, "memory limit of %d bytes reached in knapsack preprocessing - abort collecting zero items\n",
9779 *zeroitemssize);
9780 *memlimitreached = TRUE;
9781 return SCIP_OKAY;
9782 }
9783 *zeroitemssize *= 2;
9784 *zeroitemssize = MIN(*zeroitemssize, MAX_ZEROITEMS_SIZE);
9785 SCIP_CALL( SCIPreallocBufferArray(scip, zeroitems, *zeroitemssize) );
9786 SCIP_CALL( SCIPreallocBufferArray(scip, nextidxs, *zeroitemssize) );
9787 }
9788 assert(nzeros < *zeroitemssize);
9789
9790 if( *memlimitreached )
9791 *memlimitreached = FALSE;
9792
9793 /* insert element */
9794 (*zeroitems)[nzeros] = knapsackidx;
9795 (*nextidxs)[nzeros] = firstidxs[value][probindex];
9796 if( firstidxs[value][probindex] == 0 )
9797 {
9798 liftcands[value][nliftcands[value]] = probindex;
9799 ++nliftcands[value];
9800 }
9801 firstidxs[value][probindex] = nzeros;
9802 ++(*nzeroitems);
9803 zeroweightsums[value][probindex] += knapsackweight;
9804
9805 return SCIP_OKAY;
9806}
9807
9808#define MAX_CLIQUELENGTH 50
9809/** applies rule (3) of the weight tightening procedure, which can lift other variables into the knapsack:
9810 * (3) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
9811 * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
9812 * if cliqueweightsum(xi == v) < capacity:
9813 * - fixing variable xi to v would make the knapsack constraint redundant
9814 * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
9815 * redundancy effect:
9816 * wi' := capacity - cliqueweightsum(xi == v)
9817 * this rule can also be applied to binary variables not in the knapsack!
9818 */
9819static
9821 SCIP* scip, /**< SCIP data structure */
9822 SCIP_CONS* cons, /**< knapsack constraint */
9823 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9824 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9825 )
9826{
9827 SCIP_CONSDATA* consdata;
9828 SCIP_VAR** binvars;
9829 int nbinvars;
9830 int* liftcands[2]; /* binary variables that have at least one entry in zeroitems */
9831 int* firstidxs[2]; /* first index in zeroitems for each binary variable/value pair, or zero for empty list */
9832 SCIP_Longint* zeroweightsums[2]; /* sums of weights of the implied-to-zero items */
9833 int* zeroitems; /* item number in knapsack that is implied to zero */
9834 int* nextidxs; /* next index in zeroitems for the same binary variable, or zero for end of list */
9835 int zeroitemssize;
9836 int nzeroitems;
9837 SCIP_Bool* zeroiteminserted[2];
9838 SCIP_Bool memlimitreached;
9839 int nliftcands[2];
9840 SCIP_Bool* cliqueused;
9841 SCIP_Bool* itemremoved;
9842 SCIP_Longint maxcliqueweightsum;
9843 SCIP_VAR** addvars;
9844 SCIP_Longint* addweights;
9845 SCIP_Longint addweightsum;
9846 int nvars;
9847 int cliquenum;
9848 int naddvars;
9849 int val;
9850 int i;
9851
9852 int* tmpindices;
9853 SCIP_Bool* tmpboolindices;
9854 int* tmpindices2;
9855 SCIP_Bool* tmpboolindices2;
9856 int* tmpindices3;
9857 SCIP_Bool* tmpboolindices3;
9858 int tmp;
9859 int tmp2;
9860 int tmp3;
9861 SCIP_CONSHDLR* conshdlr;
9862 SCIP_CONSHDLRDATA* conshdlrdata;
9863
9864 assert(nchgcoefs != NULL);
9866
9867 consdata = SCIPconsGetData(cons);
9868 assert(consdata != NULL);
9869 assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
9870 assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
9871 assert(consdata->nvars > 0);
9872 assert(consdata->merged);
9873
9874 nvars = consdata->nvars;
9875
9876 /* check if the knapsack has too many items/cliques for applying this costly method */
9877 if( (!consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE) || consdata->ncliques > MAX_USECLIQUES_SIZE )
9878 return SCIP_OKAY;
9879
9880 /* sort items, s.t. the heaviest one is in the first position */
9881 sortItems(consdata);
9882
9883 if( !consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE )
9884 return SCIP_OKAY;
9885
9886 /* we have to consider all integral variables since even integer and implicit integer variables can have binary bounds */
9887 nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
9888 assert(nbinvars > 0);
9889 binvars = SCIPgetVars(scip);
9890
9891 /* get conshdlrdata to use cleared memory */
9892 conshdlr = SCIPconsGetHdlr(cons);
9893 assert(conshdlr != NULL);
9894 conshdlrdata = SCIPconshdlrGetData(conshdlr);
9895 assert(conshdlrdata != NULL);
9896
9897 /* allocate temporary memory for the list of implied to zero variables */
9898 zeroitemssize = MIN(nbinvars, MAX_ZEROITEMS_SIZE); /* initial size of zeroitems buffer */
9899 SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[0], nbinvars) );
9900 SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[1], nbinvars) );
9901
9902 assert(conshdlrdata->ints1size > 0);
9903 assert(conshdlrdata->ints2size > 0);
9904 assert(conshdlrdata->longints1size > 0);
9905 assert(conshdlrdata->longints2size > 0);
9906
9907 /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9908 * than binary + integer variables existed at the presolving initialization method, but for example if you would
9909 * transform all integers into their binary representation then it maybe happens
9910 */
9911 if( conshdlrdata->ints1size < nbinvars )
9912 {
9913 int oldsize = conshdlrdata->ints1size;
9914
9915 conshdlrdata->ints1size = nbinvars;
9916 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints1, oldsize, conshdlrdata->ints1size) );
9917 BMSclearMemoryArray(&(conshdlrdata->ints1[oldsize]), conshdlrdata->ints1size - oldsize); /*lint !e866*/
9918 }
9919 if( conshdlrdata->ints2size < nbinvars )
9920 {
9921 int oldsize = conshdlrdata->ints2size;
9922
9923 conshdlrdata->ints2size = nbinvars;
9924 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints2, oldsize, conshdlrdata->ints2size) );
9925 BMSclearMemoryArray(&(conshdlrdata->ints2[oldsize]), conshdlrdata->ints2size - oldsize); /*lint !e866*/
9926 }
9927 if( conshdlrdata->longints1size < nbinvars )
9928 {
9929 int oldsize = conshdlrdata->longints1size;
9930
9931 conshdlrdata->longints1size = nbinvars;
9932 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints1, oldsize, conshdlrdata->longints1size) );
9933 BMSclearMemoryArray(&(conshdlrdata->longints1[oldsize]), conshdlrdata->longints1size - oldsize); /*lint !e866*/
9934 }
9935 if( conshdlrdata->longints2size < nbinvars )
9936 {
9937 int oldsize = conshdlrdata->longints2size;
9938
9939 conshdlrdata->longints2size = nbinvars;
9940 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints2, oldsize, conshdlrdata->longints2size) );
9941 BMSclearMemoryArray(&(conshdlrdata->longints2[oldsize]), conshdlrdata->longints2size - oldsize); /*lint !e866*/
9942 }
9943
9944 firstidxs[0] = conshdlrdata->ints1;
9945 firstidxs[1] = conshdlrdata->ints2;
9946 zeroweightsums[0] = conshdlrdata->longints1;
9947 zeroweightsums[1] = conshdlrdata->longints2;
9948
9949 /* check for cleared arrays, all entries are zero */
9950#ifndef NDEBUG
9951 for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9952 {
9953 assert(firstidxs[0][tmp] == 0);
9954 assert(firstidxs[1][tmp] == 0);
9955 assert(zeroweightsums[0][tmp] == 0);
9956 assert(zeroweightsums[1][tmp] == 0);
9957 }
9958#endif
9959
9960 SCIP_CALL( SCIPallocBufferArray(scip, &zeroitems, zeroitemssize) );
9961 SCIP_CALL( SCIPallocBufferArray(scip, &nextidxs, zeroitemssize) );
9962
9963 zeroitems[0] = -1; /* dummy element */
9964 nextidxs[0] = -1;
9965 nzeroitems = 1;
9966 nliftcands[0] = 0;
9967 nliftcands[1] = 0;
9968
9969 assert(conshdlrdata->bools1size > 0);
9970 assert(conshdlrdata->bools2size > 0);
9971
9972 /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9973 * than binary + integer variables existed at the presolving initialization method, but for example if you would
9974 * transform all integers into their binary representation then it maybe happens
9975 */
9976 if( conshdlrdata->bools1size < nbinvars )
9977 {
9978 int oldsize = conshdlrdata->bools1size;
9979
9980 conshdlrdata->bools1size = nbinvars;
9981 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools1, oldsize, conshdlrdata->bools1size) );
9982 BMSclearMemoryArray(&(conshdlrdata->bools1[oldsize]), conshdlrdata->bools1size - oldsize); /*lint !e866*/
9983 }
9984 if( conshdlrdata->bools2size < nbinvars )
9985 {
9986 int oldsize = conshdlrdata->bools2size;
9987
9988 conshdlrdata->bools2size = nbinvars;
9989 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools2, oldsize, conshdlrdata->bools2size) );
9990 BMSclearMemoryArray(&(conshdlrdata->bools2[oldsize]), conshdlrdata->bools2size - oldsize); /*lint !e866*/
9991 }
9992
9993 zeroiteminserted[0] = conshdlrdata->bools1;
9994 zeroiteminserted[1] = conshdlrdata->bools2;
9995
9996 /* check for cleared arrays, all entries are zero */
9997#ifndef NDEBUG
9998 for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9999 {
10000 assert(zeroiteminserted[0][tmp] == 0);
10001 assert(zeroiteminserted[1][tmp] == 0);
10002 }
10003#endif
10004
10005 SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices3, consdata->nvars) );
10006 SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices2, 2 * nbinvars) );
10007 SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices3, consdata->nvars) );
10008 SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices2, 2 * nbinvars) );
10009 SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, 2 * nbinvars) );
10010 SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices, 2 * nbinvars) );
10011
10012 tmp2 = 0;
10013 tmp3 = 0;
10014
10015 memlimitreached = FALSE;
10016 for( i = 0; i < consdata->nvars && !memlimitreached; ++i )
10017 {
10018 SCIP_CLIQUE** cliques;
10019 SCIP_VAR* var;
10020 SCIP_Longint weight;
10021 SCIP_Bool value;
10022 int varprobindex;
10023 int ncliques;
10024 int j;
10025
10026 tmp = 0;
10027
10028 /* get corresponding active problem variable */
10029 var = consdata->vars[i];
10030 weight = consdata->weights[i];
10031 value = TRUE;
10033 varprobindex = SCIPvarGetProbindex(var);
10034 assert(0 <= varprobindex && varprobindex < nbinvars);
10035
10036 /* update the zeroweightsum */
10037 zeroweightsums[!value][varprobindex] += weight; /*lint !e514*/
10038 tmpboolindices3[tmp3] = !value;
10039 tmpindices3[tmp3] = varprobindex;
10040 ++tmp3;
10041
10042 /* initialize the arrays of inserted zero items */
10043 /* first add the implications (~x == 1 -> x == 0) */
10044 {
10045 SCIP_Bool implvalue;
10046 int probindex;
10047
10048 probindex = SCIPvarGetProbindex(var);
10049 assert(0 <= probindex && probindex < nbinvars);
10050
10051 implvalue = !value;
10052
10053 /* insert the item into the list of the implied variable/value */
10054 assert( !zeroiteminserted[implvalue][probindex] );
10055
10056 if( firstidxs[implvalue][probindex] == 0 )
10057 {
10058 tmpboolindices2[tmp2] = implvalue;
10059 tmpindices2[tmp2] = probindex;
10060 ++tmp2;
10061 }
10062 SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
10063 &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
10064 &memlimitreached) );
10065 zeroiteminserted[implvalue][probindex] = TRUE;
10066 tmpboolindices[tmp] = implvalue;
10067 tmpindices[tmp] = probindex;
10068 ++tmp;
10069 }
10070
10071 /* get the cliques where the knapsack item is member of with value 1 */
10072 ncliques = SCIPvarGetNCliques(var, value);
10073 cliques = SCIPvarGetCliques(var, value);
10074 for( j = 0; j < ncliques && !memlimitreached; ++j )
10075 {
10076 SCIP_VAR** cliquevars;
10077 SCIP_Bool* cliquevalues;
10078 int ncliquevars;
10079 int k;
10080
10081 ncliquevars = SCIPcliqueGetNVars(cliques[j]);
10082
10083 /* discard big cliques */
10084 if( ncliquevars > MAX_CLIQUELENGTH )
10085 continue;
10086
10087 cliquevars = SCIPcliqueGetVars(cliques[j]);
10088 cliquevalues = SCIPcliqueGetValues(cliques[j]);
10089
10090 for( k = ncliquevars - 1; k >= 0; --k )
10091 {
10092 SCIP_Bool implvalue;
10093 int probindex;
10094
10095 if( var == cliquevars[k] )
10096 continue;
10097
10098 probindex = SCIPvarGetProbindex(cliquevars[k]);
10099 if( probindex == -1 )
10100 continue;
10101
10102 assert(0 <= probindex && probindex < nbinvars);
10103 implvalue = cliquevalues[k];
10104
10105 /* insert the item into the list of the clique variable/value */
10106 if( !zeroiteminserted[implvalue][probindex] )
10107 {
10108 if( firstidxs[implvalue][probindex] == 0 )
10109 {
10110 tmpboolindices2[tmp2] = implvalue;
10111 tmpindices2[tmp2] = probindex;
10112 ++tmp2;
10113 }
10114
10115 SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
10116 &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
10117 &memlimitreached) );
10118 zeroiteminserted[implvalue][probindex] = TRUE;
10119 tmpboolindices[tmp] = implvalue;
10120 tmpindices[tmp] = probindex;
10121 ++tmp;
10122
10123 if( memlimitreached )
10124 break;
10125 }
10126 }
10127 }
10128 /* clear zeroiteminserted */
10129 for( --tmp; tmp >= 0; --tmp)
10130 zeroiteminserted[tmpboolindices[tmp]][tmpindices[tmp]] = FALSE;
10131 }
10132 SCIPfreeBufferArray(scip, &tmpboolindices);
10133
10134 /* calculate the clique partition and the maximal sum of weights using the clique information */
10135 assert(consdata->sorted);
10136 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10137
10138 assert(conshdlrdata->bools3size > 0);
10139
10140 /* next if condition should normally not be true, because it means that presolving has created more binary variables
10141 * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10142 * method, but for example if you would transform all integers into their binary representation then it maybe happens
10143 */
10144 if( conshdlrdata->bools3size < consdata->nvars )
10145 {
10146 int oldsize = conshdlrdata->bools3size;
10147
10148 conshdlrdata->bools3size = consdata->nvars;;
10149 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools3, oldsize, conshdlrdata->bools3size) );
10150 BMSclearMemoryArray(&(conshdlrdata->bools3[oldsize]), conshdlrdata->bools3size - oldsize); /*lint !e866*/
10151 }
10152
10153 cliqueused = conshdlrdata->bools3;
10154
10155 /* check for cleared array, all entries are zero */
10156#ifndef NDEBUG
10157 for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10158 assert(cliqueused[tmp] == 0);
10159#endif
10160
10161 maxcliqueweightsum = 0;
10162 tmp = 0;
10163
10164 /* calculates maximal weight of cliques */
10165 for( i = 0; i < consdata->nvars; ++i )
10166 {
10167 cliquenum = consdata->cliquepartition[i];
10168 assert(0 <= cliquenum && cliquenum < consdata->nvars);
10169
10170 if( !cliqueused[cliquenum] )
10171 {
10172 maxcliqueweightsum += consdata->weights[i];
10173 cliqueused[cliquenum] = TRUE;
10174 tmpindices[tmp] = cliquenum;
10175 ++tmp;
10176 }
10177 }
10178 /* clear cliqueused */
10179 for( --tmp; tmp >= 0; --tmp)
10180 cliqueused[tmp] = FALSE;
10181
10182 assert(conshdlrdata->bools4size > 0);
10183
10184 /* next if condition should normally not be true, because it means that presolving has created more binary variables
10185 * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10186 * method, but for example if you would transform all integers into their binary representation then it maybe happens
10187 */
10188 if( conshdlrdata->bools4size < consdata->nvars )
10189 {
10190 int oldsize = conshdlrdata->bools4size;
10191
10192 conshdlrdata->bools4size = consdata->nvars;
10193 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools4, oldsize, conshdlrdata->bools4size) );
10194 BMSclearMemoryArray(&conshdlrdata->bools4[oldsize], conshdlrdata->bools4size - oldsize); /*lint !e866*/
10195 }
10196
10197 itemremoved = conshdlrdata->bools4;
10198
10199 /* check for cleared array, all entries are zero */
10200#ifndef NDEBUG
10201 for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10202 assert(itemremoved[tmp] == 0);
10203#endif
10204
10205 /* for each binary variable xi and each fixing v, calculate the cliqueweightsum and update the weight of the
10206 * variable in the knapsack (this is sequence-dependent because the new or modified weights have to be
10207 * included in subsequent cliqueweightsum calculations)
10208 */
10209 SCIP_CALL( SCIPallocBufferArray(scip, &addvars, 2*nbinvars) );
10210 SCIP_CALL( SCIPallocBufferArray(scip, &addweights, 2*nbinvars) );
10211 naddvars = 0;
10212 addweightsum = 0;
10213 for( val = 0; val < 2 && addweightsum < consdata->capacity; ++val )
10214 {
10215 for( i = 0; i < nliftcands[val] && addweightsum < consdata->capacity; ++i )
10216 {
10217 SCIP_Longint cliqueweightsum;
10218 int probindex;
10219 int idx;
10220 int j;
10221
10222 tmp = 0;
10223
10224 probindex = liftcands[val][i];
10225 assert(0 <= probindex && probindex < nbinvars);
10226
10227 /* ignore empty zero lists and variables that cannot be lifted anyways */
10228 if( firstidxs[val][probindex] == 0
10229 || maxcliqueweightsum - zeroweightsums[val][probindex] + addweightsum >= consdata->capacity )
10230 continue;
10231
10232 /* mark the items that are implied to zero by setting the current variable to the current value */
10233 for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10234 {
10235 assert(0 < idx && idx < nzeroitems);
10236 assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10237 itemremoved[zeroitems[idx]] = TRUE;
10238 }
10239
10240 /* calculate the residual cliqueweight sum */
10241 cliqueweightsum = addweightsum; /* the previously added items are single-element cliques */
10242 for( j = 0; j < consdata->nvars; ++j )
10243 {
10244 cliquenum = consdata->cliquepartition[j];
10245 assert(0 <= cliquenum && cliquenum < consdata->nvars);
10246 if( !itemremoved[j] )
10247 {
10248 if( !cliqueused[cliquenum] )
10249 {
10250 cliqueweightsum += consdata->weights[j];
10251 cliqueused[cliquenum] = TRUE;
10252 tmpindices[tmp] = cliquenum;
10253 ++tmp;
10254 }
10255
10256 if( cliqueweightsum >= consdata->capacity )
10257 break;
10258 }
10259 }
10260
10261 /* check if the weight of the variable/value can be increased */
10262 if( cliqueweightsum < consdata->capacity )
10263 {
10264 SCIP_VAR* var;
10265 SCIP_Longint weight;
10266
10267 /* insert the variable (with value TRUE) in the list of additional items */
10268 assert(naddvars < 2*nbinvars);
10269 var = binvars[probindex];
10270 if( val == FALSE )
10271 {
10273 }
10274 weight = consdata->capacity - cliqueweightsum;
10275 addvars[naddvars] = var;
10276 addweights[naddvars] = weight;
10277 addweightsum += weight;
10278 naddvars++;
10279
10280 SCIPdebugMsg(scip, "knapsack constraint <%s>: adding lifted item %" SCIP_LONGINT_FORMAT "<%s>\n",
10281 SCIPconsGetName(cons), weight, SCIPvarGetName(var));
10282 }
10283
10284 /* clear itemremoved */
10285 for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10286 {
10287 assert(0 < idx && idx < nzeroitems);
10288 assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10289 itemremoved[zeroitems[idx]] = FALSE;
10290 }
10291 /* clear cliqueused */
10292 for( --tmp; tmp >= 0; --tmp)
10293 cliqueused[tmpindices[tmp]] = FALSE;
10294 }
10295 }
10296
10297 /* clear part of zeroweightsums */
10298 for( --tmp3; tmp3 >= 0; --tmp3)
10299 zeroweightsums[tmpboolindices3[tmp3]][tmpindices3[tmp3]] = 0;
10300
10301 /* clear rest of zeroweightsums and firstidxs */
10302 for( --tmp2; tmp2 >= 0; --tmp2)
10303 {
10304 zeroweightsums[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10305 firstidxs[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10306 }
10307
10308 /* add all additional item weights */
10309 for( i = 0; i < naddvars; ++i )
10310 {
10311 SCIP_CALL( addCoef(scip, cons, addvars[i], addweights[i]) );
10312 }
10313 *nchgcoefs += naddvars;
10314
10315 if( naddvars > 0 )
10316 {
10317 /* if new items were added, multiple entries of the same variable are possible and we have to clean up the constraint */
10319 }
10320
10321 /* free temporary memory */
10322 SCIPfreeBufferArray(scip, &addweights);
10323 SCIPfreeBufferArray(scip, &addvars);
10324 SCIPfreeBufferArray(scip, &tmpindices);
10325 SCIPfreeBufferArray(scip, &tmpindices2);
10326 SCIPfreeBufferArray(scip, &tmpindices3);
10327 SCIPfreeBufferArray(scip, &tmpboolindices2);
10328 SCIPfreeBufferArray(scip, &tmpboolindices3);
10329 SCIPfreeBufferArray(scip, &nextidxs);
10330 SCIPfreeBufferArray(scip, &zeroitems);
10331 SCIPfreeBufferArray(scip, &liftcands[1]);
10332 SCIPfreeBufferArray(scip, &liftcands[0]);
10333
10334 return SCIP_OKAY;
10335}
10336
10337/** tightens item weights and capacity in presolving:
10338 * given a knapsack sum(wi*xi) <= capacity
10339 * (1) let weightsum := sum(wi)
10340 * if weightsum - wi < capacity:
10341 * - not using item i would make the knapsack constraint redundant
10342 * - wi and capacity can be changed to have the same redundancy effect and the same results for
10343 * fixing xi to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10344 * - change coefficients:
10345 * wi' := weightsum - capacity
10346 * capacity' := capacity - (wi - wi')
10347 * (2) increase weights from front to back(sortation is necessary) if there is no space left for another weight
10348 * - determine the four(can be adjusted) minimal weightsums of the knapsack, i.e. in increasing order
10349 * weights[nvars - 1], weights[nvars - 2], MIN(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]),
10350 * MIN(MAX(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]), weights[nvars - 4]), note that there
10351 * can be multiple times the same weight, this can be improved
10352 * - check if summing up a minimal weightsum with a big weight exceeds the capacity, then we can increase the big
10353 * weight, to capacity - lastmininmalweightsum, e.g. :
10354 * 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19
10355 * -> minimal weightsums: 5, 5, 10, 10
10356 * -> 15 + 5 > 19 => increase 15 to 19 - 0 = 19
10357 * -> 10 + 10 > 19 => increase 10 to 19 - 5 = 14, resulting in
10358 * 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10359 * (3) let W(C) be the maximal weight of clique C,
10360 * cliqueweightsum := sum(W(C))
10361 * if cliqueweightsum - W(C) < capacity:
10362 * - not using any item of C would make the knapsack constraint redundant
10363 * - weights wi, i in C, and capacity can be changed to have the same redundancy effect and the same results for
10364 * fixing xi, i in C, to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10365 * - change coefficients:
10366 * delta := capacity - (cliqueweightsum - W(C))
10367 * wi' := max(wi - delta, 0)
10368 * capacity' := capacity - delta
10369 * This rule has to add the used cliques in order to ensure they are enforced - otherwise, the reduction might
10370 * introduce infeasible solutions.
10371 * (4) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
10372 * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
10373 * if cliqueweightsum(xi == v) < capacity:
10374 * - fixing variable xi to v would make the knapsack constraint redundant
10375 * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
10376 * redundancy effect:
10377 * wi' := capacity - cliqueweightsum(xi == v)
10378 * This rule can also be applied to binary variables not in the knapsack!
10379 * (5) if min{w} + wi > capacity:
10380 * - using item i would force to fix other items to zero
10381 * - wi can be increased to the capacity
10382 */
10383static
10385 SCIP* scip, /**< SCIP data structure */
10386 SCIP_CONS* cons, /**< knapsack constraint */
10387 SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
10388 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10389 int* nchgsides, /**< pointer to count number of side changes */
10390 int* naddconss, /**< pointer to count number of added constraints */
10391 int* ndelconss, /**< pointer to count number of deleted constraints */
10392 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
10393 )
10394{
10395 SCIP_CONSHDLRDATA* conshdlrdata;
10396 SCIP_CONSDATA* consdata;
10397 SCIP_Longint* weights;
10398 SCIP_Longint sumcoef;
10399 SCIP_Longint capacity;
10400 SCIP_Longint newweight;
10401 SCIP_Longint maxweight;
10402 SCIP_Longint minweight;
10403 SCIP_Bool sumcoefcase = FALSE;
10404 int startpos;
10405 int backpos;
10406 int nvars;
10407 int pos;
10408 int k;
10409 int i;
10410
10411 assert(nchgcoefs != NULL);
10412 assert(nchgsides != NULL);
10414
10415 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
10416 assert(conshdlrdata != NULL);
10417
10418 consdata = SCIPconsGetData(cons);
10419 assert(consdata != NULL);
10420 assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
10421 assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
10422 assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
10423 assert(consdata->nvars > 0);
10424
10426 if( *cutoff )
10427 return SCIP_OKAY;
10428
10429 /* apply rule (1) */
10430 if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10431 {
10432 do
10433 {
10434 assert(consdata->merged);
10435
10436 /* sort items, s.t. the heaviest one is in the first position */
10437 sortItems(consdata);
10438
10439 for( i = 0; i < consdata->nvars; ++i )
10440 {
10441 SCIP_Longint weight;
10442
10443 weight = consdata->weights[i];
10444 if( consdata->weightsum - weight < consdata->capacity )
10445 {
10446 newweight = consdata->weightsum - consdata->capacity;
10447 consdataChgWeight(consdata, i, newweight);
10448 consdata->capacity -= (weight - newweight);
10449 (*nchgcoefs)++;
10450 (*nchgsides)++;
10451 assert(!consdata->sorted);
10452 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",
10453 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, newweight,
10454 consdata->capacity + (weight-newweight), consdata->capacity);
10455 }
10456 else
10457 break;
10458 }
10459 }
10460 while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10461 }
10462
10463 /* check for redundancy */
10464 if( consdata->weightsum <= consdata->capacity )
10465 return SCIP_OKAY;
10466
10467 pos = 0;
10468 while( pos < consdata->nvars && consdata->weights[pos] == consdata->capacity )
10469 ++pos;
10470
10471 sumcoef = 0;
10472 weights = consdata->weights;
10473 nvars = consdata->nvars;
10474 capacity = consdata->capacity;
10475
10476 if( (presoltiming & (SCIP_PRESOLTIMING_FAST | SCIP_PRESOLTIMING_MEDIUM)) != 0 &&
10477 pos < nvars && weights[pos] + weights[pos + 1] > capacity )
10478 {
10479 /* further reductions using the next possible coefficient sum
10480 *
10481 * e.g. 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19 <=> 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10482 */
10483 /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
10484 for( k = 0; k < 4; ++k )
10485 {
10486 newweight = capacity - sumcoef;
10487
10488 /* determine next minimal coefficient sum */
10489 switch( k )
10490 {
10491 case 0:
10492 sumcoef = weights[nvars - 1];
10493 backpos = nvars - 1;
10494 break;
10495 case 1:
10496 sumcoef = weights[nvars - 2];
10497 backpos = nvars - 2;
10498 break;
10499 case 2:
10500 if( weights[nvars - 3] < weights[nvars - 1] + weights[nvars - 2] )
10501 {
10502 sumcoefcase = TRUE;
10503 sumcoef = weights[nvars - 3];
10504 backpos = nvars - 3;
10505 }
10506 else
10507 {
10508 sumcoefcase = FALSE;
10509 sumcoef = weights[nvars - 1] + weights[nvars - 2];
10510 backpos = nvars - 2;
10511 }
10512 break;
10513 default:
10514 assert(k == 3);
10515 if( sumcoefcase )
10516 {
10517 if( weights[nvars - 4] < weights[nvars - 1] + weights[nvars - 2] )
10518 {
10519 sumcoef = weights[nvars - 4];
10520 backpos = nvars - 4;
10521 }
10522 else
10523 {
10524 sumcoef = weights[nvars - 1] + weights[nvars - 2];
10525 backpos = nvars - 2;
10526 }
10527 }
10528 else
10529 {
10530 sumcoef = weights[nvars - 3];
10531 backpos = nvars - 3;
10532 }
10533 break;
10534 }
10535
10536 if( backpos <= pos )
10537 break;
10538
10539 /* tighten next coefficients that, paired with the current small coefficient, exceed the capacity */
10540 maxweight = weights[pos];
10541 startpos = pos;
10542 while( 2 * maxweight > capacity && maxweight + sumcoef > capacity )
10543 {
10544 assert(newweight > weights[pos]);
10545
10546 SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10547 SCIPconsGetName(cons), maxweight, newweight);
10548
10549 consdataChgWeight(consdata, pos, newweight);
10550
10551 ++pos;
10552 assert(pos < nvars);
10553
10554 maxweight = weights[pos];
10555
10556 if( backpos <= pos )
10557 break;
10558 }
10559 (*nchgcoefs) += (pos - startpos);
10560
10561 /* skip unchangable weights */
10562 while( pos < nvars && weights[pos] + sumcoef == capacity )
10563 ++pos;
10564
10565 /* check special case were there is only one weight left to tighten
10566 *
10567 * e.g. 95x1 + 59x2 + 37x3 + 36x4 <= 95 (37 > 36)
10568 *
10569 * => 95x1 + 59x2 + 59x3 + 36x4 <= 95
10570 *
10571 * 197x1 + 120x2 + 77x3 + 10x4 <= 207 (here we cannot tighten the coefficient further)
10572 */
10573 if( pos + 1 == backpos && weights[pos] > sumcoef &&
10574 ((k == 0) || (k == 1 && weights[nvars - 1] + sumcoef + weights[pos] > capacity)) )
10575 {
10576 newweight = capacity - sumcoef;
10577 assert(newweight > weights[pos]);
10578
10579 SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10580 SCIPconsGetName(cons), maxweight, newweight);
10581
10582 consdataChgWeight(consdata, pos, newweight);
10583
10584 break;
10585 }
10586
10587 if( backpos <= pos )
10588 break;
10589 }
10590 }
10591
10592 /* apply rule (2) (don't apply, if the knapsack has too many items for applying this costly method) */
10593 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
10594 {
10595 if( conshdlrdata->disaggregation && SCIPconsGetNUpgradeLocks(cons) == 0
10596 && consdata->nvars - pos <= MAX_USECLIQUES_SIZE && consdata->nvars >= 2 && pos > 0
10597 && (SCIP_Longint)consdata->nvars - pos <= consdata->capacity
10598 && consdata->weights[pos - 1] == consdata->capacity
10599 && ( pos == consdata->nvars || consdata->weights[pos] == 1 ) )
10600 {
10601 SCIP_VAR** clqvars;
10602 SCIP_CONS* cliquecons;
10603 char name[SCIP_MAXSTRLEN];
10604 int* clqpart;
10605 int nclqvars;
10606 int nclq;
10607 int len;
10608 int c;
10609 int w;
10610
10611 assert(!SCIPconsIsDeleted(cons));
10612
10613 if( pos == consdata->nvars )
10614 {
10615 SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
10616
10617 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, SCIPconsGetName(cons), pos, consdata->vars,
10621 SCIPconsIsStickingAtNode(cons)) );
10622
10623 /* add the upgraded constraint to the problem */
10624 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10625 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10626 ++(*naddconss);
10627
10628 /* delete old constraint */
10629 SCIP_CALL( SCIPdelCons(scip, cons) );
10630 ++(*ndelconss);
10631
10632 return SCIP_OKAY;
10633 }
10634
10635 len = consdata->nvars - pos;
10636
10637 /* allocate temporary memory */
10638 SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
10639
10640 /* calculate clique partition */
10641 SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[pos]), len, &conshdlrdata->probtoidxmap, &conshdlrdata->probtoidxmapsize, clqpart, &nclq) );
10642 assert(nclq <= len);
10643
10644#ifndef NDEBUG
10645 /* clique numbers must be at least as high as the index */
10646 for( w = 0; w < nclq; ++w )
10647 assert(clqpart[w] <= w);
10648#endif
10649
10650 SCIPdebugMsg(scip, "Disaggregating knapsack constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
10651
10652 /* allocate temporary memory */
10653 SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, pos + len - nclq + 1) );
10654
10655 /* copy corresponding variables with big coefficients */
10656 for( w = pos - 1; w >= 0; --w )
10657 clqvars[w] = consdata->vars[w];
10658
10659 /* create for each clique a set-packing constraint */
10660 for( c = 0; c < nclq; ++c )
10661 {
10662 nclqvars = pos;
10663
10664 for( w = c; w < len; ++w )
10665 {
10666 if( clqpart[w] == c )
10667 {
10668 assert(nclqvars < pos + len - nclq + 1);
10669 clqvars[nclqvars] = consdata->vars[w + pos];
10670 ++nclqvars;
10671 }
10672 }
10673
10674 assert(nclqvars > 1);
10675
10676 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, c);
10677 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
10681 SCIPconsIsStickingAtNode(cons)) );
10682
10683 /* add the special constraint to the problem */
10684 SCIPdebugMsg(scip, " -> adding clique constraint: ");
10685 SCIPdebugPrintCons(scip, cliquecons, NULL);
10686 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10687 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10688 ++(*naddconss);
10689 }
10690
10691 /* delete old constraint */
10692 SCIP_CALL( SCIPdelCons(scip, cons) );
10693 ++(*ndelconss);
10694
10695 SCIPfreeBufferArray(scip, &clqvars);
10696 SCIPfreeBufferArray(scip, &clqpart);
10697
10698 return SCIP_OKAY;
10699 }
10700 else if( consdata->nvars <= MAX_USECLIQUES_SIZE || (consdata->cliquepartitioned && consdata->ncliques <= MAX_USECLIQUES_SIZE) )
10701 {
10702 SCIP_Longint* maxcliqueweights;
10703 SCIP_Longint* newweightvals;
10704 int* newweightidxs;
10705 SCIP_Longint cliqueweightsum;
10706
10707 SCIP_CALL( SCIPallocBufferArray(scip, &maxcliqueweights, consdata->nvars) );
10708 SCIP_CALL( SCIPallocBufferArray(scip, &newweightvals, consdata->nvars) );
10709 SCIP_CALL( SCIPallocBufferArray(scip, &newweightidxs, consdata->nvars) );
10710
10711 /* repeat as long as changes have been applied */
10712 do
10713 {
10714 int ncliques;
10715 int cliquenum;
10716 SCIP_Bool zeroweights;
10717
10718 assert(consdata->merged);
10719
10720 /* sort items, s.t. the heaviest one is in the first position */
10721 sortItems(consdata);
10722
10723 /* calculate a clique partition */
10724 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10725
10726 /* if there are only single element cliques, rule (2) is equivalent to rule (1) */
10727 if( consdata->cliquepartition[consdata->nvars - 1] == consdata->nvars - 1 )
10728 break;
10729
10730 /* calculate the maximal weight of the cliques and store the clique type */
10731 cliqueweightsum = 0;
10732 ncliques = 0;
10733
10734 for( i = 0; i < consdata->nvars; ++i )
10735 {
10736 SCIP_Longint weight;
10737
10738 cliquenum = consdata->cliquepartition[i];
10739 assert(0 <= cliquenum && cliquenum <= ncliques);
10740
10741 weight = consdata->weights[i];
10742 assert(weight > 0);
10743
10744 if( cliquenum == ncliques )
10745 {
10746 maxcliqueweights[ncliques] = weight;
10747 cliqueweightsum += weight;
10748 ++ncliques;
10749 }
10750
10751 assert(maxcliqueweights[cliquenum] >= weight);
10752 }
10753
10754 /* apply rule on every clique */
10755 zeroweights = FALSE;
10756 for( i = 0; i < ncliques; ++i )
10757 {
10758 SCIP_Longint delta;
10759
10760 delta = consdata->capacity - (cliqueweightsum - maxcliqueweights[i]);
10761 if( delta > 0 )
10762 {
10763 SCIP_Longint newcapacity;
10764#ifndef NDEBUG
10765 SCIP_Longint newmincliqueweight;
10766#endif
10767 SCIP_Longint newminweightsuminclique;
10768 SCIP_Bool forceclique;
10769 int nnewweights;
10770 int j;
10771
10772 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",
10773 SCIPconsGetName(cons), i, maxcliqueweights[i], cliqueweightsum, consdata->capacity, delta);
10774 newcapacity = consdata->capacity - delta;
10775 forceclique = FALSE;
10776 nnewweights = 0;
10777#ifndef NDEBUG
10778 newmincliqueweight = newcapacity + 1;
10779 for( j = 0; j < i; ++j )
10780 assert(consdata->cliquepartition[j] < i); /* no element j < i can be in clique i */
10781#endif
10782 for( j = i; j < consdata->nvars; ++j )
10783 {
10784 if( consdata->cliquepartition[j] == i )
10785 {
10786 newweight = consdata->weights[j] - delta;
10787 newweight = MAX(newweight, 0);
10788
10789 /* cache the new weight */
10790 assert(nnewweights < consdata->nvars);
10791 newweightvals[nnewweights] = newweight;
10792 newweightidxs[nnewweights] = j;
10793 nnewweights++;
10794
10795#ifndef NDEBUG
10796 assert(newweight <= newmincliqueweight); /* items are sorted by non-increasing weight! */
10797 newmincliqueweight = newweight;
10798#endif
10799 }
10800 }
10801
10802 /* check if our clique information results out of this knapsack constraint and if so check if we would loose the clique information */
10803 if( nnewweights > 1 )
10804 {
10805#ifndef NDEBUG
10806 j = newweightidxs[nnewweights - 2];
10807 assert(0 <= j && j < consdata->nvars);
10808 assert(consdata->cliquepartition[j] == i);
10809 j = newweightidxs[nnewweights - 1];
10810 assert(0 <= j && j < consdata->nvars);
10811 assert(consdata->cliquepartition[j] == i);
10812#endif
10813
10814 newminweightsuminclique = newweightvals[nnewweights - 2];
10815 newminweightsuminclique += newweightvals[nnewweights - 1];
10816
10817 /* check if these new two minimal weights both fit into the knapsack;
10818 * if this is true, we have to add a clique constraint in order to enforce the clique
10819 * (otherwise, the knapsack might have been one of the reasons for the clique, and the weight
10820 * reduction might be infeasible, i.e., allows additional solutions)
10821 */
10822 if( newminweightsuminclique <= newcapacity )
10823 forceclique = TRUE;
10824 }
10825
10826 /* check if we really want to apply the change */
10827 if( conshdlrdata->disaggregation || !forceclique )
10828 {
10829 SCIPdebugMsg(scip, " -> change capacity from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT " (forceclique:%u)\n",
10830 consdata->capacity, newcapacity, forceclique);
10831 consdata->capacity = newcapacity;
10832 (*nchgsides)++;
10833
10834 for( k = 0; k < nnewweights; ++k )
10835 {
10836 j = newweightidxs[k];
10837 assert(0 <= j && j < consdata->nvars);
10838 assert(consdata->cliquepartition[j] == i);
10839
10840 /* apply the weight change */
10841 SCIPdebugMsg(scip, " -> change weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10842 SCIPvarGetName(consdata->vars[j]), consdata->weights[j], newweightvals[k]);
10843 consdataChgWeight(consdata, j, newweightvals[k]);
10844 (*nchgcoefs)++;
10845 assert(!consdata->sorted);
10846 zeroweights = zeroweights || (newweightvals[k] == 0);
10847 }
10848 /* if before the weight update at least one pair of weights did not fit into the knapsack and now fits,
10849 * we have to make sure, the clique is enforced - the clique might have been constructed partially from
10850 * this constraint, and by reducing the weights, this clique information is not contained anymore in the
10851 * knapsack constraint
10852 */
10853 if( forceclique )
10854 {
10855 SCIP_CONS* cliquecons;
10856 char name[SCIP_MAXSTRLEN];
10857 SCIP_VAR** cliquevars;
10858
10859 SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nnewweights) );
10860 for( k = 0; k < nnewweights; ++k )
10861 cliquevars[k] = consdata->vars[newweightidxs[k]];
10862
10863 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, i);
10864 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nnewweights, cliquevars,
10868 SCIPconsIsStickingAtNode(cons)) );
10869
10870 /* add the special constraint to the problem */
10871 SCIPdebugMsg(scip, " -> adding clique constraint: ");
10872 SCIPdebugPrintCons(scip, cliquecons, NULL);
10873 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10874 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10875 ++(*naddconss);
10876
10877 /* free clique array */
10878 SCIPfreeBufferArray(scip, &cliquevars);
10879 }
10880 }
10881 }
10882 }
10883 if( zeroweights )
10884 {
10886 }
10887 }
10888 while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10889
10890 /* free temporary memory */
10891 SCIPfreeBufferArray(scip, &newweightidxs);
10892 SCIPfreeBufferArray(scip, &newweightvals);
10893 SCIPfreeBufferArray(scip, &maxcliqueweights);
10894
10895 /* check for redundancy */
10896 if( consdata->weightsum <= consdata->capacity )
10897 return SCIP_OKAY;
10898 }
10899 }
10900
10901 /* apply rule (3) */
10902 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
10903 {
10904 SCIP_CALL( tightenWeightsLift(scip, cons, nchgcoefs, cutoff) );
10905 }
10906
10907 /* check for redundancy */
10908 if( consdata->weightsum <= consdata->capacity )
10909 return SCIP_OKAY;
10910
10911 if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10912 {
10913 /* apply rule (4) (all but smallest weight) */
10914 assert(consdata->merged);
10915 sortItems(consdata);
10916 minweight = consdata->weights[consdata->nvars-1];
10917 for( i = 0; i < consdata->nvars-1; ++i )
10918 {
10919 SCIP_Longint weight;
10920
10921 weight = consdata->weights[i];
10922 assert(weight >= minweight);
10923 if( minweight + weight > consdata->capacity )
10924 {
10925 if( weight < consdata->capacity )
10926 {
10927 SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10928 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, consdata->capacity);
10929 assert(consdata->sorted);
10930 consdataChgWeight(consdata, i, consdata->capacity); /* this does not destroy the weight order! */
10931 assert(i == 0 || consdata->weights[i-1] >= consdata->weights[i]);
10932 consdata->sorted = TRUE;
10933 (*nchgcoefs)++;
10934 }
10935 }
10936 else
10937 break;
10938 }
10939
10940 /* apply rule (5) (smallest weight) */
10941 if( consdata->nvars >= 2 )
10942 {
10943 SCIP_Longint weight;
10944
10945 minweight = consdata->weights[consdata->nvars-2];
10946 weight = consdata->weights[consdata->nvars-1];
10947 assert(minweight >= weight);
10948 if( minweight + weight > consdata->capacity && weight < consdata->capacity )
10949 {
10950 SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10951 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[consdata->nvars-1]), weight, consdata->capacity);
10952 assert(consdata->sorted);
10953 consdataChgWeight(consdata, consdata->nvars-1, consdata->capacity); /* this does not destroy the weight order! */
10954 assert(minweight >= consdata->weights[consdata->nvars-1]);
10955 consdata->sorted = TRUE;
10956 (*nchgcoefs)++;
10957 }
10958 }
10959 }
10960
10961 return SCIP_OKAY;
10962}
10963
10964
10965#ifdef SCIP_DEBUG
10966static
10967void printClique(
10968 SCIP_VAR** cliquevars,
10969 int ncliquevars
10970 )
10971{
10972 int b;
10973 SCIPdebugMessage("adding new Clique: ");
10974 for( b = 0; b < ncliquevars; ++b )
10975 SCIPdebugPrintf("%s ", SCIPvarGetName(cliquevars[b]));
10976 SCIPdebugPrintf("\n");
10977}
10978#endif
10979
10980/** adds negated cliques of the knapsack constraint to the global clique table */
10981static
10983 SCIP*const scip, /**< SCIP data structure */
10984 SCIP_CONS*const cons, /**< knapsack constraint */
10985 SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
10986 int*const nbdchgs /**< pointer to count the number of performed bound changes */
10987 )
10988{
10989 SCIP_CONSDATA* consdata;
10990 SCIP_CONSHDLRDATA* conshdlrdata;
10991 SCIP_VAR** poscliquevars;
10992 SCIP_VAR** cliquevars;
10993 SCIP_Longint* maxweights;
10994 SCIP_Longint* gainweights;
10995 int* gaincliquepartition;
10996 SCIP_Bool* cliqueused;
10997 SCIP_Longint minactduetonegcliques;
10998 SCIP_Longint freecapacity;
10999 SCIP_Longint lastweight;
11000 SCIP_Longint beforelastweight;
11001 int nposcliquevars;
11002 int ncliquevars;
11003 int nvars;
11004 int nnegcliques;
11005 int lastcliqueused;
11006 int thisnbdchgs;
11007 int v;
11008 int w;
11009
11010 assert(scip != NULL);
11011 assert(cons != NULL);
11012 assert(cutoff != NULL);
11013 assert(nbdchgs != NULL);
11014
11015 *cutoff = FALSE;
11016
11017 consdata = SCIPconsGetData(cons);
11018 assert(consdata != NULL);
11019
11020 nvars = consdata->nvars;
11021
11022 /* check whether the cliques have already been added */
11023 if( consdata->cliquesadded || nvars == 0 )
11024 return SCIP_OKAY;
11025
11026 /* make sure, the items are merged */
11028 if( *cutoff )
11029 return SCIP_OKAY;
11030
11031 /* make sure, items are sorted by non-increasing weight */
11032 sortItems(consdata);
11033
11034 assert(consdata->merged);
11035
11036 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11037 assert(conshdlrdata != NULL);
11038
11039 /* calculate a clique partition */
11040 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
11041 nnegcliques = consdata->nnegcliques;
11042
11043 /* if we have no negated cliques, stop */
11044 if( nnegcliques == nvars )
11045 return SCIP_OKAY;
11046
11047 /* get temporary memory */
11048 SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
11049 SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
11050 SCIP_CALL( SCIPallocClearBufferArray(scip, &gainweights, nvars) );
11051 SCIP_CALL( SCIPallocBufferArray(scip, &gaincliquepartition, nvars) );
11052 SCIP_CALL( SCIPallocBufferArray(scip, &maxweights, nnegcliques) );
11053 SCIP_CALL( SCIPallocClearBufferArray(scip, &cliqueused, nnegcliques) );
11054
11055 nnegcliques = 0;
11056 minactduetonegcliques = 0;
11057
11058 /* determine maximal weights for all negated cliques and calculate minimal weightsum due to negated cliques */
11059 for( v = 0; v < nvars; ++v )
11060 {
11061 assert(0 <= consdata->negcliquepartition[v] && consdata->negcliquepartition[v] <= nnegcliques);
11062 assert(consdata->weights[v] > 0);
11063
11064 if( consdata->negcliquepartition[v] == nnegcliques )
11065 {
11066 nnegcliques++;
11067 maxweights[consdata->negcliquepartition[v]] = consdata->weights[v];
11068 }
11069 else
11070 minactduetonegcliques += consdata->weights[v];
11071 }
11072
11073 nposcliquevars = 0;
11074
11075 /* add cliques, using negated cliques information */
11076 if( minactduetonegcliques > 0 )
11077 {
11078 /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11079 freecapacity = consdata->capacity - minactduetonegcliques;
11080
11082 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",
11083 SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11084
11085 /* calculate possible gain by switching chosen items in negated cliques */
11086 for( v = 0; v < nvars; ++v )
11087 {
11088 if( !cliqueused[consdata->negcliquepartition[v]] )
11089 {
11090 cliqueused[consdata->negcliquepartition[v]] = TRUE;
11091 for( w = v + 1; w < nvars; ++w )
11092 {
11093 /* if we would take the biggest weight instead of another what would we gain, take weight[v] instead of
11094 * weight[w] (which are both in a negated clique) */
11095 if( consdata->negcliquepartition[v] == consdata->negcliquepartition[w]
11096 && consdata->weights[v] > consdata->weights[w] )
11097 {
11098 poscliquevars[nposcliquevars] = consdata->vars[w];
11099 gainweights[nposcliquevars] = maxweights[consdata->negcliquepartition[v]] - consdata->weights[w];
11100 gaincliquepartition[nposcliquevars] = consdata->negcliquepartition[v];
11101 ++nposcliquevars;
11102 }
11103 }
11104 }
11105 }
11106
11107 /* try to create negated cliques */
11108 if( nposcliquevars > 0 )
11109 {
11110 /* sort possible gain per substitution of the clique members */
11111 SCIPsortDownLongPtrInt(gainweights,(void**) poscliquevars, gaincliquepartition, nposcliquevars);
11112
11113 for( v = 0; v < nposcliquevars; ++v )
11114 {
11115 SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[v], &cliquevars[0]) );
11116 ncliquevars = 1;
11117 lastweight = gainweights[v];
11118 beforelastweight = -1;
11119 lastcliqueused = gaincliquepartition[v];
11120 /* clear cliqueused to get an unused array */
11121 BMSclearMemoryArray(cliqueused, nnegcliques);
11122 cliqueused[gaincliquepartition[v]] = TRUE;
11123
11124 /* taking bigger weights make the knapsack redundant so we will create cliques, only take items which are not
11125 * in the same negated clique and by taking two of them would exceed the free capacity */
11127 {
11128 beforelastweight = lastweight;
11129 lastweight = gainweights[w];
11130 lastcliqueused = gaincliquepartition[w];
11131 cliqueused[gaincliquepartition[w]] = TRUE;
11132 SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars]) );
11133 ++ncliquevars;
11134 }
11135
11136 if( ncliquevars > 1 )
11137 {
11138 SCIPdebug( printClique(cliquevars, ncliquevars) );
11139 assert(beforelastweight > 0);
11140 /* add the clique to the clique table */
11141 /* this really happens, e.g., on enigma.mps from the short test set */
11142 SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11143 if( *cutoff )
11144 goto TERMINATE;
11145 *nbdchgs += thisnbdchgs;
11146
11147 /* reset last used clique to get slightly different cliques */
11148 cliqueused[lastcliqueused] = FALSE;
11149
11150 /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11152 {
11153 SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars - 1]) );
11154 SCIPdebug( printClique(cliquevars, ncliquevars) );
11155 SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11156 if( *cutoff )
11157 goto TERMINATE;
11158 *nbdchgs += thisnbdchgs;
11159 }
11160 }
11161 }
11162 }
11163 }
11164
11165 TERMINATE:
11166 /* free temporary memory */
11167 SCIPfreeBufferArray(scip, &cliqueused);
11168 SCIPfreeBufferArray(scip, &maxweights);
11169 SCIPfreeBufferArray(scip, &gaincliquepartition);
11170 SCIPfreeBufferArray(scip, &gainweights);
11171 SCIPfreeBufferArray(scip, &cliquevars);
11172 SCIPfreeBufferArray(scip, &poscliquevars);
11173
11174 return SCIP_OKAY;
11175}
11176
11177/** greedy clique detection by considering weights and capacity
11178 *
11179 * greedily detects cliques by first sorting the items by decreasing weights (optional) and then collecting greedily
11180 * 1) neighboring items which exceed the capacity together => one clique
11181 * 2) looping through the remaining items and finding the largest set of preceding items to build a clique => possibly many more cliques
11182 */
11183static
11185 SCIP*const scip, /**< SCIP data structure */
11186 SCIP_VAR** items, /**< array of variable items */
11187 SCIP_Longint* weights, /**< weights of the items */
11188 int nitems, /**< the number of items */
11189 SCIP_Longint capacity, /**< maximum free capacity of the knapsack */
11190 SCIP_Bool sorteditems, /**< are the items sorted by their weights nonincreasing? */
11191 SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11192 SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11193 int*const nbdchgs /**< pointer to count the number of performed bound changes */
11194 )
11195{
11196 SCIP_Longint lastweight;
11197 int ncliquevars;
11198 int i;
11199 int thisnbdchgs;
11200
11201 if( nitems <= 1 )
11202 return SCIP_OKAY;
11203
11204 /* sort possible gain per substitution of the clique members */
11205 if( ! sorteditems )
11206 SCIPsortDownLongPtr(weights,(void**) items, nitems);
11207
11208 ncliquevars = 1;
11209 lastweight = weights[0];
11210
11211 /* taking these two weights together violates the knapsack => include into clique */
11212 for( i = 1; i < nitems && weights[i] + lastweight > capacity; ++i )
11213 {
11214 lastweight = weights[i];
11215 ++ncliquevars;
11216 }
11217
11218 if( ncliquevars > 1 )
11219 {
11220 SCIP_Longint compareweight;
11221 SCIP_VAR** cliquevars;
11222 int compareweightidx;
11223 int minclqsize;
11224 int nnzadded;
11225
11226 /* add the clique to the clique table */
11227 SCIPdebug( printClique(items, ncliquevars) );
11228 SCIP_CALL( SCIPaddClique(scip, items, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11229
11230 if( *cutoff )
11231 return SCIP_OKAY;
11232
11233 *nbdchgs += thisnbdchgs;
11234 nnzadded = ncliquevars;
11235
11236 /* 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)*/
11237 if( ncliquevars == nitems )
11238 return SCIP_OKAY;
11239
11240 /* copy items in order into buffer array and deduce more cliques */
11241 SCIP_CALL( SCIPduplicateBufferArray(scip, &cliquevars, items, ncliquevars) );
11242
11243 /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11244 /* loop over remaining, smaller items and compare each item backwards against larger weights, starting with the second smallest weight */
11245 compareweightidx = ncliquevars - 2;
11246 assert(i == nitems || weights[i] + weights[ncliquevars - 1] <= capacity);
11247
11248 /* determine minimum clique size for the following loop */
11249 minclqsize = (int)(cliqueextractfactor * ncliquevars);
11250 minclqsize = MAX(minclqsize, 2);
11251
11252 /* loop over the remaining variables and the larger items of the first clique until we
11253 * find another clique or reach the size limit */
11254 while( compareweightidx >= 0 && i < nitems && ! (*cutoff)
11255 && ncliquevars >= minclqsize /* stop at a given minimum clique size */
11256 && nnzadded <= 2 * nitems /* stop if enough nonzeros were added to the cliquetable */
11257 )
11258 {
11259 compareweight = weights[compareweightidx];
11260 assert(compareweight > 0);
11261
11262 /* include this item together with all items that have a weight at least as large as the compare weight in a clique */
11263 if( compareweight + weights[i] > capacity )
11264 {
11265 assert(compareweightidx == ncliquevars -2);
11266 cliquevars[ncliquevars - 1] = items[i];
11267 SCIPdebug( printClique(cliquevars, ncliquevars) );
11268 SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11269
11270 nnzadded += ncliquevars;
11271
11272 /* stop when there is a cutoff */
11273 if( ! (*cutoff) )
11274 *nbdchgs += thisnbdchgs;
11275
11276 /* go to next smaller item */
11277 ++i;
11278 }
11279 else
11280 {
11281 /* choose a preceding, larger weight to compare small items against. Clique size is reduced by 1 simultaneously */
11282 compareweightidx--;
11283 ncliquevars --;
11284 }
11285 }
11286
11287 SCIPfreeBufferArray(scip, &cliquevars);
11288 }
11289
11290 return SCIP_OKAY;
11291}
11292
11293/** adds cliques of the knapsack constraint to the global clique table */
11294static
11296 SCIP*const scip, /**< SCIP data structure */
11297 SCIP_CONS*const cons, /**< knapsack constraint */
11298 SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11299 SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11300 int*const nbdchgs /**< pointer to count the number of performed bound changes */
11301 )
11302{
11303 SCIP_CONSDATA* consdata;
11304 SCIP_CONSHDLRDATA* conshdlrdata;
11305 int i;
11306 SCIP_Longint minactduetonegcliques;
11307 SCIP_Longint freecapacity;
11308 int nnegcliques;
11309 int cliquenum;
11310 SCIP_VAR** poscliquevars;
11311 SCIP_Longint* gainweights;
11312 int nposcliquevars;
11313 SCIP_Longint* secondmaxweights;
11314 int nvars;
11315
11316 assert(scip != NULL);
11317 assert(cons != NULL);
11318 assert(cutoff != NULL);
11319 assert(nbdchgs != NULL);
11320
11321 *cutoff = FALSE;
11322
11323 consdata = SCIPconsGetData(cons);
11324 assert(consdata != NULL);
11325
11326 nvars = consdata->nvars;
11327
11328 /* check whether the cliques have already been added */
11329 if( consdata->cliquesadded || nvars == 0 )
11330 return SCIP_OKAY;
11331
11332 /* make sure, the items are merged */
11334 if( *cutoff )
11335 return SCIP_OKAY;
11336
11337 /* make sure, the items are sorted by non-increasing weight */
11338 sortItems(consdata);
11339
11340 assert(consdata->merged);
11341
11342 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11343 assert(conshdlrdata != NULL);
11344
11345 /* calculate a clique partition */
11346 SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
11347 nnegcliques = consdata->nnegcliques;
11348 assert(nnegcliques <= nvars);
11349
11350 /* get temporary memory */
11351 SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
11352 SCIP_CALL( SCIPallocBufferArray(scip, &gainweights, nvars) );
11353 BMSclearMemoryArray(gainweights, nvars);
11354 SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
11355 BMSclearMemoryArray(secondmaxweights, nnegcliques);
11356
11357 minactduetonegcliques = 0;
11358
11359 /* calculate minimal activity due to negated cliques, and determine second maximal weight in each clique */
11360 if( nnegcliques < nvars )
11361 {
11362 nnegcliques = 0;
11363
11364 for( i = 0; i < nvars; ++i )
11365 {
11366 SCIP_Longint weight;
11367
11368 cliquenum = consdata->negcliquepartition[i];
11369 assert(0 <= cliquenum && cliquenum <= nnegcliques);
11370
11371 weight = consdata->weights[i];
11372 assert(weight > 0);
11373
11374 if( cliquenum == nnegcliques )
11375 nnegcliques++;
11376 else
11377 {
11378 minactduetonegcliques += weight;
11379 if( secondmaxweights[cliquenum] == 0 )
11380 secondmaxweights[cliquenum] = weight;
11381 }
11382 }
11383 }
11384
11385 /* add cliques, using negated cliques information */
11386 if( minactduetonegcliques > 0 )
11387 {
11388 /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11389 freecapacity = consdata->capacity - minactduetonegcliques;
11390
11392 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",
11393 SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11394
11395 /* create negated cliques out of negated cliques, if we do not take the smallest weight of a cliques ... */
11396 SCIP_CALL( addNegatedCliques(scip, cons, cutoff, nbdchgs ) );
11397
11398 if( *cutoff )
11399 goto TERMINATE;
11400
11401 nposcliquevars = 0;
11402
11403 for( i = nvars - 1; i >= 0; --i )
11404 {
11405 /* if we would take the biggest weight instead of the second biggest */
11406 cliquenum = consdata->negcliquepartition[i];
11407 if( consdata->weights[i] > secondmaxweights[cliquenum] )
11408 {
11409 poscliquevars[nposcliquevars] = consdata->vars[i];
11410 gainweights[nposcliquevars] = consdata->weights[i] - secondmaxweights[cliquenum];
11411 ++nposcliquevars;
11412 }
11413 }
11414
11415 /* use the gain weights and free capacity to derive greedily cliques */
11416 if( nposcliquevars > 1 )
11417 {
11418 SCIP_CALL( greedyCliqueAlgorithm(scip, poscliquevars, gainweights, nposcliquevars, freecapacity, FALSE, cliqueextractfactor, cutoff, nbdchgs) );
11419
11420 if( *cutoff )
11421 goto TERMINATE;
11422 }
11423 }
11424
11425 /* build cliques by using the items with the maximal weights */
11426 SCIP_CALL( greedyCliqueAlgorithm(scip, consdata->vars, consdata->weights, nvars, consdata->capacity, TRUE, cliqueextractfactor, cutoff, nbdchgs) );
11427
11428 TERMINATE:
11429 /* free temporary memory and mark the constraint */
11430 SCIPfreeBufferArray(scip, &secondmaxweights);
11431 SCIPfreeBufferArray(scip, &gainweights);
11432 SCIPfreeBufferArray(scip, &poscliquevars);
11433 consdata->cliquesadded = TRUE;
11434
11435 return SCIP_OKAY;
11436}
11437
11438
11439/** gets the key of the given element */
11440static
11441SCIP_DECL_HASHGETKEY(hashGetKeyKnapsackcons)
11442{ /*lint --e{715}*/
11443 /* the key is the element itself */
11444 return elem;
11445}
11446
11447/** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables and the
11448 * same coefficients
11449 */
11450static
11451SCIP_DECL_HASHKEYEQ(hashKeyEqKnapsackcons)
11452{
11453#ifndef NDEBUG
11454 SCIP* scip;
11455#endif
11456 SCIP_CONSDATA* consdata1;
11457 SCIP_CONSDATA* consdata2;
11458 int i;
11459
11460 consdata1 = SCIPconsGetData((SCIP_CONS*)key1);
11461 consdata2 = SCIPconsGetData((SCIP_CONS*)key2);
11462 assert(consdata1->sorted);
11463 assert(consdata2->sorted);
11464#ifndef NDEBUG
11465 scip = (SCIP*)userptr;
11466 assert(scip != NULL);
11467#endif
11468
11469 /* checks trivial case */
11470 if( consdata1->nvars != consdata2->nvars )
11471 return FALSE;
11472
11473 for( i = consdata1->nvars - 1; i >= 0; --i )
11474 {
11475 /* tests if variables are equal */
11476 if( consdata1->vars[i] != consdata2->vars[i] )
11477 {
11478 assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 ||
11479 SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1);
11480 return FALSE;
11481 }
11482 assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 0);
11483
11484 /* tests if weights are equal too */
11485 if( consdata1->weights[i] != consdata2->weights[i] )
11486 return FALSE;
11487 }
11488
11489 return TRUE;
11490}
11491
11492/** returns the hash value of the key */
11493static
11494SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)
11495{
11496#ifndef NDEBUG
11497 SCIP* scip;
11498#endif
11499 SCIP_CONSDATA* consdata;
11500 uint64_t firstweight;
11501 int minidx;
11502 int mididx;
11503 int maxidx;
11504
11505 consdata = SCIPconsGetData((SCIP_CONS*)key);
11506 assert(consdata != NULL);
11507 assert(consdata->nvars > 0);
11508
11509#ifndef NDEBUG
11510 scip = (SCIP*)userptr;
11511 assert(scip != NULL);
11512#endif
11513
11514 /* sorts the constraints */
11515 sortItems(consdata);
11516
11517 minidx = SCIPvarGetIndex(consdata->vars[0]);
11518 mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]);
11519 maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]);
11520 assert(minidx >= 0 && mididx >= 0 && maxidx >= 0);
11521
11522 /* hash value depends on vectors of variable indices */
11523 firstweight = (uint64_t)consdata->weights[0];
11524 return SCIPhashSix(consdata->nvars, minidx, mididx, maxidx, firstweight>>32, firstweight);
11525}
11526
11527/** compares each constraint with all other constraints for possible redundancy and removes or changes constraint
11528 * accordingly; in contrast to preprocessConstraintPairs(), it uses a hash table
11529 */
11530static
11532 SCIP* scip, /**< SCIP data structure */
11533 BMS_BLKMEM* blkmem, /**< block memory */
11534 SCIP_CONS** conss, /**< constraint set */
11535 int nconss, /**< number of constraints in constraint set */
11536 SCIP_Bool* cutoff, /**< pointer to store whether the problem is infeasible */
11537 int* ndelconss /**< pointer to count number of deleted constraints */
11538 )
11539{
11540 SCIP_HASHTABLE* hashtable;
11541 int hashtablesize;
11542 int c;
11543
11544 assert(scip != NULL);
11545 assert(blkmem != NULL);
11546 assert(conss != NULL);
11547 assert(ndelconss != NULL);
11548
11549 /* create a hash table for the constraint set */
11550 hashtablesize = nconss;
11551 hashtablesize = MAX(hashtablesize, HASHSIZE_KNAPSACKCONS);
11552 SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize,
11553 hashGetKeyKnapsackcons, hashKeyEqKnapsackcons, hashKeyValKnapsackcons, (void*) scip) );
11554
11555 /* check all constraints in the given set for redundancy */
11556 for( c = nconss - 1; c >= 0; --c )
11557 {
11558 SCIP_CONS* cons0;
11559 SCIP_CONS* cons1;
11560 SCIP_CONSDATA* consdata0;
11561
11562 cons0 = conss[c];
11563
11564 if( !SCIPconsIsActive(cons0) || SCIPconsIsModifiable(cons0) )
11565 continue;
11566
11567 consdata0 = SCIPconsGetData(cons0);
11568 assert(consdata0 != NULL);
11569 if( consdata0->nvars == 0 )
11570 {
11571 if( consdata0->capacity < 0 )
11572 {
11573 *cutoff = TRUE;
11574 goto TERMINATE;
11575 }
11576 else
11577 {
11578 SCIP_CALL( SCIPdelCons(scip, cons0) );
11579 ++(*ndelconss);
11580 continue;
11581 }
11582 }
11583
11584 /* get constraint from current hash table with same variables and same weights as cons0 */
11585 cons1 = (SCIP_CONS*)(SCIPhashtableRetrieve(hashtable, (void*)cons0));
11586
11587 if( cons1 != NULL )
11588 {
11589 SCIP_CONS* consstay;
11590 SCIP_CONS* consdel;
11591 SCIP_CONSDATA* consdata1;
11592
11593 assert(SCIPconsIsActive(cons1));
11595
11596 /* constraint found: create a new constraint with same coefficients and best left and right hand side;
11597 * delete old constraints afterwards
11598 */
11599 consdata1 = SCIPconsGetData(cons1);
11600
11601 assert(consdata1 != NULL);
11602 assert(consdata0->nvars > 0 && consdata0->nvars == consdata1->nvars);
11603
11604 assert(consdata0->sorted && consdata1->sorted);
11605 assert(consdata0->vars[0] == consdata1->vars[0]);
11606 assert(consdata0->weights[0] == consdata1->weights[0]);
11607
11608 SCIPdebugMsg(scip, "knapsack constraints <%s> and <%s> with equal coefficients\n",
11609 SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11610
11611 /* check which constraint has to stay; */
11612 if( consdata0->capacity < consdata1->capacity )
11613 {
11614 consstay = cons0;
11615 consdel = cons1;
11616
11617 /* exchange consdel with consstay in hashtable */
11618 SCIP_CALL( SCIPhashtableRemove(hashtable, (void*) consdel) );
11619 SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) consstay) );
11620 }
11621 else
11622 {
11623 consstay = cons1;
11624 consdel = cons0;
11625 }
11626
11627 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11628 SCIP_CALL( SCIPupdateConsFlags(scip, consstay, consdel) );
11629
11630 /* delete consdel */
11631 SCIP_CALL( SCIPdelCons(scip, consdel) );
11632 ++(*ndelconss);
11633
11634 assert(SCIPconsIsActive(consstay));
11635 }
11636 else
11637 {
11638 /* no such constraint in current hash table: insert cons0 into hash table */
11639 SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) cons0) );
11640 }
11641 }
11642
11643 TERMINATE:
11644 /* free hash table */
11645 SCIPhashtableFree(&hashtable);
11646
11647 return SCIP_OKAY;
11648}
11649
11650
11651/** compares constraint with all prior constraints for possible redundancy or aggregation,
11652 * and removes or changes constraint accordingly
11653 */
11654static
11656 SCIP* scip, /**< SCIP data structure */
11657 SCIP_CONS** conss, /**< constraint set */
11658 int firstchange, /**< first constraint that changed since last pair preprocessing round */
11659 int chkind, /**< index of constraint to check against all prior indices upto startind */
11660 int* ndelconss /**< pointer to count number of deleted constraints */
11661 )
11662{
11663 SCIP_CONS* cons0;
11664 SCIP_CONSDATA* consdata0;
11665 int c;
11666
11667 assert(scip != NULL);
11668 assert(conss != NULL);
11669 assert(firstchange <= chkind);
11670 assert(ndelconss != NULL);
11671
11672 /* get the constraint to be checked against all prior constraints */
11673 cons0 = conss[chkind];
11674 assert(cons0 != NULL);
11675 assert(SCIPconsIsActive(cons0));
11677
11678 consdata0 = SCIPconsGetData(cons0);
11679 assert(consdata0 != NULL);
11680 assert(consdata0->nvars >= 1);
11681 assert(consdata0->merged);
11682
11683 /* sort the constraint */
11684 sortItems(consdata0);
11685
11686 /* see #2970 */
11687 if( consdata0->capacity == 0 )
11688 return SCIP_OKAY;
11689
11690 /* check constraint against all prior constraints */
11691 for( c = (consdata0->presolvedtiming == SCIP_PRESOLTIMING_EXHAUSTIVE ? firstchange : 0); c < chkind; ++c )
11692 {
11693 SCIP_CONS* cons1;
11694 SCIP_CONSDATA* consdata1;
11695 SCIP_Bool iscons0incons1contained;
11696 SCIP_Bool iscons1incons0contained;
11697 SCIP_Real quotient;
11698 int v;
11699 int v0;
11700 int v1;
11701
11702 cons1 = conss[c];
11703 assert(cons1 != NULL);
11704 if( !SCIPconsIsActive(cons1) || SCIPconsIsModifiable(cons1) )
11705 continue;
11706
11707 consdata1 = SCIPconsGetData(cons1);
11708 assert(consdata1 != NULL);
11709
11710 /* if both constraints didn't change since last pair processing, we can ignore the pair */
11711 if( consdata0->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE && consdata1->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE ) /*lint !e574*/
11712 continue;
11713
11714 assert(consdata1->nvars >= 1);
11715 assert(consdata1->merged);
11716
11717 /* sort the constraint */
11718 sortItems(consdata1);
11719
11720 /* see #2970 */
11721 if( consdata1->capacity == 0 )
11722 continue;
11723
11724 quotient = ((SCIP_Real) consdata0->capacity) / ((SCIP_Real) consdata1->capacity);
11725
11726 if( consdata0->nvars > consdata1->nvars )
11727 {
11728 iscons0incons1contained = FALSE;
11729 iscons1incons0contained = TRUE;
11730 v = consdata1->nvars - 1;
11731 }
11732 else if( consdata0->nvars < consdata1->nvars )
11733 {
11734 iscons0incons1contained = TRUE;
11735 iscons1incons0contained = FALSE;
11736 v = consdata0->nvars - 1;
11737 }
11738 else
11739 {
11740 iscons0incons1contained = TRUE;
11741 iscons1incons0contained = TRUE;
11742 v = consdata0->nvars - 1;
11743 }
11744
11745 SCIPdebugMsg(scip, "preprocess knapsack constraint pair <%s> and <%s>\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11746
11747 /* check consdata0 against consdata1:
11748 * 1. if all variables var_i of cons1 are in cons0 and for each of these variables
11749 * (consdata0->weights[i] / quotient) >= consdata1->weights[i] cons1 is redundant
11750 * 2. if all variables var_i of cons0 are in cons1 and for each of these variables
11751 * (consdata0->weights[i] / quotient) <= consdata1->weights[i] cons0 is redundant
11752 */
11753 v0 = consdata0->nvars - 1;
11754 v1 = consdata1->nvars - 1;
11755
11756 while( v >= 0 )
11757 {
11758 assert(iscons0incons1contained || iscons1incons0contained);
11759
11760 /* now there are more variables in cons1 left */
11761 if( v1 > v0 )
11762 {
11763 iscons1incons0contained = FALSE;
11764 if( !iscons0incons1contained )
11765 break;
11766 }
11767 /* now there are more variables in cons0 left */
11768 else if( v1 < v0 )
11769 {
11770 iscons0incons1contained = FALSE;
11771 if( !iscons1incons0contained )
11772 break;
11773 }
11774
11775 assert(v == v0 || v == v1);
11776 assert(v0 >= 0);
11777 assert(v1 >= 0);
11778
11779 /* both variables are the same */
11780 if( consdata0->vars[v0] == consdata1->vars[v1] )
11781 {
11782 /* if cons1 is possible contained in cons0 (consdata0->weights[v0] / quotient) must be greater equals consdata1->weights[v1] */
11783 if( iscons1incons0contained && SCIPisLT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11784 {
11785 iscons1incons0contained = FALSE;
11786 if( !iscons0incons1contained )
11787 break;
11788 }
11789 /* if cons0 is possible contained in cons1 (consdata0->weight[v0] / quotient) must be less equals consdata1->weight[v1] */
11790 else if( iscons0incons1contained && SCIPisGT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11791 {
11792 iscons0incons1contained = FALSE;
11793 if( !iscons1incons0contained )
11794 break;
11795 }
11796 --v0;
11797 --v1;
11798 --v;
11799 }
11800 else
11801 {
11802 /* both constraints have a variables which is not part of the other constraint, so stop */
11803 if( iscons0incons1contained && iscons1incons0contained )
11804 {
11805 iscons0incons1contained = FALSE;
11806 iscons1incons0contained = FALSE;
11807 break;
11808 }
11809 assert(iscons0incons1contained ? (v1 >= v0) : iscons1incons0contained);
11810 assert(iscons1incons0contained ? (v1 <= v0) : iscons0incons1contained);
11811 /* continue to the next variable */
11812 if( iscons0incons1contained )
11813 --v1;
11814 else
11815 --v0;
11816 }
11817 }
11818 /* neither one constraint was contained in another or we checked all variables of one constraint against the
11819 * other
11820 */
11821 assert(!iscons1incons0contained || !iscons0incons1contained || v0 == -1 || v1 == -1);
11822
11823 if( iscons1incons0contained )
11824 {
11825 SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons1));
11826 SCIPdebugPrintCons(scip, cons1, NULL);
11827
11828 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11829 SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
11830
11831 SCIP_CALL( SCIPdelCons(scip, cons1) );
11832 ++(*ndelconss);
11833 }
11834 else if( iscons0incons1contained )
11835 {
11836 SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons0));
11837 SCIPdebugPrintCons(scip, cons0, NULL);
11838
11839 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11840 SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
11841
11842 SCIP_CALL( SCIPdelCons(scip, cons0) );
11843 ++(*ndelconss);
11844 break;
11845 }
11846 }
11847
11848 return SCIP_OKAY;
11849}
11850
11851/** helper function to enforce constraints */
11852static
11854 SCIP* scip, /**< SCIP data structure */
11855 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11856 SCIP_CONS** conss, /**< constraints to process */
11857 int nconss, /**< number of constraints */
11858 int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
11859 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
11860 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
11861 )
11862{
11863 SCIP_CONSHDLRDATA* conshdlrdata;
11864 SCIP_Bool violated;
11866 int maxncuts;
11867 int ncuts = 0;
11868 int i;
11869
11871
11872 SCIPdebugMsg(scip, "knapsack enforcement of %d/%d constraints for %s solution\n", nusefulconss, nconss,
11873 sol == NULL ? "LP" : "relaxation");
11874
11875 /* get maximal number of cuts per round */
11876 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11877 assert(conshdlrdata != NULL);
11878 maxncuts = (SCIPgetDepth(scip) == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
11879
11880 /* search for violated useful knapsack constraints */
11881 for( i = 0; i < nusefulconss && ncuts < maxncuts && ! cutoff; i++ )
11882 {
11883 SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11884 if( violated )
11885 {
11886 /* add knapsack constraint as LP row to the relaxation */
11887 SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11888 ncuts++;
11889 }
11890 }
11891
11892 /* as long as no violations were found, search for violated obsolete knapsack constraints */
11893 for( i = nusefulconss; i < nconss && ncuts == 0 && ! cutoff; i++ )
11894 {
11895 SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11896 if( violated )
11897 {
11898 /* add knapsack constraint as LP row to the relaxation */
11899 SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11900 ncuts++;
11901 }
11902 }
11903
11904 /* adjust the result code */
11905 if ( cutoff )
11907 else if ( ncuts > 0 )
11909
11910 return SCIP_OKAY;
11911}
11912
11913/*
11914 * Linear constraint upgrading
11915 */
11916
11917/** creates and captures a knapsack constraint out of a linear inequality */
11918static
11920 SCIP* scip, /**< SCIP data structure */
11921 SCIP_CONS** cons, /**< pointer to hold the created constraint */
11922 const char* name, /**< name of constraint */
11923 int nvars, /**< number of variables in the constraint */
11924 SCIP_VAR** vars, /**< array with variables of constraint entries */
11925 SCIP_Real* vals, /**< array with inequality coefficients */
11926 SCIP_Real lhs, /**< left hand side of inequality */
11927 SCIP_Real rhs, /**< right hand side of inequality */
11928 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11929 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11930 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11931 * Usually set to TRUE. */
11932 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11933 * TRUE for model constraints, FALSE for additional, redundant constraints. */
11934 SCIP_Bool check, /**< should the constraint be checked for feasibility?
11935 * TRUE for model constraints, FALSE for additional, redundant constraints. */
11936 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11937 * Usually set to TRUE. */
11938 SCIP_Bool local, /**< is constraint only valid locally?
11939 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11940 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11941 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11942 * adds coefficients to this constraint. */
11943 SCIP_Bool dynamic, /**< is constraint subject to aging?
11944 * Usually set to FALSE. Set to TRUE for own cuts which
11945 * are separated as constraints. */
11946 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
11947 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11948 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
11949 * if it may be moved to a more global node?
11950 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
11951 )
11952{
11953 SCIP_VAR** transvars;
11954 SCIP_Longint* weights;
11955 SCIP_Longint capacity;
11956 SCIP_Longint weight;
11957 int mult;
11958 int v;
11959
11960 assert(nvars == 0 || vars != NULL);
11961 assert(nvars == 0 || vals != NULL);
11962 assert(SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11963
11964 /* get temporary memory */
11965 SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );
11967
11968 /* if the right hand side is non-infinite, we have to negate all variables with negative coefficient;
11969 * otherwise, we have to negate all variables with positive coefficient and multiply the row with -1
11970 */
11971 if( SCIPisInfinity(scip, rhs) )
11972 {
11973 mult = -1;
11974 capacity = (SCIP_Longint)SCIPfeasFloor(scip, -lhs);
11975 }
11976 else
11977 {
11978 mult = +1;
11979 capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
11980 }
11981
11982 /* negate positive or negative variables */
11983 for( v = 0; v < nvars; ++v )
11984 {
11985 assert(SCIPisFeasIntegral(scip, vals[v]));
11986 weight = mult * (SCIP_Longint)SCIPfeasFloor(scip, vals[v]);
11987 if( weight > 0 )
11988 {
11989 transvars[v] = vars[v];
11990 weights[v] = weight;
11991 }
11992 else
11993 {
11994 SCIP_CALL( SCIPgetNegatedVar(scip, vars[v], &transvars[v]) );
11995 weights[v] = -weight; /*lint !e2704*/
11996 capacity -= weight;
11997 }
11998 assert(transvars[v] != NULL);
11999 }
12000
12001 /* create the constraint */
12002 SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, transvars, weights, capacity,
12003 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
12004
12005 /* free temporary memory */
12006 SCIPfreeBufferArray(scip, &weights);
12007 SCIPfreeBufferArray(scip, &transvars);
12008
12009 return SCIP_OKAY;
12010}
12011
12012/** tries to upgrade a linear constraint into a knapsack constraint */
12013static
12014SCIP_DECL_LINCONSUPGD(linconsUpgdKnapsack)
12015{ /*lint --e{715}*/
12016 SCIP_Bool upgrade;
12017
12018 assert(upgdcons != NULL);
12019
12020 /* check, if linear constraint can be upgraded to a knapsack constraint
12021 * - all variables must be binary
12022 * - all coefficients must be integral
12023 * - exactly one of the sides must be infinite
12024 * note that this includes the case of negative capacity, which has been
12025 * observed to occur, e.g., when upgrading a conflict constraint
12026 */
12027 upgrade = (nposbin + nnegbin + nposimplbin + nnegimplbin == nvars)
12028 && (ncoeffspone + ncoeffsnone + ncoeffspint + ncoeffsnint == nvars)
12029 && (SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
12030
12031 if( upgrade )
12032 {
12033 SCIPdebugMsg(scip, "upgrading constraint <%s> to knapsack constraint\n", SCIPconsGetName(cons));
12034
12035 /* create the knapsack constraint (an automatically upgraded constraint is always unmodifiable) */
12037 SCIP_CALL( createNormalizedKnapsack(scip, upgdcons, SCIPconsGetName(cons), nvars, vars, vals, lhs, rhs,
12042 }
12043
12044 return SCIP_OKAY;
12045}
12046
12047/** adds symmetry information of constraint to a symmetry detection graph */
12048static
12050 SCIP* scip, /**< SCIP pointer */
12051 SYM_SYMTYPE symtype, /**< type of symmetries that need to be added */
12052 SCIP_CONS* cons, /**< constraint */
12053 SYM_GRAPH* graph, /**< symmetry detection graph */
12054 SCIP_Bool* success /**< pointer to store whether symmetry information could be added */
12055 )
12056{
12057 SCIP_CONSDATA* consdata;
12058 SCIP_VAR** vars;
12059 SCIP_Real* vals;
12060 SCIP_Real constant = 0.0;
12061 SCIP_Real rhs;
12062 int nlocvars;
12063 int nvars;
12064 int i;
12065
12066 assert(scip != NULL);
12067 assert(cons != NULL);
12068 assert(graph != NULL);
12069 assert(success != NULL);
12070
12071 consdata = SCIPconsGetData(cons);
12072 assert(consdata != NULL);
12073 assert(graph != NULL);
12074
12075 /* get active variables of the constraint */
12077 nlocvars = consdata->nvars;
12078
12081
12082 for( i = 0; i < consdata->nvars; ++i )
12083 {
12084 vars[i] = consdata->vars[i];
12085 vals[i] = (SCIP_Real) consdata->weights[i];
12086 }
12087
12088 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &vars, &vals, &nlocvars, &constant, SCIPisTransformed(scip)) );
12089 rhs = (SCIP_Real) SCIPgetCapacityKnapsack(scip, cons) - constant;
12090
12092 cons, -SCIPinfinity(scip), rhs, success) );
12093
12094 SCIPfreeBufferArray(scip, &vals);
12096
12097 return SCIP_OKAY;
12098}
12099
12100/*
12101 * Callback methods of constraint handler
12102 */
12103
12104/** copy method for constraint handler plugins (called when SCIP copies plugins) */
12105/**! [SnippetConsCopyKnapsack] */
12106static
12107SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack)
12108{ /*lint --e{715}*/
12109 assert(scip != NULL);
12110 assert(conshdlr != NULL);
12111
12113
12114 /* call inclusion method of constraint handler */
12116
12117 *valid = TRUE;
12118
12119 return SCIP_OKAY;
12120}
12121/**! [SnippetConsCopyKnapsack] */
12122
12123/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12124/**! [SnippetConsFreeKnapsack] */
12125static
12126SCIP_DECL_CONSFREE(consFreeKnapsack)
12127{ /*lint --e{715}*/
12128 SCIP_CONSHDLRDATA* conshdlrdata;
12129
12130 /* free constraint handler data */
12131 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12132 assert(conshdlrdata != NULL);
12133
12134 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->probtoidxmap, conshdlrdata->probtoidxmapsize);
12135 SCIPfreeBlockMemory(scip, &conshdlrdata);
12136
12137 SCIPconshdlrSetData(conshdlr, NULL);
12138
12139 return SCIP_OKAY;
12140}
12141/**! [SnippetConsFreeKnapsack] */
12142
12143
12144/** initialization method of constraint handler (called after problem was transformed) */
12145static
12146SCIP_DECL_CONSINIT(consInitKnapsack)
12147{ /*lint --e{715}*/
12148 SCIP_CONSHDLRDATA* conshdlrdata;
12149 int nvars;
12150
12151 assert( scip != NULL );
12152 assert( conshdlr != NULL );
12153
12154 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12155 assert(conshdlrdata != NULL);
12156
12157 /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12159
12160 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->reals1, nvars) );
12161 conshdlrdata->reals1size = nvars;
12162
12163 return SCIP_OKAY;
12164}
12165
12166/** deinitialization method of constraint handler (called before transformed problem is freed) */
12167static
12168SCIP_DECL_CONSEXIT(consExitKnapsack)
12169{ /*lint --e{715}*/
12170 SCIP_CONSHDLRDATA* conshdlrdata;
12171
12172 assert( scip != NULL );
12173 assert( conshdlr != NULL );
12174
12175 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12176 assert(conshdlrdata != NULL);
12177
12178 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->reals1, conshdlrdata->reals1size);
12179 conshdlrdata->reals1size = 0;
12180
12181 return SCIP_OKAY;
12182}
12183
12184
12185/** presolving initialization method of constraint handler (called when presolving is about to begin) */
12186static
12187SCIP_DECL_CONSINITPRE(consInitpreKnapsack)
12188{ /*lint --e{715}*/
12189 SCIP_CONSHDLRDATA* conshdlrdata;
12190 int nvars;
12191
12192 assert(scip != NULL);
12193 assert(conshdlr != NULL);
12194 assert(nconss == 0 || conss != NULL);
12195
12196 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12197 assert(conshdlrdata != NULL);
12198
12199 /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12201
12202 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints1, nvars) );
12203 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints2, nvars) );
12204 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints1, nvars) );
12205 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints2, nvars) );
12206 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools1, nvars) );
12207 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools2, nvars) );
12208 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools3, nvars) );
12209 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools4, nvars) );
12210
12211 conshdlrdata->ints1size = nvars;
12212 conshdlrdata->ints2size = nvars;
12213 conshdlrdata->longints1size = nvars;
12214 conshdlrdata->longints2size = nvars;
12215 conshdlrdata->bools1size = nvars;
12216 conshdlrdata->bools2size = nvars;
12217 conshdlrdata->bools3size = nvars;
12218 conshdlrdata->bools4size = nvars;
12219
12220#ifdef WITH_CARDINALITY_UPGRADE
12221 conshdlrdata->upgradedcard = FALSE;
12222#endif
12223
12224 return SCIP_OKAY;
12225}
12226
12227
12228/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12229static
12230SCIP_DECL_CONSEXITPRE(consExitpreKnapsack)
12231{ /*lint --e{715}*/
12232 SCIP_CONSHDLRDATA* conshdlrdata;
12233 int c;
12234
12235 assert(scip != NULL);
12236 assert(conshdlr != NULL);
12237
12238 for( c = 0; c < nconss; ++c )
12239 {
12240 if( !SCIPconsIsDeleted(conss[c]) )
12241 {
12242 /* since we are not allowed to detect infeasibility in the exitpre stage, we dont give an infeasible pointer */
12243 SCIP_CALL( applyFixings(scip, conss[c], NULL) );
12244 }
12245 }
12246
12247 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12248 assert(conshdlrdata != NULL);
12249
12250 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints1, conshdlrdata->ints1size);
12251 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints2, conshdlrdata->ints2size);
12252 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints1, conshdlrdata->longints1size);
12253 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints2, conshdlrdata->longints2size);
12254 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools1, conshdlrdata->bools1size);
12255 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools2, conshdlrdata->bools2size);
12256 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools3, conshdlrdata->bools3size);
12257 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools4, conshdlrdata->bools4size);
12258
12259 conshdlrdata->ints1size = 0;
12260 conshdlrdata->ints2size = 0;
12261 conshdlrdata->longints1size = 0;
12262 conshdlrdata->longints2size = 0;
12263 conshdlrdata->bools1size = 0;
12264 conshdlrdata->bools2size = 0;
12265 conshdlrdata->bools3size = 0;
12266 conshdlrdata->bools4size = 0;
12267
12268 return SCIP_OKAY;
12269}
12270
12271/** solving process initialization method of constraint handler */
12272static
12273SCIP_DECL_CONSINITSOL(consInitsolKnapsack)
12274{ /*lint --e{715}*/
12275 /* add nlrow representation to NLP, if NLP had been constructed */
12277 {
12278 int c;
12279 for( c = 0; c < nconss; ++c )
12280 {
12281 SCIP_CALL( addNlrow(scip, conss[c]) );
12282 }
12283 }
12284
12285 return SCIP_OKAY;
12286}
12287
12288/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12289static
12290SCIP_DECL_CONSEXITSOL(consExitsolKnapsack)
12291{ /*lint --e{715}*/
12292 SCIP_CONSDATA* consdata;
12293 int c;
12294
12295 assert( scip != NULL );
12296
12297 /* release the rows and nlrows of all constraints */
12298 for( c = 0; c < nconss; ++c )
12299 {
12300 consdata = SCIPconsGetData(conss[c]);
12301 assert(consdata != NULL);
12302
12303 if( consdata->row != NULL )
12304 {
12305 SCIP_CALL( SCIPreleaseRow(scip, &consdata->row) );
12306 }
12307
12308 if( consdata->nlrow != NULL )
12309 {
12310 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
12311 }
12312 }
12313
12314 return SCIP_OKAY;
12315}
12316
12317/** frees specific constraint data */
12318static
12319SCIP_DECL_CONSDELETE(consDeleteKnapsack)
12320{ /*lint --e{715}*/
12321 SCIP_CONSHDLRDATA* conshdlrdata;
12322
12323 assert(conshdlr != NULL);
12324
12326
12327 /* get event handler */
12328 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12329 assert(conshdlrdata != NULL);
12330 assert(conshdlrdata->eventhdlr != NULL);
12331
12332 /* free knapsack constraint */
12333 SCIP_CALL( consdataFree(scip, consdata, conshdlrdata->eventhdlr) );
12334
12335 return SCIP_OKAY;
12336}
12337
12338/** transforms constraint data into data belonging to the transformed problem */
12339/**! [SnippetConsTransKnapsack]*/
12340static
12341SCIP_DECL_CONSTRANS(consTransKnapsack)
12342{ /*lint --e{715}*/
12343 SCIP_CONSHDLRDATA* conshdlrdata;
12344 SCIP_CONSDATA* sourcedata;
12345 SCIP_CONSDATA* targetdata;
12346
12347 assert(conshdlr != NULL);
12349 assert(sourcecons != NULL);
12350 assert(targetcons != NULL);
12351
12353
12354 sourcedata = SCIPconsGetData(sourcecons);
12355 assert(sourcedata != NULL);
12356 assert(sourcedata->row == NULL); /* in original problem, there cannot be LP rows */
12357
12358 /* get event handler */
12359 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12360 assert(conshdlrdata != NULL);
12361 assert(conshdlrdata->eventhdlr != NULL);
12362
12363 /* create target constraint data */
12364 SCIP_CALL( consdataCreate(scip, &targetdata,
12365 sourcedata->nvars, sourcedata->vars, sourcedata->weights, sourcedata->capacity) );
12366
12367 /* create target constraint */
12368 SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12369 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12370 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12371 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12372 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12373
12374 /* catch events for variables */
12375 SCIP_CALL( catchEvents(scip, *targetcons, targetdata, conshdlrdata->eventhdlr) );
12376
12377 return SCIP_OKAY;
12378}
12379/**! [SnippetConsTransKnapsack]*/
12380
12381/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
12382static
12383SCIP_DECL_CONSINITLP(consInitlpKnapsack)
12384{ /*lint --e{715}*/
12385 int i;
12386
12387 *infeasible = FALSE;
12388
12389 for( i = 0; i < nconss && !(*infeasible); i++ )
12390 {
12391 assert(SCIPconsIsInitial(conss[i]));
12392 SCIP_CALL( addRelaxation(scip, conss[i], infeasible) );
12393 }
12394
12395 return SCIP_OKAY;
12396}
12397
12398/** separation method of constraint handler for LP solutions */
12399static
12400SCIP_DECL_CONSSEPALP(consSepalpKnapsack)
12401{ /*lint --e{715}*/
12402 SCIP_CONSHDLRDATA* conshdlrdata;
12403 SCIP_Bool sepacardinality;
12405
12406 SCIP_Real loclowerbound;
12407 SCIP_Real glblowerbound;
12408 SCIP_Real cutoffbound;
12409 SCIP_Real maxbound;
12410
12411 int depth;
12412 int nrounds;
12413 int sepafreq;
12414 int sepacardfreq;
12415 int ncuts;
12416 int maxsepacuts;
12417 int i;
12418
12420
12421 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12422 assert(conshdlrdata != NULL);
12423
12425 nrounds = SCIPgetNSepaRounds(scip);
12426
12427 SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12428 nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12429
12430 /* only call the separator a given number of times at each node */
12431 if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12432 || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12433 return SCIP_OKAY;
12434
12435 /* check, if we should additionally separate knapsack cuts */
12436 sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12437 sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12438 sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12439 && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12440
12441 /* check dual bound to see if we want to produce knapsack cuts at this node */
12442 loclowerbound = SCIPgetLocalLowerbound(scip);
12443 glblowerbound = SCIPgetLowerbound(scip);
12444 cutoffbound = SCIPgetCutoffbound(scip);
12445 maxbound = glblowerbound + conshdlrdata->maxcardbounddist * (cutoffbound - glblowerbound);
12446 sepacardinality = sepacardinality && SCIPisLE(scip, loclowerbound, maxbound);
12447 sepacardinality = sepacardinality && (SCIPgetNLPBranchCands(scip) > 0);
12448
12449 /* get the maximal number of cuts allowed in a separation round */
12450 maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12451
12453 ncuts = 0;
12454 cutoff = FALSE;
12455
12456 /* separate useful constraints */
12457 for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12458 {
12459 SCIP_CALL( separateCons(scip, conss[i], NULL, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12460 }
12461
12462 /* adjust return value */
12463 if ( cutoff )
12465 else if ( ncuts > 0 )
12467
12468 return SCIP_OKAY;
12469}
12470
12471
12472/** separation method of constraint handler for arbitrary primal solutions */
12473static
12474SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
12475{ /*lint --e{715}*/
12476 SCIP_CONSHDLRDATA* conshdlrdata;
12477 SCIP_Bool sepacardinality;
12479
12480 int depth;
12481 int nrounds;
12482 int sepafreq;
12483 int sepacardfreq;
12484 int ncuts;
12485 int maxsepacuts;
12486 int i;
12487
12489
12490 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12491 assert(conshdlrdata != NULL);
12492
12494 nrounds = SCIPgetNSepaRounds(scip);
12495
12496 SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12497 nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12498
12499 /* only call the separator a given number of times at each node */
12500 if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12501 || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12502 return SCIP_OKAY;
12503
12504 /* check, if we should additionally separate knapsack cuts */
12505 sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12506 sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12507 sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12508 && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12509
12510 /* get the maximal number of cuts allowed in a separation round */
12511 maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12512
12514 ncuts = 0;
12515 cutoff = FALSE;
12516
12517 /* separate useful constraints */
12518 for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12519 {
12520 SCIP_CALL( separateCons(scip, conss[i], sol, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12521 }
12522
12523 /* adjust return value */
12524 if ( cutoff )
12526 else if( ncuts > 0 )
12528
12529 return SCIP_OKAY;
12530}
12531
12532/** constraint enforcing method of constraint handler for LP solutions */
12533static
12534SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
12535{ /*lint --e{715}*/
12536 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, result) );
12537
12538 return SCIP_OKAY;
12539}
12540
12541/** constraint enforcing method of constraint handler for relaxation solutions */
12542static
12543SCIP_DECL_CONSENFORELAX(consEnforelaxKnapsack)
12544{ /*lint --e{715}*/
12545 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, result) );
12546
12547 return SCIP_OKAY;
12548}
12549
12550/** constraint enforcing method of constraint handler for pseudo solutions */
12551static
12552SCIP_DECL_CONSENFOPS(consEnfopsKnapsack)
12553{ /*lint --e{715}*/
12554 SCIP_Bool violated;
12555 int i;
12556
12557 for( i = 0; i < nconss; i++ )
12558 {
12559 SCIP_CALL( checkCons(scip, conss[i], NULL, TRUE, FALSE, &violated) );
12560 if( violated )
12561 {
12563 return SCIP_OKAY;
12564 }
12565 }
12567
12568 return SCIP_OKAY;
12569}
12570
12571/** feasibility check method of constraint handler for integral solutions */
12572static
12573SCIP_DECL_CONSCHECK(consCheckKnapsack)
12574{ /*lint --e{715}*/
12575 SCIP_Bool violated;
12576 int i;
12577
12579
12580 for( i = 0; i < nconss && (*result == SCIP_FEASIBLE || completely); i++ )
12581 {
12582 SCIP_CALL( checkCons(scip, conss[i], sol, checklprows, printreason, &violated) );
12583 if( violated )
12585 }
12586
12587 return SCIP_OKAY;
12588}
12589
12590/** domain propagation method of constraint handler */
12591static
12592SCIP_DECL_CONSPROP(consPropKnapsack)
12593{ /*lint --e{715}*/
12594 SCIP_CONSHDLRDATA* conshdlrdata;
12596 SCIP_Bool redundant;
12597 SCIP_Bool inpresolve;
12598 int nfixedvars;
12599 int i;
12600
12601 cutoff = FALSE;
12602 nfixedvars = 0;
12603
12604 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12605 assert(conshdlrdata != NULL);
12606
12607 inpresolve = (SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE);
12608 assert(!inpresolve || SCIPinProbing(scip));
12609
12610 /* process useful constraints */
12611 for( i = 0; i < nmarkedconss && !cutoff; i++ )
12612 {
12613 /* do not propagate constraints with multi-aggregated variables, which should only happen in probing mode,
12614 * otherwise the multi-aggregation should be resolved
12615 */
12616 if( inpresolve && SCIPconsGetData(conss[i])->existmultaggr )
12617 continue;
12618#ifndef NDEBUG
12619 else
12620 assert(!(SCIPconsGetData(conss[i])->existmultaggr));
12621#endif
12622
12623 SCIP_CALL( propagateCons(scip, conss[i], &cutoff, &redundant, &nfixedvars, conshdlrdata->negatedclique) );
12624
12625 /* unmark the constraint to be propagated */
12627 }
12628
12629 /* adjust result code */
12630 if( cutoff )
12632 else if( nfixedvars > 0 )
12634 else
12636
12637 return SCIP_OKAY; /*lint !e438*/
12638}
12639
12640/** presolving method of constraint handler */
12641static
12642SCIP_DECL_CONSPRESOL(consPresolKnapsack)
12643{ /*lint --e{574,715}*/
12644 SCIP_CONSHDLRDATA* conshdlrdata;
12645 SCIP_CONSDATA* consdata;
12646 SCIP_CONS* cons;
12648 SCIP_Bool redundant;
12649 SCIP_Bool success;
12650 int oldnfixedvars;
12651 int oldnchgbds;
12652 int oldndelconss;
12653 int oldnaddconss;
12654 int oldnchgcoefs;
12655 int oldnchgsides;
12656 int firstchange;
12657 int c;
12658 SCIP_Bool newchanges;
12659
12660 /* remember old preprocessing counters */
12661 cutoff = FALSE;
12662 oldnfixedvars = *nfixedvars;
12663 oldnchgbds = *nchgbds;
12664 oldndelconss = *ndelconss;
12665 oldnaddconss = *naddconss;
12666 oldnchgcoefs = *nchgcoefs;
12667 oldnchgsides = *nchgsides;
12668 firstchange = INT_MAX;
12669
12670 newchanges = (nrounds == 0 || nnewfixedvars > 0 || nnewaggrvars > 0 || nnewchgbds > 0 || nnewupgdconss > 0);
12671
12672 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12673 assert(conshdlrdata != NULL);
12674
12675 for( c = 0; c < nconss && !SCIPisStopped(scip); c++ )
12676 {
12677 int thisnfixedvars;
12678 int thisnchgbds;
12679
12680 cons = conss[c];
12681 consdata = SCIPconsGetData(cons);
12682 assert(consdata != NULL);
12683
12684 /* update data structures */
12685 /* todo if UBTIGHTENED events were caught, we could move this block after the continue */
12686 if( newchanges || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12687 {
12688 SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12689 if( cutoff )
12690 break;
12691 }
12692
12693 /* force presolving the constraint in the initial round */
12694 if( nrounds == 0 )
12695 consdata->presolvedtiming = 0;
12696 else if( consdata->presolvedtiming >= presoltiming )
12697 continue;
12698
12699 SCIPdebugMsg(scip, "presolving knapsack constraint <%s>\n", SCIPconsGetName(cons));
12701 consdata->presolvedtiming = presoltiming;
12702
12703 thisnfixedvars = *nfixedvars;
12704 thisnchgbds = *nchgbds;
12705
12706 /* merge constraint, so propagation works better */
12707 SCIP_CALL( mergeMultiples(scip, cons, &cutoff) );
12708 if( cutoff )
12709 break;
12710
12711 /* add cliques in the knapsack to the clique table */
12712 if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12713 {
12714 SCIP_CALL( addCliques(scip, cons, conshdlrdata->cliqueextractfactor, &cutoff, nchgbds) );
12715 if( cutoff )
12716 break;
12717 }
12718
12719 /* propagate constraint */
12720 if( presoltiming < SCIP_PRESOLTIMING_EXHAUSTIVE )
12721 {
12722 SCIP_CALL( propagateCons(scip, cons, &cutoff, &redundant, nfixedvars, (presoltiming & SCIP_PRESOLTIMING_MEDIUM)) );
12723
12724 if( cutoff )
12725 break;
12726 if( redundant )
12727 {
12728 (*ndelconss)++;
12729 continue;
12730 }
12731 }
12732
12733 /* remove again all fixed variables, if further fixings were found */
12734 if( *nfixedvars > thisnfixedvars || *nchgbds > thisnchgbds )
12735 {
12736 SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12737 if( cutoff )
12738 break;
12739
12740 thisnfixedvars = *nfixedvars;
12741 }
12742
12743 if( !SCIPconsIsModifiable(cons) )
12744 {
12745 /* check again for redundancy (applyFixings() might have decreased weightsum due to fixed-to-zero vars) */
12746 if( consdata->weightsum <= consdata->capacity )
12747 {
12748 SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
12749 SCIPconsGetName(cons), consdata->weightsum, consdata->capacity);
12751 continue;
12752 }
12753
12754 /* divide weights by their greatest common divisor */
12755 normalizeWeights(cons, nchgcoefs, nchgsides);
12756
12757 /* try to simplify inequalities */
12758 if( conshdlrdata->simplifyinequalities && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
12759 {
12760 SCIP_CALL( simplifyInequalities(scip, cons, nfixedvars, ndelconss, nchgcoefs, nchgsides, naddconss, &cutoff) );
12761 if( cutoff )
12762 break;
12763
12764 if( SCIPconsIsDeleted(cons) )
12765 continue;
12766
12767 /* remove again all fixed variables, if further fixings were found */
12768 if( *nfixedvars > thisnfixedvars )
12769 {
12770 SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12771 if( cutoff )
12772 break;
12773 }
12774 }
12775
12776 /* tighten capacity and weights */
12777 SCIP_CALL( tightenWeights(scip, cons, presoltiming, nchgcoefs, nchgsides, naddconss, ndelconss, &cutoff) );
12778 if( cutoff )
12779 break;
12780
12781 if( SCIPconsIsActive(cons) )
12782 {
12783 if( conshdlrdata->dualpresolving && SCIPallowStrongDualReds(scip) && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12784 {
12785 /* in case the knapsack constraints is independent of everything else, solve the knapsack and apply the
12786 * dual reduction
12787 */
12788 SCIP_CALL( dualPresolving(scip, cons, nchgbds, ndelconss, &redundant) );
12789 if( redundant )
12790 continue;
12791 }
12792
12793 /* check if knapsack constraint is parallel to objective function */
12794 SCIP_CALL( checkParallelObjective(scip, cons, conshdlrdata) );
12795 }
12796 }
12797 /* remember the first changed constraint to begin the next aggregation round with */
12798 if( firstchange == INT_MAX && consdata->presolvedtiming != SCIP_PRESOLTIMING_EXHAUSTIVE )
12799 firstchange = c;
12800 }
12801
12802 /* preprocess pairs of knapsack constraints */
12803 if( !cutoff && conshdlrdata->presolusehashing && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12804 {
12805 /* detect redundant constraints; fast version with hash table instead of pairwise comparison */
12806 SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &cutoff, ndelconss) );
12807 }
12808
12809 if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) || (*naddconss != oldnaddconss) )
12810 success = TRUE;
12811 else
12812 success = FALSE;
12813
12814 if( !cutoff && firstchange < nconss && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
12815 {
12816 SCIP_Longint npaircomparisons;
12817
12818 npaircomparisons = 0;
12819 oldndelconss = *ndelconss;
12820 oldnchgsides = *nchgsides;
12821 oldnchgcoefs = *nchgcoefs;
12822
12823 for( c = firstchange; c < nconss && !SCIPisStopped(scip); ++c )
12824 {
12825 cons = conss[c];
12826 if( !SCIPconsIsActive(cons) || SCIPconsIsModifiable(cons) )
12827 continue;
12828
12829 npaircomparisons += ((SCIPconsGetData(cons)->presolvedtiming < SCIP_PRESOLTIMING_EXHAUSTIVE) ? (SCIP_Longint) c : ((SCIP_Longint) c - (SCIP_Longint) firstchange));
12830
12831 SCIP_CALL( preprocessConstraintPairs(scip, conss, firstchange, c, ndelconss) );
12832
12833 if( npaircomparisons > NMINCOMPARISONS )
12834 {
12835 if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) )
12836 success = TRUE;
12837 if( ((SCIP_Real) (*ndelconss - oldndelconss) + ((SCIP_Real) (*nchgsides - oldnchgsides))/2.0 +
12838 ((SCIP_Real) (*nchgcoefs - oldnchgcoefs))/10.0) / ((SCIP_Real) npaircomparisons) < MINGAINPERNMINCOMPARISONS )
12839 break;
12840 oldndelconss = *ndelconss;
12841 oldnchgsides = *nchgsides;
12842 oldnchgcoefs = *nchgcoefs;
12843 npaircomparisons = 0;
12844 }
12845 }
12846 }
12847#ifdef WITH_CARDINALITY_UPGRADE
12848 /* @todo upgrade to cardinality constraints: the code below relies on disabling the checking of the knapsack
12849 * constraint in the original problem, because the upgrade ensures that at most the given number of continuous
12850 * variables has a nonzero value, but not that the binary variables corresponding to the continuous variables with
12851 * value zero are set to zero as well. This can cause problems if the user accesses the values of the binary
12852 * variables (as the MIPLIB solution checker does), or the transformed problem is freed and the original problem
12853 * (possibly with some user modifications) is re-optimized. Until there is a way to force the binary variables to 0
12854 * as well, we better keep this code disabled. */
12855 /* upgrade to cardinality constraints - only try to upgrade towards the end of presolving, since the process below is quite expensive */
12856 if ( ! cutoff && conshdlrdata->upgdcardinality && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 && SCIPisPresolveFinished(scip) && ! conshdlrdata->upgradedcard )
12857 {
12858 SCIP_HASHMAP* varhash;
12859 SCIP_VAR** cardvars;
12860 SCIP_Real* cardweights;
12861 int noldupgdconss;
12862 int nscipvars;
12863 int makeupgrade;
12864
12865 noldupgdconss = *nupgdconss;
12866 nscipvars = SCIPgetNVars(scip);
12867 SCIP_CALL( SCIPallocClearBufferArray(scip, &cardvars, nscipvars) );
12868 SCIP_CALL( SCIPallocClearBufferArray(scip, &cardweights, nscipvars) );
12869
12870 /* set up hash map */
12871 SCIP_CALL( SCIPhashmapCreate(&varhash, SCIPblkmem(scip), nscipvars) );
12872
12873 /* We loop through all cardinality constraints twice:
12874 * - First, determine for each binary variable the number of cardinality constraints that can be upgraded to a
12875 * knapsack constraint and contain this variable; this number has to coincide with the number of variable up
12876 * locks; otherwise it would be infeasible to delete the knapsack constraints after the constraint update.
12877 * - Second, upgrade knapsack constraints to cardinality constraints. */
12878 for (makeupgrade = 0; makeupgrade < 2; ++makeupgrade)
12879 {
12880 for (c = nconss-1; c >= 0 && ! SCIPisStopped(scip); --c)
12881 {
12882 SCIP_CONS* cardcons;
12883 SCIP_VAR** vars;
12884 SCIP_Longint* weights;
12885 int nvars;
12886 int v;
12887
12888 cons = conss[c];
12889 assert( cons != NULL );
12890
12891 if( SCIPconsGetNUpgradeLocks(cons) >= 1 )
12892 continue;
12893
12894 consdata = SCIPconsGetData(cons);
12895 assert( consdata != NULL );
12896
12897 nvars = consdata->nvars;
12898 vars = consdata->vars;
12899 weights = consdata->weights;
12900
12901 /* Check, whether linear knapsack can be upgraded to a cardinality constraint:
12902 * - all variables must be binary (always true)
12903 * - all coefficients must be 1.0
12904 * - the right hand side must be smaller than nvars
12905 */
12906 if ( consdata->capacity >= nvars )
12907 continue;
12908
12909 /* the weights are sorted: check first and last weight */
12910 assert( consdata->sorted );
12911 if ( weights[0] != 1 || weights[nvars-1] != 1 )
12912 continue;
12913
12914 /* check whether all variables are of the form 0 <= x_v <= u_v y_v for y_v \in \{0,1\} and zero objective */
12915 for (v = 0; v < nvars; ++v)
12916 {
12917 SCIP_BOUNDTYPE* impltypes;
12918 SCIP_Real* implbounds;
12919 SCIP_VAR** implvars;
12920 SCIP_VAR* var;
12921 int nimpls;
12922 int j;
12923
12924 var = consdata->vars[v];
12925 assert( var != NULL );
12927
12928 /* ignore non-active variables */
12929 if ( ! SCIPvarIsActive(var) )
12930 break;
12931
12932 /* be sure that implication variable has zero objective */
12933 if ( ! SCIPisZero(scip, SCIPvarGetObj(var)) )
12934 break;
12935
12936 nimpls = SCIPvarGetNImpls(var, FALSE);
12937 implvars = SCIPvarGetImplVars(var, FALSE);
12938 implbounds = SCIPvarGetImplBounds(var, FALSE);
12939 impltypes = SCIPvarGetImplTypes(var, FALSE);
12940
12941 for (j = 0; j < nimpls; ++j)
12942 {
12943 /* be sure that continuous variable is fixed to 0 */
12944 if ( impltypes[j] != SCIP_BOUNDTYPE_UPPER )
12945 continue;
12946
12947 /* cannot currently deal with nonzero fixings */
12948 if ( ! SCIPisZero(scip, implbounds[j]) )
12949 continue;
12950
12951 /* number of down locks should be one */
12953 continue;
12954
12955 cardvars[v] = implvars[j];
12956 cardweights[v] = (SCIP_Real) v;
12957
12958 break;
12959 }
12960
12961 /* found no variable upper bound candidate -> exit */
12962 if ( j >= nimpls )
12963 break;
12964 }
12965
12966 /* did not find fitting variable upper bound for some variable -> exit */
12967 if ( v < nvars )
12968 break;
12969
12970 /* save number of knapsack constraints that can be upgraded to a cardinality constraint,
12971 * in which the binary variable is involved in */
12972 if ( makeupgrade == 0 )
12973 {
12974 for (v = 0; v < nvars; ++v)
12975 {
12976 if ( SCIPhashmapExists(varhash, vars[v]) )
12977 {
12978 int image;
12979
12980 image = SCIPhashmapGetImageInt(varhash, vars[v]);
12981 SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image + 1) );
12982 assert( image + 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12983 }
12984 else
12985 {
12986 SCIP_CALL( SCIPhashmapInsertInt(varhash, vars[v], 1) );
12987 assert( 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12988 assert( SCIPhashmapExists(varhash, vars[v]) );
12989 }
12990 }
12991 }
12992 else
12993 {
12994 SCIP_CONS* origcons;
12995
12996 /* for each variable: check whether the number of cardinality constraints that can be upgraded to a
12997 * knapsack constraint coincides with the number of variable up locks */
12998 for (v = 0; v < nvars; ++v)
12999 {
13000 assert( SCIPhashmapExists(varhash, vars[v]) );
13002 break;
13003 }
13004 if ( v < nvars )
13005 break;
13006
13007 /* store that we have upgraded */
13008 conshdlrdata->upgradedcard = TRUE;
13009
13010 /* at this point we found suitable variable upper bounds */
13011 SCIPdebugMessage("Upgrading knapsack constraint <%s> to cardinality constraint ...\n", SCIPconsGetName(cons));
13012
13013 /* create cardinality constraint */
13014 assert( ! SCIPconsIsModifiable(cons) );
13015 SCIP_CALL( SCIPcreateConsCardinality(scip, &cardcons, SCIPconsGetName(cons), nvars, cardvars, (int) consdata->capacity, vars, cardweights,
13019#ifdef SCIP_DEBUG
13020 SCIPprintCons(scip, cons, NULL);
13021 SCIPinfoMessage(scip, NULL, "\n");
13022 SCIPprintCons(scip, cardcons, NULL);
13023 SCIPinfoMessage(scip, NULL, "\n");
13024#endif
13025 /* add the upgraded constraint to the problem */
13026 SCIP_CALL( SCIPaddConsUpgrade(scip, cons, &cardcons) );
13027 ++(*nupgdconss);
13028
13029 /* delete oknapsack constraint */
13030 SCIP_CALL( SCIPdelCons(scip, cons) );
13031 ++(*ndelconss);
13032
13033 /* We need to disable the original knapsack constraint, since it might happen that the binary variables
13034 * are 1 although the continuous variables are 0. Thus, the knapsack constraint might be violated,
13035 * although the cardinality constraint is satisfied. */
13036 origcons = SCIPfindOrigCons(scip, SCIPconsGetName(cons));
13037 assert( origcons != NULL );
13038 SCIP_CALL( SCIPsetConsChecked(scip, origcons, FALSE) );
13039
13040 for (v = 0; v < nvars; ++v)
13041 {
13042 int image;
13043
13044 assert ( SCIPhashmapExists(varhash, vars[v]) );
13045 image = SCIPhashmapGetImageInt(varhash, vars[v]);
13046 SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image - 1) );
13047 assert( image - 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
13048 }
13049 }
13050 }
13051 }
13052 SCIPhashmapFree(&varhash);
13053 SCIPfreeBufferArray(scip, &cardweights);
13054 SCIPfreeBufferArray(scip, &cardvars);
13055
13056 if ( *nupgdconss > noldupgdconss )
13057 success = TRUE;
13058 }
13059#endif
13060
13061 if( cutoff )
13063 else if( success || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
13065 else
13067
13068 return SCIP_OKAY;
13069}
13070
13071/** propagation conflict resolving method of constraint handler */
13072static
13073SCIP_DECL_CONSRESPROP(consRespropKnapsack)
13074{ /*lint --e{715}*/
13075 SCIP_CONSDATA* consdata;
13076 SCIP_Longint capsum;
13077 int i;
13078
13079 assert(result != NULL);
13080
13081 consdata = SCIPconsGetData(cons);
13082 assert(consdata != NULL);
13083
13084 /* check if we fixed a binary variable to one (due to negated clique) */
13085 if( inferinfo >= 0 && SCIPvarGetLbLocal(infervar) > 0.5 )
13086 {
13087 for( i = 0; i < consdata->nvars; ++i )
13088 {
13089 if( SCIPvarGetIndex(consdata->vars[i]) == inferinfo )
13090 {
13091 assert( SCIPgetVarUbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) < 0.5 );
13092 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
13093 break;
13094 }
13095 }
13097 }
13098 else
13099 {
13100 /* according to negated cliques the minweightsum and all variables which are fixed to one which led to a fixing of
13101 * another negated clique variable to one, the inferinfo was chosen to be the negative of the position in the
13102 * knapsack constraint, see one above call of SCIPinferBinvarCons
13103 */
13104 if( inferinfo < 0 )
13105 capsum = 0;
13106 else
13107 {
13108 /* locate the inference variable and calculate the capacity that has to be used up to conclude infervar == 0;
13109 * inferinfo stores the position of the inference variable (but maybe the variables were re-sorted)
13110 */
13111 if( inferinfo < consdata->nvars && consdata->vars[inferinfo] == infervar )
13112 capsum = consdata->weights[inferinfo];
13113 else
13114 {
13115 for( i = 0; i < consdata->nvars && consdata->vars[i] != infervar; ++i )
13116 {}
13118 capsum = consdata->weights[i];
13119 }
13120 }
13121
13122 /* add fixed-to-one variables up to the point, that their weight plus the weight of the conflict variable exceeds
13123 * the capacity
13124 */
13125 if( capsum <= consdata->capacity )
13126 {
13127 for( i = 0; i < consdata->nvars; i++ )
13128 {
13129 if( SCIPgetVarLbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) > 0.5 )
13130 {
13131 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
13132 capsum += consdata->weights[i];
13133 if( capsum > consdata->capacity )
13134 break;
13135 }
13136 }
13137 }
13138 }
13139
13140 /* NOTE: It might be the case that capsum < consdata->capacity. This is due the fact that the fixing of the variable
13141 * to zero can included negated clique information. A negated clique means, that at most one of the clique
13142 * variables can be zero. These information can be used to compute a minimum activity of the constraint and
13143 * used to fix variables to zero.
13144 *
13145 * Even if capsum < consdata->capacity we still reported a complete reason since the minimum activity is based
13146 * on global variable bounds. It might even be the case that we reported to many variables which are fixed to
13147 * one.
13148 */
13150
13151 return SCIP_OKAY;
13152}
13153
13154/** variable rounding lock method of constraint handler */
13155/**! [SnippetConsLockKnapsack] */
13156static
13157SCIP_DECL_CONSLOCK(consLockKnapsack)
13158{ /*lint --e{715}*/
13159 SCIP_CONSDATA* consdata;
13160 int i;
13161
13162 consdata = SCIPconsGetData(cons);
13163 assert(consdata != NULL);
13164
13165 for( i = 0; i < consdata->nvars; i++)
13166 {
13167 SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlocksneg, nlockspos) );
13168 }
13169
13170 return SCIP_OKAY;
13171}
13172/**! [SnippetConsLockKnapsack] */
13173
13174/** constraint activation notification method of constraint handler */
13175static
13176SCIP_DECL_CONSACTIVE(consActiveKnapsack)
13177{ /*lint --e{715}*/
13179 {
13180 SCIP_CALL( addNlrow(scip, cons) );
13181 }
13182
13183 return SCIP_OKAY;
13184}
13185
13186/** constraint deactivation notification method of constraint handler */
13187static
13188SCIP_DECL_CONSDEACTIVE(consDeactiveKnapsack)
13189{ /*lint --e{715}*/
13190 SCIP_CONSDATA* consdata;
13191
13192 assert(cons != NULL);
13193
13194 consdata = SCIPconsGetData(cons);
13195 assert(consdata != NULL);
13196
13197 /* remove row from NLP, if still in solving
13198 * if we are in exitsolve, the whole NLP will be freed anyway
13199 */
13200 if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && consdata->nlrow != NULL )
13201 {
13202 SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
13203 }
13204
13205 return SCIP_OKAY;
13206}
13207
13208/** variable deletion method of constraint handler */
13209static
13210SCIP_DECL_CONSDELVARS(consDelvarsKnapsack)
13211{
13212 assert(scip != NULL);
13213 assert(conshdlr != NULL);
13214 assert(conss != NULL || nconss == 0);
13215
13216 if( nconss > 0 )
13217 {
13218 SCIP_CALL( performVarDeletions(scip, conshdlr, conss, nconss) );
13219 }
13220
13221 return SCIP_OKAY;
13222}
13223
13224/** constraint display method of constraint handler */
13225static
13226SCIP_DECL_CONSPRINT(consPrintKnapsack)
13227{ /*lint --e{715}*/
13228 SCIP_CONSDATA* consdata;
13229 int i;
13230
13231 assert( scip != NULL );
13232 assert( conshdlr != NULL );
13233 assert( cons != NULL );
13234
13235 consdata = SCIPconsGetData(cons);
13236 assert(consdata != NULL);
13237
13238 for( i = 0; i < consdata->nvars; ++i )
13239 {
13240 if( i > 0 )
13241 SCIPinfoMessage(scip, file, " ");
13242 SCIPinfoMessage(scip, file, "%+" SCIP_LONGINT_FORMAT, consdata->weights[i]);
13243 SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[i], TRUE) );
13244 }
13245 SCIPinfoMessage(scip, file, " <= %" SCIP_LONGINT_FORMAT "", consdata->capacity);
13246
13247 return SCIP_OKAY;
13248}
13249
13250/** constraint copying method of constraint handler */
13251static
13252SCIP_DECL_CONSCOPY(consCopyKnapsack)
13253{ /*lint --e{715}*/
13254 SCIP_CONSHDLRDATA* conshdlrdata;
13255 SCIP_VAR** sourcevars;
13256 SCIP_Longint* weights;
13257 const char* consname;
13258 int nvars;
13259
13260 assert(scip != NULL);
13261 assert(sourcescip != NULL);
13262 assert(sourcecons != NULL);
13263 assert(valid != NULL);
13264
13265 conshdlrdata = SCIPconshdlrGetData(sourceconshdlr);
13266 assert(conshdlrdata != NULL);
13267
13268 /* get variables and weights of the source constraint */
13269 sourcevars = SCIPgetVarsKnapsack(sourcescip, sourcecons);
13270 nvars = SCIPgetNVarsKnapsack(sourcescip, sourcecons);
13271 weights = SCIPgetWeightsKnapsack(sourcescip, sourcecons);
13272
13273 if( conshdlrdata->copytypedcons )
13274 {
13275 SCIP_VAR** targetvars;
13276 int v;
13277
13278 *valid = TRUE;
13279 assert(nvars >= 0);
13280
13281 /* allocate target variable array */
13282 SCIP_CALL( SCIPallocBufferArray(scip, &targetvars, nvars) );
13283
13284 /* map source variables to target variables */
13285 for( v = 0; v < nvars && *valid; ++v )
13286 {
13287 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &targetvars[v], varmap, consmap, global, valid) );
13288 assert(!(*valid) || targetvars[v] != NULL);
13289 }
13290
13291 /* only create the target constraint if all variables were successfully copied */
13292 if( *valid )
13293 {
13294 if( name != NULL )
13295 consname = name;
13296 else
13297 consname = SCIPconsGetName(sourcecons);
13298
13299 SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, consname, nvars, targetvars, weights,
13300 SCIPgetCapacityKnapsack(sourcescip, sourcecons),
13301 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13302 }
13303
13304 SCIPfreeBufferArray(scip, &targetvars);
13305 }
13306 else
13307 {
13308 SCIP_Real* coefs;
13309 int v;
13310
13312 for( v = 0; v < nvars; ++v )
13313 coefs[v] = (SCIP_Real) weights[v];
13314
13315 if( name != NULL )
13316 consname = name;
13317 else
13318 consname = SCIPconsGetName(sourcecons);
13319
13320 /* copy the logic using the linear constraint copy method */
13321 SCIP_CALL( SCIPcopyConsLinear(scip, cons, sourcescip, consname, nvars, sourcevars, coefs,
13322 -SCIPinfinity(scip), (SCIP_Real) SCIPgetCapacityKnapsack(sourcescip, sourcecons), varmap, consmap,
13323 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, global, valid) );
13324 assert(cons != NULL);
13325
13326 SCIPfreeBufferArray(scip, &coefs);
13327 }
13328
13329 return SCIP_OKAY;
13330}
13331
13332/** constraint parsing method of constraint handler */
13333static
13334SCIP_DECL_CONSPARSE(consParseKnapsack)
13335{ /*lint --e{715}*/
13336 SCIP_VAR* var;
13337 SCIP_Longint weight;
13338 SCIP_VAR** vars;
13339 SCIP_Longint* weights;
13340 SCIP_Longint capacity;
13341 char* endptr;
13342 int nread;
13343 int nvars;
13344 int varssize;
13345
13346 assert(scip != NULL);
13347 assert(success != NULL);
13348 assert(str != NULL);
13349 assert(name != NULL);
13350 assert(cons != NULL);
13351
13352 *success = TRUE;
13353
13354 nvars = 0;
13355 varssize = 5;
13356 SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13357 SCIP_CALL( SCIPallocBufferArray(scip, &weights, varssize) );
13358
13359 while( *str != '\0' )
13360 {
13361 /* try to parse coefficient, and use 1 if not successful */
13362 weight = 1;
13363 nread = 0;
13364 (void) sscanf(str, "%" SCIP_LONGINT_FORMAT "%n", &weight, &nread);
13365 str += nread;
13366
13367 /* parse variable name */
13368 SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13369
13370 if( var == NULL )
13371 {
13372 endptr = strchr(endptr, '<');
13373
13374 if( endptr == NULL )
13375 {
13376 SCIPerrorMessage("no capacity found\n");
13377 *success = FALSE;
13378 }
13379 else
13380 str = endptr;
13381
13382 break;
13383 }
13384
13385 str = endptr;
13386
13387 /* store weight and variable */
13388 if( varssize <= nvars )
13389 {
13390 varssize = SCIPcalcMemGrowSize(scip, varssize+1);
13391 SCIP_CALL( SCIPreallocBufferArray(scip, &vars, varssize) );
13392 SCIP_CALL( SCIPreallocBufferArray(scip, &weights, varssize) );
13393 }
13394
13395 vars[nvars] = var;
13396 weights[nvars] = weight;
13397 ++nvars;
13398
13399 /* skip whitespace */
13400 SCIP_CALL( SCIPskipSpace((char**)&str) );
13401 }
13402
13403 if( *success )
13404 {
13405 if( strncmp(str, "<=", 2) != 0 )
13406 {
13407 SCIPerrorMessage("expected '<=' at begin of '%s'\n", str);
13408 *success = FALSE;
13409 }
13410 else
13411 {
13412 str += 2;
13413 }
13414 }
13415
13416 if( *success )
13417 {
13418 /* skip whitespace */
13419 SCIP_CALL( SCIPskipSpace((char**)&str) );
13420
13421 /* coverity[secure_coding] */
13422 if( sscanf(str, "%" SCIP_LONGINT_FORMAT, &capacity) != 1 )
13423 {
13424 SCIPerrorMessage("error parsing capacity from '%s'\n", str);
13425 *success = FALSE;
13426 }
13427 else
13428 {
13429 SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13430 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13431 }
13432 }
13433
13435 SCIPfreeBufferArray(scip, &weights);
13436
13437 return SCIP_OKAY;
13438}
13439
13440/** constraint method of constraint handler which returns the variables (if possible) */
13441static
13442SCIP_DECL_CONSGETVARS(consGetVarsKnapsack)
13443{ /*lint --e{715}*/
13444 SCIP_CONSDATA* consdata;
13445
13446 consdata = SCIPconsGetData(cons);
13447 assert(consdata != NULL);
13448
13449 if( varssize < consdata->nvars )
13450 (*success) = FALSE;
13451 else
13452 {
13453 assert(vars != NULL);
13454
13455 BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13456 (*success) = TRUE;
13457 }
13458
13459 return SCIP_OKAY;
13460}
13461
13462/** constraint method of constraint handler which returns the number of variables (if possible) */
13463static
13464SCIP_DECL_CONSGETNVARS(consGetNVarsKnapsack)
13465{ /*lint --e{715}*/
13466 SCIP_CONSDATA* consdata;
13467
13468 consdata = SCIPconsGetData(cons);
13469 assert(consdata != NULL);
13470
13471 (*nvars) = consdata->nvars;
13472 (*success) = TRUE;
13473
13474 return SCIP_OKAY;
13475}
13476
13477/** constraint handler method which returns the permutation symmetry detection graph of a constraint */
13478static
13479SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphKnapsack)
13480{ /*lint --e{715}*/
13481 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) );
13482
13483 return SCIP_OKAY;
13484}
13485
13486/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint */
13487static
13488SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphKnapsack)
13489{ /*lint --e{715}*/
13490 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) );
13491
13492 return SCIP_OKAY;
13493}
13494
13495/*
13496 * Event handler
13497 */
13498
13499/** execution method of bound change event handler */
13500static
13501SCIP_DECL_EVENTEXEC(eventExecKnapsack)
13502{ /*lint --e{715}*/
13503 SCIP_CONSDATA* consdata;
13504
13505 assert(eventdata != NULL);
13506 assert(eventdata->cons != NULL);
13507
13508 consdata = SCIPconsGetData(eventdata->cons);
13509 assert(consdata != NULL);
13510
13511 switch( SCIPeventGetType(event) )
13512 {
13514 consdata->onesweightsum += eventdata->weight;
13515 consdata->presolvedtiming = 0;
13516 SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13517 break;
13519 consdata->onesweightsum -= eventdata->weight;
13520 break;
13522 consdata->presolvedtiming = 0;
13523 SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13524 break;
13525 case SCIP_EVENTTYPE_VARFIXED: /* the variable should be removed from the constraint in presolving */
13526 if( !consdata->existmultaggr )
13527 {
13528 SCIP_VAR* var;
13529 var = SCIPeventGetVar(event);
13530 assert(var != NULL);
13531
13532 /* if the variable was aggregated or multiaggregated, we must signal to propagation that we are no longer merged */
13534 {
13535 consdata->existmultaggr = TRUE;
13536 consdata->merged = FALSE;
13537 }
13540 consdata->merged = FALSE;
13541 }
13542 /*lint -fallthrough*/
13543 case SCIP_EVENTTYPE_IMPLADDED: /* further preprocessing might be possible due to additional implications */
13544 consdata->presolvedtiming = 0;
13545 break;
13547 consdata->varsdeleted = TRUE;
13548 break;
13549 default:
13550 SCIPerrorMessage("invalid event type %" SCIP_EVENTTYPE_FORMAT "\n", SCIPeventGetType(event));
13551 return SCIP_INVALIDDATA;
13552 }
13553
13554 return SCIP_OKAY;
13555}
13556
13557
13558/*
13559 * constraint specific interface methods
13560 */
13561
13562/** creates the handler for knapsack constraints and includes it in SCIP */
13564 SCIP* scip /**< SCIP data structure */
13565 )
13566{
13567 SCIP_EVENTHDLRDATA* eventhdlrdata;
13568 SCIP_CONSHDLRDATA* conshdlrdata;
13569 SCIP_CONSHDLR* conshdlr;
13570
13571 /* create knapsack constraint handler data */
13572 SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
13573
13574 /* include event handler for bound change events */
13575 eventhdlrdata = NULL;
13576 conshdlrdata->eventhdlr = NULL;
13578 eventExecKnapsack, eventhdlrdata) );
13579 conshdlrdata->probtoidxmap = NULL;
13580 conshdlrdata->probtoidxmapsize = 0;
13581
13582 /* get event handler for bound change events */
13583 if( conshdlrdata->eventhdlr == NULL )
13584 {
13585 SCIPerrorMessage("event handler for knapsack constraints not found\n");
13586 return SCIP_PLUGINNOTFOUND;
13587 }
13588
13589 /* include constraint handler */
13592 consEnfolpKnapsack, consEnfopsKnapsack, consCheckKnapsack, consLockKnapsack,
13593 conshdlrdata) );
13594
13595 assert(conshdlr != NULL);
13596
13597 /* set non-fundamental callbacks via specific setter functions */
13598 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyKnapsack, consCopyKnapsack) );
13599 SCIP_CALL( SCIPsetConshdlrActive(scip, conshdlr, consActiveKnapsack) );
13600 SCIP_CALL( SCIPsetConshdlrDeactive(scip, conshdlr, consDeactiveKnapsack) );
13601 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteKnapsack) );
13602 SCIP_CALL( SCIPsetConshdlrDelvars(scip, conshdlr, consDelvarsKnapsack) );
13603 SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitKnapsack) );
13604 SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreKnapsack) );
13605 SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolKnapsack) );
13606 SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolKnapsack) );
13607 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeKnapsack) );
13608 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsKnapsack) );
13609 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsKnapsack) );
13610 SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitKnapsack) );
13611 SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreKnapsack) );
13612 SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpKnapsack) );
13613 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseKnapsack) );
13615 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintKnapsack) );
13618 SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropKnapsack) );
13619 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpKnapsack, consSepasolKnapsack, CONSHDLR_SEPAFREQ,
13621 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransKnapsack) );
13622 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxKnapsack) );
13623 SCIP_CALL( SCIPsetConshdlrGetPermsymGraph(scip, conshdlr, consGetPermsymGraphKnapsack) );
13624 SCIP_CALL( SCIPsetConshdlrGetSignedPermsymGraph(scip, conshdlr, consGetSignedPermsymGraphKnapsack) );
13625
13626 if( SCIPfindConshdlr(scip,"linear") != NULL )
13627 {
13628 /* include the linear constraint to knapsack constraint upgrade in the linear constraint handler */
13630 }
13631
13632 /* add knapsack constraint handler parameters */
13634 "constraints/" CONSHDLR_NAME "/sepacardfreq",
13635 "multiplier on separation frequency, how often knapsack cuts are separated (-1: never, 0: only at root)",
13636 &conshdlrdata->sepacardfreq, TRUE, DEFAULT_SEPACARDFREQ, -1, SCIP_MAXTREEDEPTH, NULL, NULL) );
13638 "constraints/" CONSHDLR_NAME "/maxcardbounddist",
13639 "maximal relative distance from current node's dual bound to primal bound compared to best node's dual bound for separating knapsack cuts",
13640 &conshdlrdata->maxcardbounddist, TRUE, DEFAULT_MAXCARDBOUNDDIST, 0.0, 1.0, NULL, NULL) );
13642 "constraints/" CONSHDLR_NAME "/cliqueextractfactor",
13643 "lower clique size limit for greedy clique extraction algorithm (relative to largest clique)",
13644 &conshdlrdata->cliqueextractfactor, TRUE, DEFAULT_CLIQUEEXTRACTFACTOR, 0.0, 1.0, NULL, NULL) );
13646 "constraints/" CONSHDLR_NAME "/maxrounds",
13647 "maximal number of separation rounds per node (-1: unlimited)",
13648 &conshdlrdata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
13650 "constraints/" CONSHDLR_NAME "/maxroundsroot",
13651 "maximal number of separation rounds per node in the root node (-1: unlimited)",
13652 &conshdlrdata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
13654 "constraints/" CONSHDLR_NAME "/maxsepacuts",
13655 "maximal number of cuts separated per separation round",
13656 &conshdlrdata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
13658 "constraints/" CONSHDLR_NAME "/maxsepacutsroot",
13659 "maximal number of cuts separated per separation round in the root node",
13660 &conshdlrdata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
13662 "constraints/" CONSHDLR_NAME "/disaggregation",
13663 "should disaggregation of knapsack constraints be allowed in preprocessing?",
13664 &conshdlrdata->disaggregation, TRUE, DEFAULT_DISAGGREGATION, NULL, NULL) );
13666 "constraints/" CONSHDLR_NAME "/simplifyinequalities",
13667 "should presolving try to simplify knapsacks",
13668 &conshdlrdata->simplifyinequalities, TRUE, DEFAULT_SIMPLIFYINEQUALITIES, NULL, NULL) );
13670 "constraints/" CONSHDLR_NAME "/negatedclique",
13671 "should negated clique information be used in solving process",
13672 &conshdlrdata->negatedclique, TRUE, DEFAULT_NEGATEDCLIQUE, NULL, NULL) );
13674 "constraints/" CONSHDLR_NAME "/presolpairwise",
13675 "should pairwise constraint comparison be performed in presolving?",
13676 &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13678 "constraints/" CONSHDLR_NAME "/presolusehashing",
13679 "should hash table be used for detecting redundant constraints in advance",
13680 &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) );
13682 "constraints/" CONSHDLR_NAME "/dualpresolving",
13683 "should dual presolving steps be performed?",
13684 &conshdlrdata->dualpresolving, TRUE, DEFAULT_DUALPRESOLVING, NULL, NULL) );
13686 "constraints/" CONSHDLR_NAME "/usegubs",
13687 "should GUB information be used for separation?",
13688 &conshdlrdata->usegubs, TRUE, DEFAULT_USEGUBS, NULL, NULL) );
13690 "constraints/" CONSHDLR_NAME "/detectcutoffbound",
13691 "should presolving try to detect constraints parallel to the objective function defining an upper bound and prevent these constraints from entering the LP?",
13692 &conshdlrdata->detectcutoffbound, TRUE, DEFAULT_DETECTCUTOFFBOUND, NULL, NULL) );
13694 "constraints/" CONSHDLR_NAME "/detectlowerbound",
13695 "should presolving try to detect constraints parallel to the objective function defining a lower bound and prevent these constraints from entering the LP?",
13696 &conshdlrdata->detectlowerbound, TRUE, DEFAULT_DETECTLOWERBOUND, NULL, NULL) );
13698 "constraints/" CONSHDLR_NAME "/updatecliquepartitions",
13699 "should clique partition information be updated when old partition seems outdated?",
13700 &conshdlrdata->updatecliquepartitions, TRUE, DEFAULT_UPDATECLIQUEPARTITIONS, NULL, NULL) );
13702 "constraints/" CONSHDLR_NAME "/clqpartupdatefac",
13703 "factor on the growth of global cliques to decide when to update a previous "
13704 "(negated) clique partition (used only if updatecliquepartitions is set to TRUE)",
13705 &conshdlrdata->clqpartupdatefac, TRUE, DEFAULT_CLQPARTUPDATEFAC, 1.0, 10.0, NULL, NULL) );
13706#ifdef WITH_CARDINALITY_UPGRADE
13708 "constraints/" CONSHDLR_NAME "/upgdcardinality",
13709 "if TRUE then try to update knapsack constraints to cardinality constraints",
13710 &conshdlrdata->upgdcardinality, TRUE, DEFAULT_UPGDCARDINALITY, NULL, NULL) );
13711#endif
13713 "constraints/" CONSHDLR_NAME "/copytypedcons",
13714 "should knapsack constraints be copied as knapsack instead of as linear constraints?",
13715 &conshdlrdata->copytypedcons, TRUE, DEFAULT_COPYTYPEDCONS, NULL, NULL) );
13716
13717 return SCIP_OKAY;
13718}
13719
13720/** creates and captures a knapsack constraint
13721 *
13722 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13723 */
13724/**! [SnippetConsCreationKnapsack] */
13726 SCIP* scip, /**< SCIP data structure */
13727 SCIP_CONS** cons, /**< pointer to hold the created constraint */
13728 const char* name, /**< name of constraint */
13729 int nvars, /**< number of items in the knapsack */
13730 SCIP_VAR** vars, /**< array with item variables */
13731 SCIP_Longint* weights, /**< array with item weights */
13732 SCIP_Longint capacity, /**< capacity of knapsack (right hand side of inequality) */
13733 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13734 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13735 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13736 * Usually set to TRUE. */
13737 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13738 * TRUE for model constraints, FALSE for additional, redundant constraints. */
13739 SCIP_Bool check, /**< should the constraint be checked for feasibility?
13740 * TRUE for model constraints, FALSE for additional, redundant constraints. */
13741 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13742 * Usually set to TRUE. */
13743 SCIP_Bool local, /**< is constraint only valid locally?
13744 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13745 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13746 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13747 * adds coefficients to this constraint. */
13748 SCIP_Bool dynamic, /**< is constraint subject to aging?
13749 * Usually set to FALSE. Set to TRUE for own cuts which
13750 * are separated as constraints. */
13751 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13752 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13753 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13754 * if it may be moved to a more global node?
13755 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13756 )
13757{
13758 SCIP_CONSHDLRDATA* conshdlrdata;
13759 SCIP_CONSHDLR* conshdlr;
13760 SCIP_CONSDATA* consdata;
13761 int i;
13762
13763 /* find the knapsack constraint handler */
13764 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13765 if( conshdlr == NULL )
13766 {
13767 SCIPerrorMessage("knapsack constraint handler not found\n");
13768 return SCIP_PLUGINNOTFOUND;
13769 }
13770
13771 /* check whether all variables are binary */
13772 assert(vars != NULL || nvars == 0);
13773 for( i = 0; i < nvars; ++i )
13774 {
13775 if( !SCIPvarIsBinary(vars[i]) )
13776 {
13777 SCIPerrorMessage("item <%s> is not binary\n", SCIPvarGetName(vars[i]));
13778 return SCIP_INVALIDDATA;
13779 }
13780 }
13781
13782 /* get event handler */
13783 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13784 assert(conshdlrdata != NULL);
13785 assert(conshdlrdata->eventhdlr != NULL);
13786
13787 /* create constraint data */
13788 SCIP_CALL( consdataCreate(scip, &consdata, nvars, vars, weights, capacity) );
13789
13790 /* create constraint */
13791 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
13792 local, modifiable, dynamic, removable, stickingatnode) );
13793
13794 /* catch events for variables */
13795 if( SCIPisTransformed(scip) )
13796 {
13797 SCIP_CALL( catchEvents(scip, *cons, consdata, conshdlrdata->eventhdlr) );
13798 }
13799
13800 return SCIP_OKAY;
13801}
13802/**! [SnippetConsCreationKnapsack] */
13803
13804/** creates and captures a knapsack constraint
13805 * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13806 * method SCIPcreateConsKnapsack(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13807 *
13808 * @see SCIPcreateConsKnapsack() for information about the basic constraint flag configuration
13809 *
13810 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13811 */
13813 SCIP* scip, /**< SCIP data structure */
13814 SCIP_CONS** cons, /**< pointer to hold the created constraint */
13815 const char* name, /**< name of constraint */
13816 int nvars, /**< number of items in the knapsack */
13817 SCIP_VAR** vars, /**< array with item variables */
13818 SCIP_Longint* weights, /**< array with item weights */
13819 SCIP_Longint capacity /**< capacity of knapsack */
13820 )
13821{
13822 assert(scip != NULL);
13823
13824 SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13826
13827 return SCIP_OKAY;
13828}
13829
13830/** adds new item to knapsack constraint */
13832 SCIP* scip, /**< SCIP data structure */
13833 SCIP_CONS* cons, /**< constraint data */
13834 SCIP_VAR* var, /**< item variable */
13835 SCIP_Longint weight /**< item weight */
13836 )
13837{
13838 assert(var != NULL);
13839 assert(scip != NULL);
13840
13842
13843 SCIP_CALL( addCoef(scip, cons, var, weight) );
13844
13845 return SCIP_OKAY;
13846}
13847
13848/** gets the capacity of the knapsack constraint */
13850 SCIP* scip, /**< SCIP data structure */
13851 SCIP_CONS* cons /**< constraint data */
13852 )
13853{
13854 SCIP_CONSDATA* consdata;
13855
13856 assert(scip != NULL);
13857
13859
13860 consdata = SCIPconsGetData(cons);
13861 assert(consdata != NULL);
13862
13863 return consdata->capacity;
13864}
13865
13866/** changes capacity of the knapsack constraint
13867 *
13868 * @note This method can only be called during problem creation stage (SCIP_STAGE_PROBLEM)
13869 */
13871 SCIP* scip, /**< SCIP data structure */
13872 SCIP_CONS* cons, /**< constraint data */
13873 SCIP_Longint capacity /**< new capacity of knapsack */
13874 )
13875{
13876 SCIP_CONSDATA* consdata;
13877
13878 assert(scip != NULL);
13879
13881
13883 {
13884 SCIPerrorMessage("method can only be called during problem creation stage\n");
13885 return SCIP_INVALIDDATA;
13886 }
13887
13888 consdata = SCIPconsGetData(cons);
13889 assert(consdata != NULL);
13890
13891 consdata->capacity = capacity;
13892
13893 return SCIP_OKAY;
13894}
13895
13896/** gets the number of items in the knapsack constraint */
13898 SCIP* scip, /**< SCIP data structure */
13899 SCIP_CONS* cons /**< constraint data */
13900 )
13901{
13902 SCIP_CONSDATA* consdata;
13903
13904 assert(scip != NULL);
13905
13907
13908 consdata = SCIPconsGetData(cons);
13909 assert(consdata != NULL);
13910
13911 return consdata->nvars;
13912}
13913
13914/** gets the array of variables in the knapsack constraint; the user must not modify this array! */
13916 SCIP* scip, /**< SCIP data structure */
13917 SCIP_CONS* cons /**< constraint data */
13918 )
13919{
13920 SCIP_CONSDATA* consdata;
13921
13922 assert(scip != NULL);
13923
13925
13926 consdata = SCIPconsGetData(cons);
13927 assert(consdata != NULL);
13928
13929 return consdata->vars;
13930}
13931
13932/** gets the array of weights in the knapsack constraint; the user must not modify this array! */
13934 SCIP* scip, /**< SCIP data structure */
13935 SCIP_CONS* cons /**< constraint data */
13936 )
13937{
13938 SCIP_CONSDATA* consdata;
13939
13940 assert(scip != NULL);
13941
13943
13944 consdata = SCIPconsGetData(cons);
13945 assert(consdata != NULL);
13946
13947 return consdata->weights;
13948}
13949
13950/** gets the dual solution of the knapsack constraint in the current LP */
13952 SCIP* scip, /**< SCIP data structure */
13953 SCIP_CONS* cons /**< constraint data */
13954 )
13955{
13956 SCIP_CONSDATA* consdata;
13957
13958 assert(scip != NULL);
13959
13961
13962 consdata = SCIPconsGetData(cons);
13963 assert(consdata != NULL);
13964
13965 if( consdata->row != NULL )
13966 return SCIProwGetDualsol(consdata->row);
13967 else
13968 return 0.0;
13969}
13970
13971/** gets the dual Farkas value of the knapsack constraint in the current infeasible LP */
13973 SCIP* scip, /**< SCIP data structure */
13974 SCIP_CONS* cons /**< constraint data */
13975 )
13976{
13977 SCIP_CONSDATA* consdata;
13978
13979 assert(scip != NULL);
13980
13982
13983 consdata = SCIPconsGetData(cons);
13984 assert(consdata != NULL);
13985
13986 if( consdata->row != NULL )
13987 return SCIProwGetDualfarkas(consdata->row);
13988 else
13989 return 0.0;
13990}
13991
13992/** returns the linear relaxation of the given knapsack constraint; may return NULL if no LP row was yet created;
13993 * the user must not modify the row!
13994 */
13996 SCIP* scip, /**< SCIP data structure */
13997 SCIP_CONS* cons /**< constraint data */
13998 )
13999{
14000 SCIP_CONSDATA* consdata;
14001
14002 assert(scip != NULL);
14003
14005
14006 consdata = SCIPconsGetData(cons);
14007 assert(consdata != NULL);
14008
14009 return consdata->row;
14010}
14011
14012/** creates and returns the row of the given knapsack constraint */
14014 SCIP* scip, /**< SCIP data structure */
14015 SCIP_CONS* cons /**< constraint data */
14016 )
14017{
14018 SCIP_CONSDATA* consdata;
14019 int i;
14020
14021 assert(scip != NULL);
14022
14024
14025 consdata = SCIPconsGetData(cons);
14026 assert(consdata != NULL);
14027 assert(consdata->row == NULL);
14028
14029 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, cons, SCIPconsGetName(cons),
14030 -SCIPinfinity(scip), (SCIP_Real)consdata->capacity,
14032
14033 SCIP_CALL( SCIPcacheRowExtensions(scip, consdata->row) );
14034 for( i = 0; i < consdata->nvars; ++i )
14035 {
14036 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, consdata->vars[i], (SCIP_Real)consdata->weights[i]) );
14037 }
14038 SCIP_CALL( SCIPflushRowExtensions(scip, consdata->row) );
14039
14040 return SCIP_OKAY;
14041}
14042
14043/** cleans up (multi-)aggregations and fixings from knapsack constraints */
14045 SCIP* scip, /**< SCIP data structure */
14046 SCIP_Bool onlychecked, /**< should only checked constraints be cleaned up? */
14047 SCIP_Bool* infeasible, /**< pointer to return whether the problem was detected to be infeasible */
14048 int* ndelconss /**< pointer to count number of deleted constraints */
14049 )
14050{
14051 SCIP_CONSHDLR* conshdlr;
14052 SCIP_CONS** conss;
14053 int nconss;
14054 int i;
14055
14056 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14057 if( conshdlr == NULL )
14058 return SCIP_OKAY;
14059
14060 assert(infeasible != NULL);
14061 *infeasible = FALSE;
14062
14063 nconss = onlychecked ? SCIPconshdlrGetNCheckConss(conshdlr) : SCIPconshdlrGetNActiveConss(conshdlr);
14064 conss = onlychecked ? SCIPconshdlrGetCheckConss(conshdlr) : SCIPconshdlrGetConss(conshdlr);
14065
14066 /* loop backwards since then deleted constraints do not interfere with the loop */
14067 for( i = nconss - 1; i >= 0; --i )
14068 {
14069 SCIP_CALL( applyFixings(scip, conss[i], infeasible) );
14070
14071 if( *infeasible )
14072 break;
14073
14074 if( SCIPconsGetData(conss[i])->nvars >= 1 )
14075 continue;
14076
14077 SCIP_CALL( SCIPdelCons(scip, conss[i]) );
14078 ++(*ndelconss);
14079 }
14080
14081 return SCIP_OKAY;
14082}
#define EVENTHDLR_NAME
SCIP_VAR * h
SCIP_VAR * w
SCIP_VAR ** b
#define EVENTHDLR_DESC
#define DEFAULT_DUALPRESOLVING
Definition cons_and.c:109
#define CONSHDLR_NEEDSCONS
Definition cons_and.c:96
#define CONSHDLR_SEPAFREQ
Definition cons_and.c:89
#define CONSHDLR_CHECKPRIORITY
Definition cons_and.c:88
#define CONSHDLR_DESC
Definition cons_and.c:85
#define CONSHDLR_PROP_TIMING
Definition cons_and.c:99
#define CONSHDLR_MAXPREROUNDS
Definition cons_and.c:93
#define DEFAULT_PRESOLPAIRWISE
Definition cons_and.c:104
#define CONSHDLR_SEPAPRIORITY
Definition cons_and.c:86
#define DEFAULT_PRESOLUSEHASHING
Definition cons_and.c:112
#define MINGAINPERNMINCOMPARISONS
Definition cons_and.c:114
#define CONSHDLR_PROPFREQ
Definition cons_and.c:90
#define NMINCOMPARISONS
Definition cons_and.c:113
#define CONSHDLR_PRESOLTIMING
Definition cons_and.c:98
#define CONSHDLR_EAGERFREQ
Definition cons_and.c:91
#define CONSHDLR_ENFOPRIORITY
Definition cons_and.c:87
#define CONSHDLR_DELAYSEPA
Definition cons_and.c:94
#define CONSHDLR_NAME
Definition cons_and.c:84
#define CONSHDLR_DELAYPROP
Definition cons_and.c:95
constraint handler for cardinality constraints
#define DEFAULT_MAXROUNDSROOT
#define DEFAULT_MAXSEPACUTSROOT
#define DEFAULT_MAXSEPACUTS
#define DEFAULT_MAXROUNDS
#define LINCONSUPGD_PRIORITY
static SCIP_Longint safeAddMinweightsGUB(SCIP_Longint val1, SCIP_Longint val2)
static SCIP_RETCODE separateCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool sepacuts, SCIP_Bool usegubs, SCIP_Bool *cutoff, int *ncuts)
static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSDATA **consdata, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
static SCIP_RETCODE getLiftingSequenceGUB(SCIP *scip, SCIP_GUBSET *gubset, SCIP_Real *solvals, SCIP_Longint *weights, int *varsC1, int *varsC2, int *varsF, int *varsR, int nvarsC1, int nvarsC2, int nvarsF, int nvarsR, int *gubconsGC1, int *gubconsGC2, int *gubconsGFC1, int *gubconsGR, int *ngubconsGC1, int *ngubconsGC2, int *ngubconsGFC1, int *ngubconsGR, int *ngubconscapexceed, int *maxgubvarssize)
GUBConsstatus
@ GUBCONSSTATUS_BELONGSTOSET_GF
@ GUBCONSSTATUS_UNINITIAL
@ GUBCONSSTATUS_BELONGSTOSET_GR
@ GUBCONSSTATUS_BELONGSTOSET_GOC1
@ GUBCONSSTATUS_BELONGSTOSET_GNC1
@ GUBCONSSTATUS_BELONGSTOSET_GC2
static SCIP_RETCODE deleteRedundantVars(SCIP *scip, SCIP_CONS *cons, SCIP_Longint frontsum, int splitpos, int *nchgcoefs, int *nchgsides, int *naddconss)
#define DEFAULT_SEPACARDFREQ
static SCIP_RETCODE insertZerolist(SCIP *scip, int **liftcands, int *nliftcands, int **firstidxs, SCIP_Longint **zeroweightsums, int **zeroitems, int **nextidxs, int *zeroitemssize, int *nzeroitems, int probindex, SCIP_Bool value, int knapsackidx, SCIP_Longint knapsackweight, SCIP_Bool *memlimitreached)
static SCIP_RETCODE addRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff)
#define KNAPSACKRELAX_MAXDELTA
static SCIP_RETCODE eventdataCreate(SCIP *scip, SCIP_EVENTDATA **eventdata, SCIP_CONS *cons, SCIP_Longint weight)
static SCIP_RETCODE prepareCons(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *ndelconss, int *nchgcoefs)
#define DEFAULT_USEGUBS
static SCIP_RETCODE enlargeMinweights(SCIP *scip, SCIP_Longint **minweightsptr, int *minweightslen, int *minweightssize, int newlen)
#define DEFAULT_COPYTYPEDCONS
static SCIP_RETCODE separateSequLiftedExtendedWeightInequality(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *feassetvars, int *nonfeassetvars, int nfeassetvars, int nnonfeassetvars, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
static SCIP_RETCODE GUBconsCreate(SCIP *scip, SCIP_GUBCONS **gubcons)
#define KNAPSACKRELAX_MAXSCALE
static void normalizeWeights(SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
static SCIP_RETCODE separateSupLiftedMinimalCoverInequality(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *mincovervars, int *nonmincovervars, int nmincovervars, int nnonmincovervars, SCIP_Longint mincoverweight, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
#define DEFAULT_DETECTCUTOFFBOUND
static SCIP_RETCODE addCliques(SCIP *const scip, SCIP_CONS *const cons, SCIP_Real cliqueextractfactor, SCIP_Bool *const cutoff, int *const nbdchgs)
static SCIP_RETCODE upgradeCons(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *naddconss)
static SCIP_RETCODE createRelaxation(SCIP *scip, SCIP_CONS *cons)
static void updateWeightSums(SCIP_CONSDATA *consdata, SCIP_VAR *var, SCIP_Longint weightdelta)
static void GUBconsFree(SCIP *scip, SCIP_GUBCONS **gubcons)
struct SCIP_GUBSet SCIP_GUBSET
static void getPartitionCovervars(SCIP *scip, SCIP_Real *solvals, int *covervars, int ncovervars, int *varsC1, int *varsC2, int *nvarsC1, int *nvarsC2)
static void GUBsetSwapVars(SCIP *scip, SCIP_GUBSET *gubset, int var1, int var2)
static SCIP_RETCODE unlockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
static SCIP_RETCODE getCover(SCIP *scip, SCIP_VAR **vars, int nvars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int *ncovervars, int *nnoncovervars, SCIP_Longint *coverweight, SCIP_Bool *found, SCIP_Bool modtransused, int *ntightened, SCIP_Bool *fractional)
static SCIP_RETCODE consdataEnsureVarsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num, SCIP_Bool transformed)
static void GUBsetFree(SCIP *scip, SCIP_GUBSET **gubset)
static SCIP_RETCODE createNormalizedKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
static SCIP_RETCODE calcCliquepartition(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONSDATA *consdata, SCIP_Bool normalclique, SCIP_Bool negatedclique)
static SCIP_RETCODE performVarDeletions(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
struct sortkeypair SORTKEYPAIR
#define DEFAULT_NEGATEDCLIQUE
enum GUBVarstatus GUBVARSTATUS
static SCIP_RETCODE changePartitionCovervars(SCIP *scip, SCIP_Longint *weights, int *varsC1, int *varsC2, int *nvarsC1, int *nvarsC2)
#define DEFAULT_MAXCARDBOUNDDIST
#define MAXCOVERSIZEITERLEWI
static SCIP_RETCODE mergeMultiples(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff)
static SCIP_RETCODE GUBsetCheck(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars)
static SCIP_RETCODE GUBsetMoveVar(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, int var, int oldgubcons, int newgubcons)
static void sortItems(SCIP_CONSDATA *consdata)
static SCIP_RETCODE addNegatedCliques(SCIP *const scip, SCIP_CONS *const cons, SCIP_Bool *const cutoff, int *const nbdchgs)
static SCIP_RETCODE detectRedundantVars(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *nchgcoefs, int *nchgsides, int *naddconss)
static SCIP_RETCODE GUBsetGetCliquePartition(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, SCIP_Real *solvals)
static SCIP_RETCODE addSymmetryInformation(SCIP *scip, SYM_SYMTYPE symtype, SCIP_CONS *cons, SYM_GRAPH *graph, SCIP_Bool *success)
static SCIP_RETCODE applyFixings(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff)
static SCIP_RETCODE lockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
static void computeMinweightsGUB(SCIP_Longint *minweights, SCIP_Longint *finished, SCIP_Longint *unfinished, int minweightslen)
static SCIP_RETCODE sequentialUpAndDownLiftingGUB(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, int ngubconscapexceed, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *gubconsGC1, int *gubconsGC2, int *gubconsGFC1, int *gubconsGR, int ngubconsGC1, int ngubconsGC2, int ngubconsGFC1, int ngubconsGR, int alpha0, int *liftcoefs, SCIP_Real *cutact, int *liftrhs, int maxgubvarssize)
#define HASHSIZE_KNAPSACKCONS
static SCIP_RETCODE GUBsetCalcCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques, SCIP_Real *solvals)
static SCIP_RETCODE checkCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool checklprows, SCIP_Bool printreason, SCIP_Bool *violated)
static SCIP_RETCODE dualWeightsTightening(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *nchgcoefs, int *nchgsides, int *naddconss)
#define MAX_CLIQUELENGTH
#define DEFAULT_CLQPARTUPDATEFAC
static SCIP_RETCODE addCoef(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
static SCIP_RETCODE dropEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata, SCIP_EVENTHDLR *eventhdlr)
#define IDX(j, d)
static SCIP_Bool checkMinweightidx(SCIP_Longint *weights, SCIP_Longint capacity, int *covervars, int ncovervars, SCIP_Longint coverweight, int minweightidx, int j)
static SCIP_RETCODE sequentialUpAndDownLifting(SCIP *scip, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *varsM1, int *varsM2, int *varsF, int *varsR, int nvarsM1, int nvarsM2, int nvarsF, int nvarsR, int alpha0, int *liftcoefs, SCIP_Real *cutact, int *liftrhs)
struct SCIP_GUBCons SCIP_GUBCONS
static SCIP_RETCODE separateSequLiftedMinimalCoverInequality(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *mincovervars, int *nonmincovervars, int nmincovervars, int nnonmincovervars, SCIP_SOL *sol, SCIP_GUBSET *gubset, SCIP_Bool *cutoff, int *ncuts)
#define GUBCONSGROWVALUE
static SCIP_RETCODE makeCoverMinimal(SCIP *scip, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int *ncovervars, int *nnoncovervars, SCIP_Longint *coverweight, SCIP_Bool modtransused)
static SCIP_RETCODE delCoefPos(SCIP *scip, SCIP_CONS *cons, int pos)
static SCIP_RETCODE greedyCliqueAlgorithm(SCIP *const scip, SCIP_VAR **items, SCIP_Longint *weights, int nitems, SCIP_Longint capacity, SCIP_Bool sorteditems, SCIP_Real cliqueextractfactor, SCIP_Bool *const cutoff, int *const nbdchgs)
#define DEFAULT_CLIQUEEXTRACTFACTOR
#define DEFAULT_SIMPLIFYINEQUALITIES
static SCIP_RETCODE eventdataFree(SCIP *scip, SCIP_EVENTDATA **eventdata)
static SCIP_RETCODE detectRedundantConstraints(SCIP *scip, BMS_BLKMEM *blkmem, SCIP_CONS **conss, int nconss, SCIP_Bool *cutoff, int *ndelconss)
static SCIP_RETCODE GUBsetCreate(SCIP *scip, SCIP_GUBSET **gubset, int nvars, SCIP_Longint *weights, SCIP_Longint capacity)
static SCIP_RETCODE getLiftingSequence(SCIP *scip, SCIP_Real *solvals, SCIP_Longint *weights, int *varsF, int *varsC2, int *varsR, int nvarsF, int nvarsC2, int nvarsR)
#define MAXNCLIQUEVARSCOMP
static SCIP_RETCODE tightenWeightsLift(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, SCIP_Bool *cutoff)
static SCIP_RETCODE getFeasibleSet(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int *ncovervars, int *nnoncovervars, SCIP_Longint *coverweight, SCIP_Bool modtransused, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
static SCIP_RETCODE simplifyInequalities(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *ndelconss, int *nchgcoefs, int *nchgsides, int *naddconss, SCIP_Bool *cutoff)
enum GUBConsstatus GUBCONSSTATUS
static SCIP_RETCODE removeZeroWeights(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE catchEvents(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
static SCIP_RETCODE enforceConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_RESULT *result)
static SCIP_RETCODE superadditiveUpLifting(SCIP *scip, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int ncovervars, int nnoncovervars, SCIP_Longint coverweight, SCIP_Real *liftcoefs, SCIP_Real *cutact)
static SCIP_RETCODE addNlrow(SCIP *scip, SCIP_CONS *cons)
static void getPartitionNoncovervars(SCIP *scip, SCIP_Real *solvals, int *noncovervars, int nnoncovervars, int *varsF, int *varsR, int *nvarsF, int *nvarsR)
static SCIP_RETCODE stableSort(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR **vars, SCIP_Longint *weights, int *cliquestartposs, SCIP_Bool usenegatedclique)
static SCIP_RETCODE tightenWeights(SCIP *scip, SCIP_CONS *cons, SCIP_PRESOLTIMING presoltiming, int *nchgcoefs, int *nchgsides, int *naddconss, int *ndelconss, SCIP_Bool *cutoff)
static void consdataChgWeight(SCIP_CONSDATA *consdata, int item, SCIP_Longint newweight)
static SCIP_RETCODE propagateCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff, SCIP_Bool *redundant, int *nfixedvars, SCIP_Bool usenegatedclique)
#define KNAPSACKRELAX_MAXDNOM
#define USESUPADDLIFT
#define MAXABSVBCOEF
#define MAX_USECLIQUES_SIZE
#define DEFAULT_UPDATECLIQUEPARTITIONS
GUBVarstatus
@ GUBVARSTATUS_BELONGSTOSET_F
@ GUBVARSTATUS_BELONGSTOSET_C1
@ GUBVARSTATUS_BELONGSTOSET_R
@ GUBVARSTATUS_BELONGSTOSET_C2
@ GUBVARSTATUS_CAPACITYEXCEEDED
@ GUBVARSTATUS_UNINITIAL
static SCIP_RETCODE checkParallelObjective(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata)
static SCIP_RETCODE GUBconsAddVar(SCIP *scip, SCIP_GUBCONS *gubcons, int var)
static SCIP_RETCODE changePartitionFeasiblesetvars(SCIP *scip, SCIP_Longint *weights, int *varsC1, int *varsC2, int *nvarsC1, int *nvarsC2)
#define DEFAULT_DISAGGREGATION
static SCIP_RETCODE preprocessConstraintPairs(SCIP *scip, SCIP_CONS **conss, int firstchange, int chkind, int *ndelconss)
static SCIP_RETCODE GUBconsDelVar(SCIP *scip, SCIP_GUBCONS *gubcons, int var, int gubvarsidx)
#define DEFAULT_DETECTLOWERBOUND
static SCIP_RETCODE dualPresolving(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *ndelconss, SCIP_Bool *deleted)
#define EVENTTYPE_KNAPSACK
#define MAX_ZEROITEMS_SIZE
Constraint handler for knapsack constraints of the form , x binary and .
Constraint handler for linear constraints in their most general form, .
Constraint handler for logicor constraints (equivalent to set covering, but algorithms are suited fo...
Constraint handler for the set partitioning / packing / covering constraints .
#define NULL
Definition def.h:257
#define SCIP_MAXSTRLEN
Definition def.h:278
#define SCIP_Longint
Definition def.h:150
#define SCIP_MAXTREEDEPTH
Definition def.h:306
#define SCIP_INVALID
Definition def.h:187
#define SCIP_Bool
Definition def.h:100
#define MIN(x, y)
Definition def.h:233
#define SCIP_STRINGEQ(name, reference, retcode)
Definition def.h:454
#define SCIP_Real
Definition def.h:165
#define TRUE
Definition def.h:102
#define FALSE
Definition def.h:103
#define MAX(x, y)
Definition def.h:229
#define SCIP_LONGINT_FORMAT
Definition def.h:157
#define REALABS(x)
Definition def.h:191
#define SCIP_LONGINT_MAX
Definition def.h:151
#define SCIP_CALL(x)
Definition def.h:364
SCIP_RETCODE SCIPincludeLinconsUpgrade(SCIP *scip, SCIP_DECL_LINCONSUPGD((*linconsupgd)), int priority, const char *conshdlrname)
int SCIPgetNVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcreateRowKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcreateConsCardinality(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, int cardval, SCIP_VAR **indvars, SCIP_Real *weights, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPaddCoefKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
SCIP_RETCODE SCIPsolveKnapsackApproximately(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval)
SCIP_RETCODE SCIPcleanupConssKnapsack(SCIP *scip, SCIP_Bool onlychecked, SCIP_Bool *infeasible, int *ndelconss)
SCIP_RETCODE SCIPseparateKnapsackCuts(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_SOL *sol, SCIP_Bool usegubs, SCIP_Bool *cutoff, int *ncuts)
SCIP_RETCODE SCIPcreateConsSetpack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPcreateConsBasicKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
SCIP_RETCODE SCIPchgCapacityKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_Longint capacity)
SCIP_RETCODE SCIPseparateRelaxedKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, int nknapvars, SCIP_VAR **knapvars, SCIP_Real *knapvals, SCIP_Real valscale, SCIP_Real rhs, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
SCIP_RETCODE SCIPsolveKnapsackExactly(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval, SCIP_Bool *success)
#define SCIP_DECL_LINCONSUPGD(x)
SCIP_RETCODE SCIPcreateConsKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPcopyConsLinear(SCIP *scip, SCIP_CONS **cons, SCIP *sourcescip, const char *name, int nvars, SCIP_VAR **sourcevars, SCIP_Real *sourcecoefs, SCIP_Real lhs, SCIP_Real rhs, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode, SCIP_Bool global, SCIP_Bool *valid)
SCIP_Longint * SCIPgetWeightsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_Longint SCIPgetCapacityKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_VAR ** SCIPgetVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcreateConsLogicor(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_Real SCIPgetDualfarkasKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_ROW * SCIPgetRowKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPgetDualsolKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPincludeConshdlrKnapsack(SCIP *scip)
SCIP_Bool SCIPisConsCompressionEnabled(SCIP *scip)
Definition scip_copy.c:662
SCIP_RETCODE SCIPgetVarCopy(SCIP *sourcescip, SCIP *targetscip, SCIP_VAR *sourcevar, SCIP_VAR **targetvar, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global, SCIP_Bool *success)
Definition scip_copy.c:713
SCIP_Bool SCIPisTransformed(SCIP *scip)
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
SCIP_Bool SCIPisStopped(SCIP *scip)
SCIP_STAGE SCIPgetStage(SCIP *scip)
int SCIPgetNObjVars(SCIP *scip)
Definition scip_prob.c:2616
SCIP_RETCODE SCIPaddConsUpgrade(SCIP *scip, SCIP_CONS *oldcons, SCIP_CONS **newcons)
Definition scip_prob.c:3368
int SCIPgetNContVars(SCIP *scip)
Definition scip_prob.c:2569
int SCIPgetNVars(SCIP *scip)
Definition scip_prob.c:2246
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition scip_prob.c:3274
SCIP_CONS * SCIPfindOrigCons(SCIP *scip, const char *name)
Definition scip_prob.c:3476
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition scip_prob.c:3420
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition scip_prob.c:2201
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition misc.c:3095
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3304
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition misc.c:3061
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3466
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition misc.c:3179
SCIP_RETCODE SCIPhashmapSetImageInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition misc.c:3400
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition misc.c:2348
#define SCIPhashSix(a, b, c, d, e, f)
Definition pub_misc.h:580
SCIP_RETCODE SCIPhashtableCreate(SCIP_HASHTABLE **hashtable, BMS_BLKMEM *blkmem, int tablesize, SCIP_DECL_HASHGETKEY((*hashgetkey)), SCIP_DECL_HASHKEYEQ((*hashkeyeq)), SCIP_DECL_HASHKEYVAL((*hashkeyval)), void *userptr)
Definition misc.c:2298
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition misc.c:2596
SCIP_RETCODE SCIPhashtableRemove(SCIP_HASHTABLE *hashtable, void *element)
Definition misc.c:2665
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition misc.c:2535
SCIP_RETCODE SCIPupdateLocalLowerbound(SCIP *scip, SCIP_Real newbound)
Definition scip_prob.c:4289
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition scip_prob.c:4067
SCIP_Real SCIPgetLocalLowerbound(SCIP *scip)
Definition scip_prob.c:4178
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
#define SCIPdebugMsgPrint
#define SCIPdebugMsg
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition misc.c:9197
SCIP_RETCODE SCIPcalcIntegralScalar(SCIP_Real *vals, int nvals, SCIP_Real mindelta, SCIP_Real maxdelta, SCIP_Longint maxdnom, SCIP_Real maxscale, SCIP_Real *intscalar, SCIP_Bool *success)
Definition misc.c:9641
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition misc.c:11162
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:83
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:139
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:57
int SCIPgetNLPBranchCands(SCIP *scip)
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
SCIP_RETCODE SCIPaddConflictBinvar(SCIP *scip, SCIP_VAR *var)
SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
int SCIPconshdlrGetNCheckConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4802
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition cons.c:4350
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:372
SCIP_RETCODE SCIPsetConshdlrActive(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:670
SCIP_CONS ** SCIPconshdlrGetCheckConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4759
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition scip_cons.c:540
SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:492
SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
Definition scip_cons.c:235
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition scip_cons.c:281
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:323
SCIP_RETCODE SCIPincludeConshdlrBasic(SCIP *scip, SCIP_CONSHDLR **conshdlrptr, const char *name, const char *desc, int enfopriority, int chckpriority, int eagerfreq, SCIP_Bool needscons, SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition scip_cons.c:181
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:808
SCIP_Longint SCIPconshdlrGetNCutsFound(SCIP_CONSHDLR *conshdlr)
Definition cons.c:5046
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:831
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:785
SCIP_RETCODE SCIPsetConshdlrGetSignedPermsymGraph(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:924
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4320
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)),)
Definition scip_cons.c:347
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition scip_cons.c:940
SCIP_RETCODE SCIPsetConshdlrInit(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:396
SCIP_RETCODE SCIPsetConshdlrGetPermsymGraph(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:900
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:578
SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:444
SCIP_RETCODE SCIPsetConshdlrDeactive(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:693
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4340
int SCIPconshdlrGetNActiveConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4816
int SCIPconshdlrGetSepaFreq(SCIP_CONSHDLR *conshdlr)
Definition cons.c:5276
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:601
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:647
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:516
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:468
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4739
SCIP_RETCODE SCIPsetConshdlrDelvars(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:762
SCIP_RETCODE SCIPsetConshdlrExit(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:420
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:624
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:854
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition cons.c:8423
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition cons.c:8652
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition cons.c:8413
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition cons.c:8562
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition scip_cons.c:2536
int SCIPconsGetNUpgradeLocks(SCIP_CONS *cons)
Definition cons.c:8845
SCIP_RETCODE SCIPsetConsSeparated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool separate)
Definition scip_cons.c:1296
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition cons.c:8592
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition cons.c:8522
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition cons.c:8702
SCIP_RETCODE SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial)
Definition scip_cons.c:1271
SCIP_RETCODE SCIPsetConsEnforced(SCIP *scip, SCIP_CONS *cons, SCIP_Bool enforce)
Definition scip_cons.c:1321
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition cons.c:8582
SCIP_RETCODE SCIPunmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition scip_cons.c:2042
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition cons.c:8454
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition scip_cons.c:997
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition cons.c:8612
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition cons.c:8632
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition cons.c:8393
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition scip_cons.c:1812
SCIP_RETCODE SCIPmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition scip_cons.c:2014
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition cons.c:8642
SCIP_RETCODE SCIPupdateConsFlags(SCIP *scip, SCIP_CONS *cons0, SCIP_CONS *cons1)
Definition scip_cons.c:1524
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition cons.c:8672
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition scip_cons.c:1173
SCIP_RETCODE SCIPsetConsPropagated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool propagate)
Definition scip_cons.c:1371
SCIP_RETCODE SCIPsetConsChecked(SCIP *scip, SCIP_CONS *cons, SCIP_Bool check)
Definition scip_cons.c:1346
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition cons.c:8572
SCIP_RETCODE SCIPincConsAge(SCIP *scip, SCIP_CONS *cons)
Definition scip_cons.c:1784
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition cons.c:8662
SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition scip_cut.c:117
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition scip_cut.c:135
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition scip_cut.c:225
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition scip_event.c:111
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition event.c:1194
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition scip_event.c:367
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition scip_event.c:413
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition event.c:1217
#define SCIPfreeBuffer(scip, ptr)
Definition scip_mem.h:134
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition scip_mem.h:110
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition scip_mem.c:57
#define SCIPallocClearBlockMemoryArray(scip, ptr, num)
Definition scip_mem.h:97
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition scip_mem.h:126
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition scip_mem.c:139
#define SCIPallocBufferArray(scip, ptr, num)
Definition scip_mem.h:124
#define SCIPreallocBufferArray(scip, ptr, num)
Definition scip_mem.h:128
#define SCIPfreeBufferArray(scip, ptr)
Definition scip_mem.h:136
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition scip_mem.h:132
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition scip_mem.h:93
#define SCIPallocBuffer(scip, ptr)
Definition scip_mem.h:122
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition scip_mem.h:99
#define SCIPfreeBlockMemory(scip, ptr)
Definition scip_mem.h:108
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition scip_mem.h:111
#define SCIPallocBlockMemory(scip, ptr)
Definition scip_mem.h:89
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition scip_mem.h:105
SCIP_RETCODE SCIPdelNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition scip_nlp.c:424
SCIP_RETCODE SCIPaddNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition scip_nlp.c:396
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition scip_nlp.c:110
SCIP_RETCODE SCIPreleaseNlRow(SCIP *scip, SCIP_NLROW **nlrow)
Definition scip_nlp.c:1058
SCIP_Bool SCIPnlrowIsInNLP(SCIP_NLROW *nlrow)
Definition nlp.c:1953
SCIP_RETCODE SCIPcreateNlRow(SCIP *scip, SCIP_NLROW **nlrow, const char *name, SCIP_Real constant, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, SCIP_EXPR *expr, SCIP_Real lhs, SCIP_Real rhs, SCIP_EXPRCURV curvature)
Definition scip_nlp.c:954
SCIP_Bool SCIPinProbing(SCIP *scip)
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1581
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONS *cons, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition scip_lp.c:1398
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1604
SCIP_RETCODE SCIPcreateEmptyRowConshdlr(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition scip_lp.c:1367
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition scip_lp.c:1646
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition scip_lp.c:2176
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition scip_lp.c:1508
SCIP_RETCODE SCIPcreateEmptyRowSepa(SCIP *scip, SCIP_ROW **row, SCIP_SEPA *sepa, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition scip_lp.c:1429
SCIP_RETCODE SCIPcreateEmptyRowUnspec(SCIP *scip, SCIP_ROW **row, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition scip_lp.c:1458
SCIP_Real SCIProwGetDualfarkas(SCIP_ROW *row)
Definition lp.c:17719
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition lp.c:17917
SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
Definition lp.c:17706
const char * SCIPsepaGetName(SCIP_SEPA *sepa)
Definition sepa.c:746
SCIP_Longint SCIPsepaGetNCutsFound(SCIP_SEPA *sepa)
Definition sepa.c:913
SCIP_RETCODE SCIPgetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition scip_sol.c:1844
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition scip_sol.c:1763
void SCIPupdateSolLPConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition scip_sol.c:467
SCIP_RETCODE SCIPupdateCutoffbound(SCIP *scip, SCIP_Real cutoffbound)
int SCIPgetNSepaRounds(SCIP *scip)
SCIP_Real SCIPgetLowerbound(SCIP *scip)
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPcutoffbounddelta(SCIP *scip)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPepsilon(SCIP *scip)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition scip_tree.c:146
int SCIPgetDepth(SCIP *scip)
Definition scip_tree.c:672
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:6401
int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition var.c:24514
SCIP_Bool SCIPvarIsDeleted(SCIP_VAR *var)
Definition var.c:23566
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition scip_var.c:5210
SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
Definition var.c:23875
SCIP_VAR * SCIPvarGetNegatedVar(SCIP_VAR *var)
Definition var.c:23900
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition var.c:24536
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition var.c:23674
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition var.c:23510
SCIP_RETCODE SCIPaddClique(SCIP *scip, SCIP_VAR **vars, SCIP_Bool *values, int nvars, SCIP_Bool isequation, SCIP_Bool *infeasible, int *nbdchgs)
Definition scip_var.c:8882
SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
Definition scip_var.c:2119
int SCIPvarGetNImpls(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:24600
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition var.c:23418
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition var.c:4380
SCIP_RETCODE SCIPcalcNegatedCliquePartition(SCIP *scip, SCIP_VAR **vars, int nvars, int **probtoidxmap, int *probtoidxmapsize, int *cliquepartition, int *ncliques)
Definition scip_var.c:9410
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition var.c:24300
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition var.c:23462
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition var.c:23932
SCIP_VAR * SCIPvarGetProbvar(SCIP_VAR *var)
Definition var.c:17595
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:6651
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition scip_var.c:728
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition var.c:24174
SCIP_VAR ** SCIPvarGetImplVars(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:24617
int SCIPvarGetIndex(SCIP_VAR *var)
Definition var.c:23684
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition scip_var.c:5118
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition scip_var.c:5296
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition scip_var.c:2872
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition var.c:23694
const char * SCIPvarGetName(SCIP_VAR *var)
Definition var.c:23299
SCIP_RETCODE SCIPcalcCliquePartition(SCIP *scip, SCIP_VAR **vars, int nvars, int **probtoidxmap, int *probtoidxmapsize, int *cliquepartition, int *ncliques)
Definition scip_var.c:9330
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition scip_var.c:1887
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition var.c:24546
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition var.c:24556
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition var.c:23522
SCIP_Real * SCIPvarGetImplBounds(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:24646
SCIP_RETCODE SCIPflattenVarAggregationGraph(SCIP *scip, SCIP_VAR *var)
Definition scip_var.c:2332
SCIP_RETCODE SCIPgetNegatedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **negvar)
Definition scip_var.c:2166
SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
Definition var.c:23838
int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition var.c:23826
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:24674
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition var.c:24266
SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
Definition var.c:23475
int SCIPgetNCliques(SCIP *scip)
Definition scip_var.c:9512
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition var.c:24526
SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:24685
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition var.c:24152
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition scip_var.c:10318
SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition scip_var.c:2736
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition var.c:17319
SCIP_RETCODE SCIPvarGetProbvarBinary(SCIP_VAR **var, SCIP_Bool *negated)
Definition var.c:17687
SCIP_RETCODE SCIPinferBinvarCons(SCIP *scip, SCIP_VAR *var, SCIP_Bool fixedval, SCIP_CONS *infercons, int inferinfo, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:7412
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition var.c:24588
SCIP_RETCODE SCIPwriteVarName(SCIP *scip, FILE *file, SCIP_VAR *var, SCIP_Bool type)
Definition scip_var.c:361
SCIP_RETCODE SCIPgetBinvarRepresentative(SCIP *scip, SCIP_VAR *var, SCIP_VAR **repvar, SCIP_Bool *negated)
Definition scip_var.c:2236
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition var.c:24568
SCIP_Bool SCIPvarsHaveCommonClique(SCIP_VAR *var1, SCIP_Bool value1, SCIP_VAR *var2, SCIP_Bool value2, SCIP_Bool regardimplics)
Definition var.c:16852
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition var.c:24578
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition var.c:4322
SCIP_RETCODE SCIPgetNegatedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **negvars)
Definition scip_var.c:2199
SCIP_BOUNDTYPE * SCIPvarGetImplTypes(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:24632
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition scip_var.c:1853
SCIP_Bool SCIPallowStrongDualReds(SCIP *scip)
Definition scip_var.c:10984
SCIP_RETCODE SCIPvarsGetProbvarBinary(SCIP_VAR ***vars, SCIP_Bool **negatedarr, int nvars)
Definition var.c:17655
SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition var.c:23850
void SCIPselectWeightedDownRealLongRealInt(SCIP_Real *realarray1, SCIP_Longint *longarray, SCIP_Real *realarray3, int *intarray, SCIP_Real *weights, SCIP_Real capacity, int len, int *medianpos)
void SCIPsortDownLongPtr(SCIP_Longint *longarray, void **ptrarray, int len)
void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
void SCIPsortPtrPtrIntInt(void **ptrarray1, void **ptrarray2, int *intarray1, int *intarray2, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
void SCIPsortPtrPtrLongIntInt(void **ptrarray1, void **ptrarray2, SCIP_Longint *longarray, int *intarray1, int *intarray2, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
void SCIPsortDownPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
void SCIPsortDownLongPtrPtrIntInt(SCIP_Longint *longarray, void **ptrarray1, void **ptrarray2, int *intarray1, int *intarray2, int len)
void SCIPsortRealInt(SCIP_Real *realarray, int *intarray, int len)
void SCIPsortDownRealIntLong(SCIP_Real *realarray, int *intarray, SCIP_Longint *longarray, int len)
void SCIPsortPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
void SCIPsortDownRealInt(SCIP_Real *realarray, int *intarray, int len)
void SCIPsortDownLongPtrInt(SCIP_Longint *longarray, void **ptrarray, int *intarray, int len)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition misc.c:10827
SCIP_RETCODE SCIPskipSpace(char **s)
Definition misc.c:10816
SCIP_RETCODE SCIPgetSymActiveVariables(SCIP *scip, SYM_SYMTYPE symtype, SCIP_VAR ***vars, SCIP_Real **scalars, int *nvars, SCIP_Real *constant, SCIP_Bool transformed)
SCIP_RETCODE SCIPextendPermsymDetectionGraphLinear(SCIP *scip, SYM_GRAPH *graph, SCIP_VAR **vars, SCIP_Real *vals, int nvars, SCIP_CONS *cons, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool *success)
return SCIP_OKAY
int c
int depth
SCIP_Bool cutoff
SCIP_Real objval
static SCIP_SOL * sol
assert(minobj< SCIPgetCutoffbound(scip))
int nvars
SCIP_VAR * var
static SCIP_Bool propagate
static SCIP_VAR ** vars
SCIP_VAR ** SCIPcliqueGetVars(SCIP_CLIQUE *clique)
Definition implics.c:3384
int SCIPcliqueGetNVars(SCIP_CLIQUE *clique)
Definition implics.c:3374
SCIP_Bool * SCIPcliqueGetValues(SCIP_CLIQUE *clique)
Definition implics.c:3396
memory allocation routines
#define BMScopyMemoryArray(ptr, source, num)
Definition memory.h:134
#define BMSclearMemoryArray(ptr, num)
Definition memory.h:130
struct BMS_BlkMem BMS_BLKMEM
Definition memory.h:437
public methods for managing constraints
public methods for managing events
public methods for implications, variable bounds, and cliques
public methods for LP management
public methods for message output
#define SCIPerrorMessage
Definition pub_message.h:64
#define SCIPdebug(x)
Definition pub_message.h:93
#define SCIPdebugPrintCons(x, y, z)
#define SCIPdebugMessage
Definition pub_message.h:96
#define SCIPdebugPrintf
Definition pub_message.h:99
public data structures and miscellaneous methods
methods for selecting k-medians
methods for sorting joint arrays of various types
public methods for separators
public methods for problem variables
public methods for branching rule plugins and branching
public methods for conflict handler plugins and conflict analysis
public methods for constraint handler plugins and constraints
public methods for problem copies
public methods for cuts and aggregation rows
public methods for event handler plugins and event handlers
general public methods
public methods for the LP relaxation, rows and columns
public methods for memory management
public methods for message handling
public methods for nonlinear relaxation
public methods for numerical tolerances
public methods for SCIP parameter handling
public methods for global and local (sub)problems
public methods for the probing mode
public methods for solutions
public methods for querying solving statistics
public methods for the branch-and-bound tree
public methods for SCIP variables
static SCIP_RETCODE separate(SCIP *scip, SCIP_SEPA *sepa, SCIP_SOL *sol, SCIP_RESULT *result)
Main separation function.
GUBVARSTATUS * gubvarsstatus
GUBCONSSTATUS * gubconsstatus
SCIP_GUBCONS ** gubconss
structs for symmetry computations
methods for dealing with symmetry detection graphs
@ SCIP_CONFTYPE_PROPAGATION
#define SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(x)
Definition type_cons.h:956
#define SCIP_DECL_CONSGETPERMSYMGRAPH(x)
Definition type_cons.h:938
#define SCIP_DECL_CONSENFOLP(x)
Definition type_cons.h:363
#define SCIP_DECL_CONSINITPRE(x)
Definition type_cons.h:156
#define SCIP_DECL_CONSDELETE(x)
Definition type_cons.h:229
struct SCIP_Cons SCIP_CONS
Definition type_cons.h:63
#define SCIP_DECL_CONSEXIT(x)
Definition type_cons.h:136
#define SCIP_DECL_CONSGETVARS(x)
Definition type_cons.h:867
#define SCIP_DECL_CONSINITSOL(x)
Definition type_cons.h:201
#define SCIP_DECL_CONSPRINT(x)
Definition type_cons.h:769
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition type_cons.h:64
#define SCIP_DECL_CONSSEPALP(x)
Definition type_cons.h:288
struct SYM_Graph SYM_GRAPH
Definition type_cons.h:68
#define SCIP_DECL_CONSENFORELAX(x)
Definition type_cons.h:388
#define SCIP_DECL_CONSPROP(x)
Definition type_cons.h:506
#define SCIP_DECL_CONSGETNVARS(x)
Definition type_cons.h:885
#define SCIP_DECL_CONSRESPROP(x)
Definition type_cons.h:612
#define SCIP_DECL_CONSACTIVE(x)
Definition type_cons.h:691
#define SCIP_DECL_CONSENFOPS(x)
Definition type_cons.h:431
#define SCIP_DECL_CONSPARSE(x)
Definition type_cons.h:845
#define SCIP_DECL_CONSTRANS(x)
Definition type_cons.h:239
#define SCIP_DECL_CONSDEACTIVE(x)
Definition type_cons.h:706
#define SCIP_DECL_CONSPRESOL(x)
Definition type_cons.h:561
#define SCIP_DECL_CONSINITLP(x)
Definition type_cons.h:259
#define SCIP_DECL_CONSEXITPRE(x)
Definition type_cons.h:180
#define SCIP_DECL_CONSLOCK(x)
Definition type_cons.h:676
struct SCIP_Conshdlr SCIP_CONSHDLR
Definition type_cons.h:62
#define SCIP_DECL_CONSCOPY(x)
Definition type_cons.h:810
#define SCIP_DECL_CONSINIT(x)
Definition type_cons.h:126
struct SCIP_ConsData SCIP_CONSDATA
Definition type_cons.h:65
#define SCIP_DECL_CONSCHECK(x)
Definition type_cons.h:474
#define SCIP_DECL_CONSHDLRCOPY(x)
Definition type_cons.h:108
#define SCIP_DECL_CONSEXITSOL(x)
Definition type_cons.h:216
#define SCIP_DECL_CONSFREE(x)
Definition type_cons.h:116
#define SCIP_DECL_CONSSEPASOL(x)
Definition type_cons.h:320
#define SCIP_DECL_CONSDELVARS(x)
Definition type_cons.h:753
struct SCIP_Eventhdlr SCIP_EVENTHDLR
Definition type_event.h:159
struct SCIP_EventData SCIP_EVENTDATA
Definition type_event.h:179
#define SCIP_EVENTTYPE_UBTIGHTENED
Definition type_event.h:79
#define SCIP_EVENTTYPE_VARFIXED
Definition type_event.h:72
#define SCIP_EVENTTYPE_VARDELETED
Definition type_event.h:71
struct SCIP_EventhdlrData SCIP_EVENTHDLRDATA
Definition type_event.h:160
#define SCIP_DECL_EVENTEXEC(x)
Definition type_event.h:259
#define SCIP_EVENTTYPE_LBRELAXED
Definition type_event.h:78
#define SCIP_EVENTTYPE_FORMAT
Definition type_event.h:157
#define SCIP_EVENTTYPE_IMPLADDED
Definition type_event.h:85
#define SCIP_EVENTTYPE_LBTIGHTENED
Definition type_event.h:77
@ SCIP_EXPRCURV_LINEAR
Definition type_expr.h:65
struct SCIP_Clique SCIP_CLIQUE
struct SCIP_Row SCIP_ROW
Definition type_lp.h:105
@ SCIP_BOUNDTYPE_UPPER
Definition type_lp.h:58
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition type_lp.h:60
struct SCIP_HashMap SCIP_HASHMAP
Definition type_misc.h:106
#define SCIP_DECL_SORTPTRCOMP(x)
Definition type_misc.h:189
#define SCIP_DECL_HASHKEYEQ(x)
Definition type_misc.h:195
#define SCIP_DECL_HASHGETKEY(x)
Definition type_misc.h:192
#define SCIP_DECL_HASHKEYVAL(x)
Definition type_misc.h:198
struct SCIP_HashTable SCIP_HASHTABLE
Definition type_misc.h:88
struct SCIP_NlRow SCIP_NLROW
Definition type_nlp.h:41
@ SCIP_DIDNOTRUN
Definition type_result.h:42
@ SCIP_CUTOFF
Definition type_result.h:48
@ SCIP_FEASIBLE
Definition type_result.h:45
@ SCIP_REDUCEDDOM
Definition type_result.h:51
@ SCIP_DIDNOTFIND
Definition type_result.h:44
@ SCIP_SEPARATED
Definition type_result.h:49
@ SCIP_SUCCESS
Definition type_result.h:58
@ SCIP_INFEASIBLE
Definition type_result.h:46
enum SCIP_Result SCIP_RESULT
Definition type_result.h:61
@ SCIP_INVALIDDATA
@ SCIP_PLUGINNOTFOUND
@ SCIP_NOMEMORY
@ SCIP_INVALIDCALL
@ SCIP_ERROR
enum SCIP_Retcode SCIP_RETCODE
struct Scip SCIP
Definition type_scip.h:39
struct SCIP_Sepa SCIP_SEPA
Definition type_sepa.h:51
@ SCIP_STAGE_PROBLEM
Definition type_set.h:45
@ SCIP_STAGE_INITSOLVE
Definition type_set.h:52
@ SCIP_STAGE_SOLVING
Definition type_set.h:53
@ SCIP_STAGE_TRANSFORMING
Definition type_set.h:46
struct SCIP_Sol SCIP_SOL
Definition type_sol.h:57
enum SYM_Symtype SYM_SYMTYPE
@ SYM_SYMTYPE_SIGNPERM
@ SYM_SYMTYPE_PERM
#define SCIP_PRESOLTIMING_MEDIUM
Definition type_timing.h:53
unsigned int SCIP_PRESOLTIMING
Definition type_timing.h:61
#define SCIP_PRESOLTIMING_FAST
Definition type_timing.h:52
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition type_timing.h:54
struct SCIP_Var SCIP_VAR
Definition type_var.h:166
@ SCIP_VARSTATUS_FIXED
Definition type_var.h:54
@ SCIP_VARSTATUS_MULTAGGR
Definition type_var.h:56
@ SCIP_VARSTATUS_NEGATED
Definition type_var.h:57
@ SCIP_VARSTATUS_AGGREGATED
Definition type_var.h:55
@ SCIP_LOCKTYPE_MODEL
Definition type_var.h:141