SCIP Doxygen Documentation
Loading...
Searching...
No Matches
prop_genvbounds.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 prop_genvbounds.c
26 * @ingroup DEFPLUGINS_PROP
27 * @brief generalized variable bounds propagator
28 * @author Stefan Weltge
29 * @author Ambros Gleixner
30 * @author Benjamin Mueller
31 */
32
33/**@todo should we only discard events catched from nodes that are not the current node's ancestors? */
34/**@todo improve computation of minactivity */
35/**@todo for multaggr vars on left-hand side, create a linear constraint, probably in exitpre */
36
37/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
38
40#include "scip/cons_linear.h"
41#include "scip/debug.h"
43#include "scip/pub_event.h"
44#include "scip/pub_message.h"
45#include "scip/pub_misc.h"
46#include "scip/pub_prop.h"
47#include "scip/pub_tree.h"
48#include "scip/pub_var.h"
49#include "scip/scip_conflict.h"
50#include "scip/scip_cons.h"
52#include "scip/scip_event.h"
53#include "scip/scip_general.h"
54#include "scip/scip_mem.h"
55#include "scip/scip_message.h"
56#include "scip/scip_numerics.h"
57#include "scip/scip_param.h"
58#include "scip/scip_prob.h"
59#include "scip/scip_probing.h"
60#include "scip/scip_prop.h"
61#include "scip/scip_sol.h"
62#include "scip/scip_solve.h"
64#include "scip/scip_tree.h"
65#include "scip/scip_var.h"
66
67
68#define PROP_NAME "genvbounds"
69#define PROP_DESC "generalized variable bounds propagator"
70#define PROP_TIMING SCIP_PROPTIMING_ALWAYS
71#define PROP_PRIORITY 3000000 /**< propagator priority */
72#define PROP_FREQ 1 /**< propagator frequency */
73#define PROP_DELAY FALSE /**< should propagation method be delayed, if other propagators
74 * found reductions? */
75#define PROP_PRESOL_PRIORITY -2000000 /**< priority of the presolving method (>= 0: before, < 0: after
76 * constraint handlers); combined with presolvers */
77#define PROP_PRESOLTIMING SCIP_PRESOLTIMING_FAST /* timing of the presolving method (fast, medium, or exhaustive) */
78#define PROP_PRESOL_MAXROUNDS -1 /**< maximal number of presolving rounds the presolver participates
79 * in (-1: no limit) */
80#define DEFAULT_GLOBAL_PROPAGATION TRUE /**< apply global propagation? */
81#define DEFAULT_PROPAGATE_IN_ROOT_NODE TRUE /**< apply genvbounds in root node if no new incumbent was found? */
82#define DEFAULT_SORT TRUE /**< sort genvbounds and wait for bound change events? (otherwise all
83 * genvbounds are applied in each node) */
84#define DEFAULT_PROPASCONSS FALSE /**< should genvbounds be transformed to (linear) constraints? */
85
86#define EVENTHDLR_NAME "genvbounds"
87#define EVENTHDLR_DESC "event handler for generalized variable bounds propagator"
88
89
90/*
91 * Data structures
92 */
93
94/** GenVBound data */
96{
97 SCIP_VAR** vars; /**< pointers to variables x_j occurring in this generalized variable
98 * bound */
99 SCIP_VAR* var; /**< pointer to variable x_i */
100 SCIP_Real* coefs; /**< coefficients a_j of the variables listed in vars */
101 SCIP_Real constant; /**< constant term in generalized variable bound */
102 SCIP_Real cutoffcoef; /**< cutoff bound's coefficient */
103 int coefssize; /**< size of coefs array */
104 int index; /**< index of this genvbound in genvboundstore array */
105 int ncoefs; /**< number of nonzero coefficients a_j */
106 SCIP_BOUNDTYPE boundtype; /**< type of bound provided by the genvbound, SCIP_BOUNDTYPE_LOWER/UPPER
107 * if +/- x_i on left-hand side */
108 SCIP_Bool relaxonly; /**< contains a relaxation-only variable */
109};
110typedef struct GenVBound GENVBOUND;
111
112/** starting indices data structure */
113struct SCIP_EventData
114{
115 SCIP_PROP* prop; /**< pointer to genvbounds propagator */
116 SCIP_VAR* var; /**< variable */
117 int* startindices; /**< array to store the first indices of genvbounds in components that are
118 * impacted by a change of this bound */
119 int* startcomponents; /**< array to store the components corresponding to startindices array */
120 int nstarts; /**< number of indices stored in startindices array */
121 int startindicessize; /**< size of the startindices and startcomponents arrays */
122};
123
124/** propagator data */
125struct SCIP_PropData
126{
127 GENVBOUND** genvboundstore; /**< array to store genvbounds; fast access is provided by hashmaps
128 * lbgenvbounds and ubgenvbounds */
129 SCIP_EVENTDATA** lbevents; /**< array of lower bound event data */
130 SCIP_EVENTDATA** ubevents; /**< array of upper bound event data */
131 SCIP_EVENTHDLR* eventhdlr; /**< genvbounds propagator event handler */
132 SCIP_HASHMAP* lbgenvbounds; /**< hashmap to provide fast access to lower bound genvbounds in
133 * genvboundstore array */
134 SCIP_HASHMAP* ubgenvbounds; /**< hashmap to provide fast access to upper bound genvbounds in
135 * genvboundstore array */
136 SCIP_HASHMAP* lbeventsmap; /**< hashmap to provide fast access to lbevents array */
137 SCIP_HASHMAP* ubeventsmap; /**< hashmap to provide fast access to ubevents array */
138 SCIP_HASHMAP* startmap; /**< hashmap to provide fast access to startindices array */
139 SCIP_PROP* prop; /**< pointer to genvbounds propagator */
140 SCIP_Longint lastnodenumber; /**< last node number where events for starting indices were caught */
141 SCIP_VAR* cutoffboundvar; /**< artificial variable representing primal cutoff bound */
142 int* componentsstart; /**< stores the components starting indices in genvboundstore array; the
143 * entry componentsstart[ncomponents] is equal to ngenvbounds, which
144 * makes it easier to iterate over all components */
145 int componentsstartsize;/**< size of componentsstart array */
146 int* startindices; /**< storing indices of components where local propagation should start */
147 int* startcomponents; /**< components corresponding to indices stored in startindices array */
148 int startindicessize; /**< size of startindices and startcomponents arrays */
149 int* gstartindices; /**< storing indices of components where global propagation, i.e.,
150 * propagation of an improved primal bound, should start */
151 int* gstartcomponents; /**< components corresponding to indices stored in gstartindices array */
152 int gstartindicessize; /**< size of gstartindices and gstartcomponents arrays */
153 SCIP_Real lastcutoff; /**< cutoff bound's value last time genvbounds propagator was called */
154 int genvboundstoresize; /**< size of genvboundstore array */
155 int ngenvbounds; /**< number of genvbounds stored in genvboundstore array */
156 int ncomponents; /**< number of components in genvboundstore array */
157 int nindices; /**< number of indices stored in startindices array */
158 int ngindices; /**< number of indices stored in gstartindices array */
159 int nlbevents; /**< number of data entries in lbevents array */
160 int nubevents; /**< number of data entries in ubevents array */
161 SCIP_Bool issorted; /**< stores wether array genvboundstore is topologically sorted */
162 SCIP_Bool global; /**< apply global propagation? */
163 SCIP_Bool propinrootnode; /**< apply genvbounds in root node if no new incumbent was found? */
164 SCIP_Bool sort; /**< sort genvbounds and wait for bound change events? (otherwise all
165 * genvbounds are applied in each node) */
166 SCIP_Bool propasconss; /**< should genvbounds be transformed to (linear) constraints? */
167 SCIP_PROPTIMING inittiming; /**< initial propagator timing */
168};
169
170
171/*
172 * Local methods
173 */
174
175/** returns correct cutoff bound value */
176static
178 SCIP* scip /**< SCIP data structure */
179 )
180{
181 assert(scip != NULL);
182
183 SCIPdebugMsg(scip, "cutoff = %.9g (%.9g + %.9g * %.9g)\n",
186
187 /* the cutoff bound is valid w.r.t. the current objective function in the transformed problem; during presolving,
188 * however, the objective function can change (e.g., when a variable is fixed, its contribution in the objective is
189 * subtracted from the cutoff bound and added to the objective offset); we solve this by transforming the
190 * contribution of the cutoff bound in the generalized variable bound to the original problem as described in
191 * function SCIPgenVBoundAdd()
192 */
194}
195
196/** returns corresponding genvbound in genvboundstore if there is one, NULL otherwise */
197static
199 SCIP* scip, /**< SCIP data structure */
200 SCIP_PROPDATA* propdata, /**< data of the genvbounds propagator */
201 SCIP_VAR* var, /**< bounds variable */
202 SCIP_BOUNDTYPE boundtype /**< bounds type */
203 )
204{
205 SCIP_HASHMAP* hashmap;
206
207 assert(scip != NULL);
208 assert(propdata != NULL);
209 assert(var != NULL);
210
211 hashmap = boundtype == SCIP_BOUNDTYPE_LOWER ? propdata->lbgenvbounds : propdata->ubgenvbounds;
212
213 return (GENVBOUND*) SCIPhashmapGetImage(hashmap, var);
214}
215
216#ifdef SCIP_DEBUG
217/** prints a genvbound as debug message */
218static
219void printGenVBound(
220 SCIP* scip, /**< SCIP data structure */
221 GENVBOUND* genvbound /**< genvbound to be printed */
222 )
223{
224 SCIP_Bool first;
225 int i;
226
227 assert(genvbound != NULL);
228
229 if( genvbound->boundtype == SCIP_BOUNDTYPE_UPPER )
230 {
231 SCIPdebugMsgPrint(scip, "- ");
232 }
233
234 SCIPdebugMsgPrint(scip, "<%s> >= ", SCIPvarGetName(genvbound->var));
235
236 first = TRUE;
237 for( i = 0; i < genvbound->ncoefs; i++ )
238 {
239 if( !first )
240 {
241 SCIPdebugMsgPrint(scip, " + ");
242 }
243
244 SCIPdebugMsgPrint(scip, "%g * <%s>", genvbound->coefs[i], SCIPvarGetName(genvbound->vars[i]));
245
246 first = FALSE;
247 }
248
249 if( !SCIPisZero(scip, genvbound->cutoffcoef) )
250 {
251 SCIPdebugMsgPrint(scip, " + %g * cutoff_bound", genvbound->cutoffcoef);
252 }
253
254 if( !SCIPisZero(scip, genvbound->constant) )
255 {
256 SCIPdebugMsgPrint(scip, " + %g", genvbound->constant);
257 }
258
259 SCIPdebugMsgPrint(scip, "\n");
260}
261#endif
262
263/** calculates the minactivity of a linear combination of variables stored in an array */
264static
266 SCIP* scip, /**< SCIP data structure */
267 SCIP_VAR** vars, /**< array of variables */
268 SCIP_Real* coefs, /**< array of coefficients */
269 int nvars, /**< number of variables */
270 SCIP_Bool global /**< use global variable bounds? */
271 )
272{
273 SCIP_Real minval;
274 int i;
275
276 assert(scip != NULL);
277 assert(vars != NULL);
278 assert(coefs != NULL);
279 assert(nvars >= 0);
280
281 minval = 0.0;
282
283 for( i = 0; i < nvars; i++ )
284 {
286
287 /* get global or local bound */
288 if( global )
289 bound = coefs[i] > 0.0 ? SCIPvarGetLbGlobal(vars[i]) : SCIPvarGetUbGlobal(vars[i]);
290 else
291 bound = coefs[i] > 0.0 ? SCIPvarGetLbLocal(vars[i]) : SCIPvarGetUbLocal(vars[i]);
292
293 /* with infinite bounds we cannot compute a valid minactivity and return minus infinity */
295 return -SCIPinfinity(scip);
296
297 /* add contribution to minactivity */
298 minval += coefs[i] * bound;
299 }
300
301 return minval;
302}
303
304/** calculates the minactivity of a linear combination of variables stored in the current conflict set */
305static
307 SCIP* scip, /**< SCIP data structure */
308 SCIP_VAR** vars, /**< array of variables */
309 SCIP_Real* coefs, /**< array of coefficients */
310 int nvars, /**< number of variables */
311 SCIP_BDCHGIDX* bdchgidx /**< bound change at which minactivity should be computed; if NULL use local bounds */
312 )
313{
314 SCIP_Real minval;
315 int i;
316
317 assert(scip != NULL);
318 assert(vars != NULL);
319 assert(coefs != NULL);
320 assert(nvars >= 0);
321
322 minval = 0.0;
323
324 for( i = 0; i < nvars; i++ )
325 {
327
328 if( coefs[i] > 0.0 )
329 {
330 /* get bound at current bound change */
331 bound = SCIPgetVarLbAtIndex(scip, vars[i], bdchgidx, TRUE);
332
333 /* if bdchgidx is NULL, assert that we use local bounds */
334 assert(bdchgidx != NULL || SCIPisEQ(scip, bound, SCIPvarGetLbLocal(vars[i])));
335
336 /* if bdchgidx is not NULL, use the possibly tighter bound already in the current conflict set */
337 if( bdchgidx != NULL && SCIPgetConflictVarLb(scip, vars[i]) > bound )
339 }
340 else
341 {
342 /* get bound at current bound change */
343 bound = SCIPgetVarUbAtIndex(scip, vars[i], bdchgidx, TRUE);
344
345 /* if bdchgidx is NULL, assert that we use local bounds */
346 assert(bdchgidx != NULL || SCIPisEQ(scip, bound, SCIPvarGetUbLocal(vars[i])));
347
348 /* if bdchgidx is not NULL, use the possibly tighter bound already in the current conflict set */
349 if( bdchgidx != NULL && SCIPgetConflictVarUb(scip, vars[i]) < bound )
351 }
352
353 /* with infinite bounds we cannot compute a valid minactivity and return minus infinity */
355 return -SCIPinfinity(scip);
356
357 /* add contribution to minactivity */
358 minval += coefs[i] * bound;
359 }
360
361 return minval;
362}
363
364/** returns a valid bound given by a generalized variable bound */
365static
367 SCIP* scip, /**< SCIP data structure */
368 GENVBOUND* genvbound, /**< generalized variable bound */
369 SCIP_Bool global /**< use global variable bounds? */
370 )
371{
372 SCIP_Real boundval;
373
374 assert(scip != NULL);
375 assert(genvbound != NULL);
376
377 boundval = getGenVBoundsMinActivity(scip, genvbound->vars, genvbound->coefs, genvbound->ncoefs, global);
378
379 if( SCIPisInfinity(scip, -boundval) )
380 return (genvbound->boundtype == SCIP_BOUNDTYPE_LOWER) ? -SCIPinfinity(scip) : SCIPinfinity(scip);
381
382 if( genvbound->cutoffcoef != 0.0 )
383 boundval += genvbound->cutoffcoef * getCutoffboundGenVBound(scip);
384
385 boundval += genvbound->constant;
386
387 if( genvbound->boundtype == SCIP_BOUNDTYPE_UPPER )
388 boundval *= -1.0;
389
390 return boundval;
391}
392
393#ifdef WITH_DEBUG_SOLUTION
394/** checks whether a generalized variable bound violates the debug solution */
395static
396SCIP_RETCODE checkDebugSolutionGenVBound(
397 SCIP* scip, /**< SCIP data structure */
398 GENVBOUND* genvbound /**< generalized variable bound */
399 )
400{
401 SCIP_SOL* debugsol;
402 SCIP_Real activity;
403 SCIP_Real solval;
404 int i;
405
406 assert(scip != NULL);
407 assert(genvbound != NULL);
408
409 if( !SCIPdebugIsMainscip(scip) )
410 return SCIP_OKAY;
411
412 /* the genvbound must be valid for all cutoff bounds greater equal the objective value of the debug solution */
413 SCIP_CALL( SCIPdebugGetSol(scip, &debugsol) );
414
415 /* check whether a debug solution is available */
416 if( debugsol == NULL )
417 return SCIP_OKAY;
418
419 activity = 0.0;
420 for( i = 0; i < genvbound->ncoefs; i++ )
421 {
422 SCIP_CALL( SCIPdebugGetSolVal(scip, genvbound->vars[i], &solval) );
423 if( solval != SCIP_UNKNOWN || solval != SCIP_INVALID )
424 activity += genvbound->coefs[i] * solval;
425 else
426 printf("***** debug: ignoring variable with %s value in debug solution\n",
427 solval == SCIP_UNKNOWN ? "unknown" : "invalid");
428 }
429
430 activity += genvbound->cutoffcoef *
432 activity += genvbound->constant;
433
434 SCIP_CALL( SCIPdebugGetSolVal(scip, genvbound->var, &solval) );
435 if( solval != SCIP_UNKNOWN || solval != SCIP_INVALID )
436 {
437 if( genvbound->boundtype == SCIP_BOUNDTYPE_LOWER )
438 {
439 SCIP_CALL( SCIPdebugCheckLbGlobal(scip, genvbound->var, activity) );
440 }
441 else if( genvbound->boundtype == SCIP_BOUNDTYPE_UPPER )
442 {
443 SCIP_CALL( SCIPdebugCheckUbGlobal(scip, genvbound->var, -activity) );
444 }
445 }
446
447 return SCIP_OKAY;
448}
449#endif
450
451/** allocate local and global startindices, startcomponents and startmap */
452static
454 SCIP* scip, /**< SCIP data structure */
455 SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
456 )
457{
458 assert(scip != NULL);
459 assert(propdata != NULL);
460
461 assert(propdata->startcomponents == NULL);
462 assert(propdata->startindices == NULL);
463 assert(propdata->startmap == NULL);
464 assert(propdata->nindices == -1);
465
466 assert(propdata->gstartindices == NULL);
467 assert(propdata->gstartcomponents == NULL);
468 assert(propdata->ngindices == -1);
469
470 assert(propdata->ngenvbounds >= 1);
471 assert(propdata->ncomponents >= 1);
472
473 SCIPdebugMsg(scip, "create starting data\n");
474
475 /* allocate memory for arrays */
476 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(propdata->startindices), propdata->ncomponents) );
477 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(propdata->startcomponents), propdata->ncomponents) );
478 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(propdata->gstartindices), propdata->ncomponents) );
479 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(propdata->gstartcomponents), propdata->ncomponents) );
480 propdata->startindicessize = propdata->ncomponents;
481 propdata->gstartindicessize = propdata->ncomponents;
482
483 /* create hashmap */
484 SCIP_CALL( SCIPhashmapCreate(&(propdata->startmap), SCIPblkmem(scip), propdata->ncomponents) );
485
486 propdata->nindices = 0;
487 propdata->ngindices = 0;
488
489 return SCIP_OKAY;
490}
491
492/** free local and global startindices, startcomponents and startmap */
493static
495 SCIP* scip, /**< SCIP data structure */
496 SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
497 )
498{
499 assert(scip != NULL);
500 assert(propdata != NULL);
501
502 SCIPdebugMsg(scip, "free starting data\n");
503
504 if( propdata->startcomponents != NULL )
505 {
506 assert(propdata->startindices != NULL);
507 assert(propdata->startmap != NULL);
508 assert(propdata->nindices >= 0);
509
510 SCIPfreeBlockMemoryArray(scip, &(propdata->startindices), propdata->startindicessize);
511 SCIPfreeBlockMemoryArray(scip, &(propdata->startcomponents), propdata->startindicessize);
512 propdata->startindicessize = 0;
513 SCIPhashmapFree(&(propdata->startmap));
514 propdata->nindices = -1;
515
516 assert(propdata->gstartindices != NULL);
517 assert(propdata->gstartcomponents != NULL);
518 assert(propdata->ngindices >= 0);
519
520 SCIPfreeBlockMemoryArray(scip, &(propdata->gstartindices), propdata->gstartindicessize);
521 SCIPfreeBlockMemoryArray(scip, &(propdata->gstartcomponents), propdata->gstartindicessize);
522 propdata->gstartindicessize = 0;
523 propdata->ngindices = -1;
524 }
525
526 assert(propdata->startcomponents == NULL);
527 assert(propdata->startindices == NULL);
528 assert(propdata->startmap == NULL);
529 assert(propdata->nindices == -1);
530
531 assert(propdata->gstartindices == NULL);
532 assert(propdata->gstartcomponents == NULL);
533 assert(propdata->ngindices == -1);
534
535 return SCIP_OKAY;
536}
537
538static
540 SCIP* scip, /**< SCIP data structure */
541 SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
542 )
543{
544 int i;
545
546 assert(scip != NULL);
547 assert(propdata != NULL);
548
549 assert(propdata->gstartindices != NULL);
550 assert(propdata->gstartcomponents != NULL);
551 assert(propdata->ngindices == 0);
552
553 SCIPdebugMsg(scip, "fill global starting data\n");
554
555 for( i = 0; i < propdata->ncomponents; i++ )
556 {
557 int j;
558
559 for( j = propdata->componentsstart[i]; j < propdata->componentsstart[i+1]; j++ ) /*lint !e679*/
560 {
561 assert(j < propdata->ngenvbounds);
562
563 if( !SCIPisZero(scip, propdata->genvboundstore[j]->cutoffcoef) )
564 {
565 assert(SCIPisNegative(scip, propdata->genvboundstore[j]->cutoffcoef));
566
567 propdata->gstartcomponents[propdata->ngindices] = i;
568 propdata->gstartindices[propdata->ngindices] = j;
569
570 /* go to next component */
571 propdata->ngindices++;
572 break;
573 }
574 }
575 }
576
577 /* resize arrays */
578 if( propdata->gstartindicessize != propdata->ngindices )
579 {
580 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(propdata->gstartindices), propdata->gstartindicessize, \
581 propdata->ngindices) );
582 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(propdata->gstartcomponents), propdata->gstartindicessize, \
583 propdata->ngindices) );
584 propdata->gstartindicessize = propdata->ngindices;
585 }
586
587 return SCIP_OKAY;
588}
589
590
591/** resets local starting data */
592static
594 SCIP* scip, /**< SCIP data structure */
595 SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
596 )
597{
598 assert(scip != NULL);
599 assert(propdata != NULL);
600 assert(propdata->startcomponents != NULL);
601 assert(propdata->startindices != NULL);
602 assert(propdata->startmap != NULL);
603 assert(propdata->nindices >= 0);
604
605 SCIP_CALL( SCIPhashmapRemoveAll(propdata->startmap) );
606 propdata->nindices = 0;
607
608 return SCIP_OKAY;
609}
610
611/** frees sorted components data */
612static
614 SCIP* scip, /**< SCIP data structure */
615 SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
616 )
617{
618 assert(scip != NULL);
619 assert(propdata != NULL);
620
621 SCIPdebugMsg(scip, "free components data\n");
622
623 if( propdata->componentsstart != NULL )
624 {
625 assert(propdata->ncomponents > 0);
626
627 SCIPfreeBlockMemoryArray(scip, &(propdata->componentsstart), propdata->componentsstartsize);
628 propdata->componentsstartsize = 0;
629 propdata->ncomponents = -1;
630 }
631
632 assert(propdata->componentsstart == NULL);
633 assert(propdata->ncomponents == -1);
634
635 return SCIP_OKAY;
636}
637
638/** frees memory allocated for a generalized variable bound */
639static
641 SCIP* scip,
642 GENVBOUND* genvbound
643 )
644{
645 int i;
646
647 assert(scip != NULL);
648 assert(genvbound != NULL);
649 assert(genvbound->coefs != NULL);
650 assert(genvbound->vars != NULL);
651 assert(genvbound->var != NULL);
652
653 /* release variables */
654 for( i = 0; i < genvbound->ncoefs; ++i )
655 {
656 assert(genvbound->vars[i] != NULL);
657 SCIP_CALL( SCIPreleaseVar(scip, &(genvbound->vars[i])) );
658 }
659 SCIP_CALL( SCIPreleaseVar(scip, &genvbound->var) );
660
661 /* free memory */
662 SCIPfreeBlockMemoryArray(scip, &(genvbound->coefs), genvbound->coefssize);
663 SCIPfreeBlockMemoryArray(scip, &(genvbound->vars), genvbound->coefssize);
664 SCIPfreeBlockMemory(scip, &genvbound);
665
666 return SCIP_OKAY;
667}
668
669/** helper function to release all genvbounds */
670static
672 SCIP* scip,
673 SCIP_PROP* prop,
674 SCIP_PROPDATA* propdata
675 )
676{
677 int i;
678
679 assert(scip != NULL);
680 assert(prop != NULL);
681 assert(propdata != NULL);
682
683 if( propdata->genvboundstore != NULL )
684 {
685 /* disable genvbounds propagator */
686 if( propdata->ngenvbounds >= 1 )
688
689 /* free genvbounds */
690 for( i = propdata->ngenvbounds - 1; i >= 0; i-- )
691 {
692 SCIP_CALL( freeGenVBound(scip, propdata->genvboundstore[i]) );
693 }
694
695 /* free genvboundstore hashmaps */
696 SCIPhashmapFree(&(propdata->lbgenvbounds));
697 SCIPhashmapFree(&(propdata->ubgenvbounds));
698
699 /* free genvboundstore array */
700 SCIPfreeBlockMemoryArray(scip, &(propdata->genvboundstore), propdata->genvboundstoresize);
701
702 /* set the number of genvbounds to zero */
703 propdata->ngenvbounds = 0;
704
705 /* free componentsstart array */
706 SCIP_CALL( freeComponentsData(scip, propdata) );
707
708 /* free starting indices data */
709 SCIP_CALL( freeStartingData(scip, propdata) );
710
711 /* release the cutoffboundvar and undo the locks */
712 if( propdata->cutoffboundvar != NULL )
713 {
714 SCIP_CALL( SCIPaddVarLocksType(scip, propdata->cutoffboundvar, SCIP_LOCKTYPE_MODEL, -1, -1) );
715 SCIP_CALL( SCIPreleaseVar(scip, &(propdata->cutoffboundvar)) );
716 propdata->cutoffboundvar = NULL;
717 SCIPdebugMsg(scip, "release cutoffboundvar!\n");
718 }
719 }
720
721 return SCIP_OKAY;
722}
723
724/** helper function to release relax-only genvbounds */
725static
727 SCIP* scip,
728 SCIP_PROP* prop,
729 SCIP_PROPDATA* propdata
730 )
731{
732 SCIP_Bool freedgenvbound;
733 int i;
734
735 assert(scip != NULL);
736 assert(propdata != NULL);
737
738 if( propdata->genvboundstore == NULL )
739 return SCIP_OKAY;
740
741 /* free genvbounds */
742 freedgenvbound = FALSE;
743 for( i = 0 ; i < propdata->ngenvbounds; )
744 {
745 if( propdata->genvboundstore[i]->relaxonly )
746 {
747 SCIP_CALL( SCIPhashmapRemove(propdata->genvboundstore[i]->boundtype == SCIP_BOUNDTYPE_LOWER ? propdata->lbgenvbounds : propdata->ubgenvbounds,
748 propdata->genvboundstore[i]->var) );
749
750 SCIP_CALL( freeGenVBound(scip, propdata->genvboundstore[i]) );
751 if( i != propdata->ngenvbounds-1 )
752 {
753 propdata->genvboundstore[i] = propdata->genvboundstore[propdata->ngenvbounds-1];
754 propdata->genvboundstore[i]->index = i;
755 }
756 --propdata->ngenvbounds;
757
758 propdata->issorted = FALSE;
759 freedgenvbound = TRUE;
760 }
761 else
762 ++i;
763 }
764
765 if( freedgenvbound )
766 {
767 /* free componentsstart array */
768 SCIP_CALL( freeComponentsData(scip, propdata) );
769
770 /* free starting indices data */
771 SCIP_CALL( freeStartingData(scip, propdata) );
772 }
773
774 /* disable genvbounds propagator */
775 if( propdata->ngenvbounds == 0 )
777
778 return SCIP_OKAY;
779}
780
781/** resolves propagation of lower bound on +/- left-hand side variable of a generalized variable bound */
782static
784 SCIP* scip, /**< SCIP data structure */
785 GENVBOUND* genvbound, /**< genvbound data structure */
786 SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
787 SCIP_Real* boundval, /**< pointer to lower bound value on +/- left-hand side variable */
788 SCIP_Bool* success /**< was the explanation succesful? */
789 )
790{
791 SCIP_VAR* lhsvar;
792 SCIP_VAR** vars;
793 SCIP_Real minactivity;
794 SCIP_Real tmpboundval;
795 SCIP_Real slack;
796 int nvars;
797 int i;
798
799 assert(scip != NULL);
800 assert(genvbound != NULL);
801 assert(boundval != NULL);
802 assert(success != NULL);
803
804 *success = FALSE;
805
806 /* get left-hand side variable */
807 lhsvar = genvbound->var;
808 assert(lhsvar != NULL);
809
810 /* get right-hand side variables */
811 vars = genvbound->vars;
812 nvars = genvbound->ncoefs;
813 assert(vars != NULL);
814
815 /* if only the primal bound participates in the propagation, it is globally valid and should not be analyzed */
816 assert(nvars > 0);
817
818 /* when resolving a propagation, bdchgidx is not NULL and boundval should be the bound change performed for the
819 * left-hand side variable
820 */
821 assert(bdchgidx == NULL || genvbound->boundtype != SCIP_BOUNDTYPE_LOWER || SCIPisEQ(scip,
822 SCIPvarIsIntegral(genvbound->var) ? SCIPfeasCeil(scip, *boundval) : *boundval, SCIPgetVarLbAtIndex(scip, lhsvar, bdchgidx, TRUE)));
823 assert(bdchgidx == NULL || genvbound->boundtype != SCIP_BOUNDTYPE_UPPER || SCIPisEQ(scip,
824 SCIPvarIsIntegral(genvbound->var) ? SCIPfeasCeil(scip, *boundval) : *boundval, -SCIPgetVarUbAtIndex(scip, lhsvar, bdchgidx, TRUE)));
825
826 /* when creating an initial conflict, bdchgidx is NULL and +/-boundval must exceed the upper/lower bound of the
827 * left-hand side variable
828 */
829 assert(bdchgidx != NULL || genvbound->boundtype != SCIP_BOUNDTYPE_LOWER
830 || SCIPisGT(scip, *boundval, SCIPvarGetUbLocal(lhsvar)));
831 assert(bdchgidx != NULL || genvbound->boundtype != SCIP_BOUNDTYPE_UPPER
832 || SCIPisGT(scip, *boundval, -SCIPvarGetLbLocal(lhsvar)));
833
834 SCIPdebugMsg(scip, "resolving genvbound propagation: lhs=%s<%s> >= boundval=%.15g\n",
835 genvbound->boundtype == SCIP_BOUNDTYPE_LOWER ? "+" : "-", SCIPvarGetName(lhsvar), *boundval);
836
837 /* subtract constant terms from bound value */
838 tmpboundval = *boundval;
839 tmpboundval -= genvbound->cutoffcoef * getCutoffboundGenVBound(scip);
840 tmpboundval -= genvbound->constant;
841
842 SCIPdebugMsg(scip, "subtracting constant terms gives boundval=%.15g\n", tmpboundval);
843
844 /* compute minimal activity; if bdchgidx is NULL, we create the initial conflict and use local bounds */
845 minactivity = getGenVBoundsMinActivityConflict(scip, genvbound->vars, genvbound->coefs, genvbound->ncoefs, bdchgidx);
846
847 SCIPdebugMsg(scip, "minactivity of right-hand side is minactivity=%.15g\n", minactivity);
848
849 /* a genvbound might have been replaced since the propagation took place, hence we have to check that the current
850 * genvbound can explain the propagation at the given bound change index; note that by now, with smaller cutoff
851 * bound, we might even perform a stronger propagation
852 */
853 if( SCIPisLT(scip, minactivity, tmpboundval) )
854 {
855 SCIPdebugMsg(scip, "minactivity is too small to explain propagation; was genvbound replaced?\n");
856 return SCIP_OKAY;
857 }
858
859 /* if bdchgidx is NULL, i.e., we create the initial conflict, we should be able to explain the bound change */
860 assert(SCIPisGE(scip, minactivity, tmpboundval));
861
862 slack = MAX(minactivity - tmpboundval, 0.0);
863
864 SCIPdebugMsg(scip, "slack=%.15g\n", slack);
865
866 /* add variables on the right-hand side as reasons for propagation */
867 for( i = 0; i < nvars; i++ )
868 {
869 assert(vars[i] != NULL);
872
873 /* coefficient is positive */
874 if( genvbound->coefs[i] > 0.0 )
875 {
876 SCIP_Real lbatindex;
877 SCIP_Real conflictlb;
878
879 /* get bound at current bound change */
880 lbatindex = SCIPgetVarLbAtIndex(scip, vars[i], bdchgidx, TRUE);
881
882 /* get bound already enforced by conflict set */
883 conflictlb = SCIPgetConflictVarLb(scip, genvbound->vars[i]);
884 assert(SCIPisGE(scip, conflictlb, SCIPvarGetLbGlobal(genvbound->vars[i])));
885
886 SCIPdebugMsg(scip, "lower bound of variable <%s> (genvbound->vars[%d]) in conflict set / at index is %.15g / %.15g\n",
887 SCIPvarGetName(genvbound->vars[i]), i, conflictlb, lbatindex);
888
889 /* if bound is already enforced by conflict set we do not need to add the bound change; since we used the
890 * tighest bound already when computing the initial minactivity, the slack is already correct
891 */
892 if( SCIPisLE(scip, lbatindex, conflictlb) )
893 {
894 SCIPdebugMsg(scip, "skipping lower bound of variable <%s> (genvbound->vars[%d]) already enforced in conflict set\n",
895 SCIPvarGetName(genvbound->vars[i]), i);
896 }
897 else
898 {
899 SCIP_Real relaxedlb;
900
901 /* compute relaxed bound that would suffice to explain the bound change */
902 relaxedlb = lbatindex - (slack / genvbound->coefs[i]);
903 assert(relaxedlb <= lbatindex);
904
905 /* add variable to conflict set */
906 SCIP_CALL( SCIPaddConflictRelaxedLb(scip, genvbound->vars[i], bdchgidx, relaxedlb ) );
907
908 /* get new bound of variable in conflict set; after possible bound widening in SCIPaddConflictLbRelaxed(),
909 * it should be between conflictlb and lbatindex
910 */
911 relaxedlb = SCIPgetConflictVarLb(scip, genvbound->vars[i]);
912 assert(SCIPisGE(scip, relaxedlb, conflictlb));
913 assert(SCIPisLE(scip, relaxedlb, lbatindex));
914
915 /* update slack and ensure that its nonegative */
916 slack -= genvbound->coefs[i] * (lbatindex - relaxedlb);
917 slack = MAX(slack, 0.0);
918
919 SCIPdebugMsg(scip, "added lower bound of variable <%s> (genvbound->vars[%d]); new slack=%.15g\n",
920 SCIPvarGetName(genvbound->vars[i]), i, slack);
921 }
922 }
923 /* coefficient is negative */
924 else
925 {
926 SCIP_Real ubatindex;
927 SCIP_Real conflictub;
928
929 /* get bound at current bound change */
930 ubatindex = SCIPgetVarUbAtIndex(scip, vars[i], bdchgidx, TRUE);
931
932 /* get bound already enforced by conflict set */
933 conflictub = SCIPgetConflictVarUb(scip, genvbound->vars[i]);
934 assert(SCIPisLE(scip, conflictub, SCIPvarGetUbGlobal(genvbound->vars[i])));
935
936 SCIPdebugMsg(scip, "upper bound of variable <%s> (genvbound->vars[%d]) in conflict set / at index is %.15g / %.15g\n",
937 SCIPvarGetName(genvbound->vars[i]), i, conflictub, ubatindex);
938
939 /* if bound is already enforced by conflict set we do not need to add the bound change; since we used the
940 * tighest bound already when computing the initial minactivity, the slack is already correct
941 */
942 if( SCIPisGE(scip, ubatindex, conflictub) )
943 {
944 SCIPdebugMsg(scip, "skipping upper bound of variable <%s> (genvbound->vars[%d]) already enforced in conflict set\n",
945 SCIPvarGetName(genvbound->vars[i]), i);
946 }
947 else
948 {
949 SCIP_Real relaxedub;
950
951 /* compute relaxed bound that would suffice to explain the bound change */
952 relaxedub = ubatindex - (slack / genvbound->coefs[i]);
953 assert(relaxedub >= ubatindex);
954
955 /* add variable to conflict set */
956 SCIP_CALL( SCIPaddConflictRelaxedUb(scip, genvbound->vars[i], bdchgidx, relaxedub ) );
957
958 /* get new bound of variable in conflict set; after possible bound widening in SCIPaddConflictUbRelaxed(),
959 * it should be between conflictub and ubatindex
960 */
961 relaxedub = SCIPgetConflictVarUb(scip, genvbound->vars[i]);
962 assert(SCIPisLE(scip, relaxedub, conflictub));
963 assert(SCIPisGE(scip, relaxedub, ubatindex));
964
965 /* update slack and ensure that its nonegative */
966 slack -= genvbound->coefs[i] * (ubatindex - relaxedub);
967 slack = MAX(slack, 0.0);
968
969 SCIPdebugMsg(scip, "added upper bound of variable <%s> (genvbound->vars[%d]); new slack=%.15g\n",
970 SCIPvarGetName(genvbound->vars[i]), i, slack);
971 }
972 }
973 }
974
975 /* if slack is positive, return increased boundval */
976 if( SCIPisPositive(scip, slack) )
977 tmpboundval += slack;
978
979 /* add constant terms again */
980 tmpboundval += genvbound->cutoffcoef * getCutoffboundGenVBound(scip);
981 tmpboundval += genvbound->constant;
982
983 /* boundval should not have been decreased; if this happened nevertheless, maybe due to numerical errors, we quit
984 * without success
985 */
986 if( SCIPisLT(scip, tmpboundval, *boundval) )
987 {
988 SCIPdebugMsg(scip, "boundval was reduced from %.15g to %.15g; propagation not resolved\n", *boundval, tmpboundval);
989 return SCIP_OKAY;
990 }
991
992 /* return widened boundval */
993 *boundval = tmpboundval;
994 *success = TRUE;
995
996 return SCIP_OKAY;
997}
998
999/** create initial conflict */
1000static
1002 SCIP* scip, /**< SCIP data structure */
1003 GENVBOUND* genvbound /**< genvbound data structure */
1004 )
1005{
1006 SCIP_Bool success;
1007
1008 assert(scip != NULL);
1009 assert(genvbound != NULL);
1010
1011 /* check if conflict analysis is applicable */
1013 return SCIP_OKAY;
1014
1015 /* initialize conflict analysis */
1017
1018 /* left-hand side variable >= ... */
1019 if( genvbound->boundtype == SCIP_BOUNDTYPE_LOWER )
1020 {
1021 SCIP_Real infeasthreshold;
1023
1024 /* get minimal right-hand side bound that leads to infeasibility; first try with a factor of 2 for robustness */
1025 bound = REALABS(SCIPvarGetUbLocal(genvbound->var));
1026 infeasthreshold = MAX(bound, 1.0) * 2 * SCIPfeastol(scip);
1027 bound = SCIPvarGetUbLocal(genvbound->var) + infeasthreshold;
1028
1029 /* add right-hand side variables that force the lower bound of the left-hand side variable above its upper bound
1030 * to conflict set
1031 */
1032 SCIP_CALL( resolveGenVBoundPropagation(scip, genvbound, NULL, &bound, &success) );
1033 assert(!success || SCIPisFeasGT(scip, bound, SCIPvarGetUbLocal(genvbound->var)));
1034
1035 /* if infeasibility cannot be proven with the tighter bound, try with actual bound */
1036 if( !success )
1037 {
1038 bound = REALABS(SCIPvarGetUbLocal(genvbound->var));
1039 infeasthreshold = MAX(bound, 1.0) * SCIPfeastol(scip);
1040 bound = SCIPvarGetUbLocal(genvbound->var) + infeasthreshold;
1041
1042 SCIP_CALL( resolveGenVBoundPropagation(scip, genvbound, NULL, &bound, &success) );
1043 success = success && SCIPisFeasGT(scip, bound, SCIPvarGetUbLocal(genvbound->var));
1044 }
1045
1046 /* compute upper bound on left-hand side variable that leads to infeasibility */
1047 bound -= infeasthreshold;
1048 success = success && SCIPisGE(scip, bound, SCIPvarGetUbLocal(genvbound->var));
1049
1050 /* initial reason could not be constructed, maybe due to numerics; do not apply conflict analysis */
1051 if( !success )
1052 {
1053 SCIPdebugMsg(scip, "strange: could not create initial reason to start conflict analysis\n");
1054 return SCIP_OKAY;
1055 }
1056
1057 /* if bound is already enforced by conflict set we do not have to add it */
1058 if( SCIPisGE(scip, bound, SCIPgetConflictVarUb(scip, genvbound->var)) )
1059 {
1060 SCIPdebugMsg(scip, "skipping upper bound of left-hand side variable <%s> already enforced in conflict set\n",
1061 SCIPvarGetName(genvbound->var));
1062 }
1063 else
1064 {
1065 SCIPdebugMsg(scip, "adding upper bound of left-hand side variable <%s>\n", SCIPvarGetName(genvbound->var));
1066
1068 }
1069 }
1070 /* left-hand side variable <= ..., i.e., - left-hand side variable >= ... */
1071 else
1072 {
1073 SCIP_Real infeasthreshold;
1075
1076 /* get minimal right-hand side bound that leads to infeasibility; try with a factor of 2 first for robustness */
1077 bound = REALABS(SCIPvarGetLbLocal(genvbound->var));
1078 infeasthreshold = MAX(bound, 1.0) * 2 * SCIPfeastol(scip);
1079 bound = -SCIPvarGetLbLocal(genvbound->var) + infeasthreshold;
1080
1081 /* add right-hand side variables that force the upper bound of the left-hand side variable below its lower bound
1082 * to conflict set
1083 */
1084 SCIP_CALL( resolveGenVBoundPropagation(scip, genvbound, NULL, &bound, &success) );
1085 assert(!success || SCIPisFeasLT(scip, -bound, SCIPvarGetLbLocal(genvbound->var)));
1086
1087 /* if infeasibility cannot be proven with the tighter bound, try with actual bound */
1088 if( !success )
1089 {
1090 bound = REALABS(SCIPvarGetLbLocal(genvbound->var));
1091 infeasthreshold = MAX(bound, 1.0) * SCIPfeastol(scip);
1092 bound = -SCIPvarGetLbLocal(genvbound->var) + infeasthreshold;
1093
1094 SCIP_CALL( resolveGenVBoundPropagation(scip, genvbound, NULL, &bound, &success) );
1095 success = success && SCIPisFeasLT(scip, -bound, SCIPvarGetLbLocal(genvbound->var));
1096 }
1097
1098 /* compute lower bound on left-hand side variable that leads to infeasibility */
1099 bound = -bound + infeasthreshold;
1100 success = success && SCIPisLE(scip, bound, SCIPvarGetLbLocal(genvbound->var));
1101
1102 /* initial reason could not be constructed, maybe due to numerics; do not apply conflict analysis */
1103 if( !success )
1104 {
1105 SCIPdebugMsg(scip, "strange: could not create initial reason to start conflict analysis\n");
1106 return SCIP_OKAY;
1107 }
1108
1109 /* if bound is already enforced by conflict set we do not have to add it */
1110 if( SCIPisLE(scip, bound, SCIPgetConflictVarLb(scip, genvbound->var)) )
1111 {
1112 SCIPdebugMsg(scip, "skipping lower bound of left-hand side variable <%s> already enforced in conflict set\n",
1113 SCIPvarGetName(genvbound->var));
1114 }
1115 else
1116 {
1117 SCIPdebugMsg(scip, "adding lower bound of left-hand side variable <%s>\n", SCIPvarGetName(genvbound->var));
1118
1120 }
1121 }
1122
1123 /* analyze the conflict */
1125
1126 return SCIP_OKAY;
1127}
1128
1129/** apply propagation for one generalized variable bound; also if the left-hand side variable is locally fixed, we
1130 * compute the right-hand side minactivity to possibly detect infeasibility
1131 */
1132static
1134 SCIP* scip, /**< SCIP data structure */
1135 SCIP_PROP* prop, /**< genvbounds propagator */
1136 GENVBOUND* genvbound, /**< genvbound data structure */
1137 SCIP_Bool global, /**< apply global bound changes? (global: true, local: false)*/
1138 SCIP_RESULT* result, /**< result pointer */
1139 int* nchgbds /**< counter to increment if bound was tightened */
1140 )
1141{
1142 SCIP_Real boundval;
1143 SCIP_Bool infeas;
1144 SCIP_Bool tightened;
1145
1146 assert(scip != NULL);
1147 assert(genvbound != NULL);
1148 assert(genvbound->var != NULL);
1150 assert(result != NULL);
1152
1153 /* get bound value provided by genvbound */
1154 boundval = getGenVBoundsBound(scip, genvbound, global);
1155
1156 if( SCIPisInfinity(scip, REALABS(boundval)) )
1157 return SCIP_OKAY;
1158
1159#ifdef SCIP_DEBUG
1160 {
1161 SCIP_Real lb;
1162 SCIP_Real ub;
1163 SCIP_Real new_lb;
1164 SCIP_Real new_ub;
1165
1166 lb = global ? SCIPvarGetLbGlobal(genvbound->var) : SCIPvarGetLbLocal(genvbound->var);
1167 ub = global ? SCIPvarGetUbGlobal(genvbound->var) : SCIPvarGetUbLocal(genvbound->var);
1168 new_lb = genvbound->boundtype == SCIP_BOUNDTYPE_LOWER ? boundval : lb;
1169 new_ub = genvbound->boundtype == SCIP_BOUNDTYPE_UPPER ? boundval : ub;
1170
1171 SCIPdebugMsg(scip, " %s genvbound propagation for <%s>\n", global ?
1172 "global" : "local", SCIPvarGetName(genvbound->var));
1173 SCIPdebugMsg(scip, " genvbound: ");
1174 printGenVBound(scip, genvbound);
1175 SCIPdebugMsg(scip, " [%.15g,%.15g] -> [%.15g,%.15g]\n", lb, ub, new_lb, new_ub);
1176 }
1177#endif
1178
1179 /* tighten bound globally */
1180 if( global || genvbound->ncoefs <= 0 )
1181 {
1182 if( genvbound->boundtype == SCIP_BOUNDTYPE_LOWER )
1183 {
1184 SCIP_CALL( SCIPtightenVarLbGlobal(scip, genvbound->var, boundval, FALSE, &infeas, &tightened) );
1185 }
1186 else
1187 {
1188 SCIP_CALL( SCIPtightenVarUbGlobal(scip, genvbound->var, boundval, FALSE, &infeas, &tightened) );
1189 }
1190 }
1191 /* tighten bound locally and start conflict analysis in case of infeasibility; as inferinfo we pass the index of the
1192 * genvbound that was used for propagation
1193 */
1194 else
1195 {
1196 if( genvbound->boundtype == SCIP_BOUNDTYPE_LOWER )
1197 {
1198 SCIP_CALL( SCIPinferVarLbProp(scip, genvbound->var, boundval, prop, genvbound->index, FALSE, &infeas, &tightened) );
1199
1200 /* initialize conflict analysis if infeasible */
1201 if( infeas )
1202 {
1203 SCIPdebugMsg(scip, " -> lower bound tightening on variable <%s> led to infeasibility\n",
1204 SCIPvarGetName(genvbound->var));
1205
1207 }
1208 }
1209 else
1210 {
1211 SCIP_CALL( SCIPinferVarUbProp(scip, genvbound->var, boundval, prop, genvbound->index, FALSE, &infeas, &tightened) );
1212
1213 /* initialize conflict analysis if infeasible */
1214 if( infeas )
1215 {
1216 SCIPdebugMsg(scip, " -> upper bound tightening on variable <%s> led to infeasibility\n",
1217 SCIPvarGetName(genvbound->var));
1218
1220 }
1221 }
1222 }
1223
1224 /* handle result */
1225 if( infeas )
1226 {
1228 SCIPdebugMsg(scip, " cutoff!\n");
1229 }
1230 else if( tightened )
1231 {
1233 if( nchgbds != NULL )
1234 ++(*nchgbds);
1235 SCIPdebugMsg(scip, " tightened!\n");
1236 }
1237
1238 return SCIP_OKAY;
1239}
1240
1241#ifdef SCIP_DEBUG
1242/** prints event data as debug message */
1243static
1244void printEventData(
1245 SCIP_EVENTDATA* eventdata,
1246 SCIP_BOUNDTYPE boundtype
1247 )
1248{
1249 int i;
1250
1251 SCIPdebugMessage("event data: %s bound of <%s> tightened ==> start propagating at ",
1252 boundtype == SCIP_BOUNDTYPE_LOWER ? "lower" : "upper", SCIPvarGetName(eventdata->var));
1253
1254 /* if there is eventdata it should contain at least one starting index */
1255 assert(eventdata->nstarts > 0);
1256
1257 for( i = 0; i < eventdata->nstarts; i++ )
1258 {
1259 SCIPdebugPrintf("(component %d, index %d) ", eventdata->startcomponents[i], eventdata->startindices[i]);
1260 }
1261 SCIPdebugPrintf("\n");
1262}
1263#endif
1264
1265/** frees event data */
1266static
1268 SCIP* scip, /**< SCIP data structure */
1269 SCIP_EVENTDATA** eventdata /**< event data to be freed */
1270 )
1271{
1272 assert(scip != NULL);
1273 assert(eventdata != NULL);
1274 assert(*eventdata != NULL);
1275
1276 SCIPfreeBlockMemoryArray(scip, &((*eventdata)->startcomponents), (*eventdata)->startindicessize);
1277 SCIPfreeBlockMemoryArray(scip, &((*eventdata)->startindices), (*eventdata)->startindicessize);
1278
1279 (*eventdata)->startindicessize = 0;
1280 (*eventdata)->nstarts = -1;
1281 (*eventdata)->var = NULL;
1282 (*eventdata)->prop = NULL;
1283
1284 SCIPfreeBlockMemory(scip, eventdata);
1285
1286 return SCIP_OKAY;
1287}
1288
1289/** frees all eventdata stored */
1290static
1292 SCIP* scip, /**< SCIP data structure */
1293 SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
1294 )
1295{
1296 int i;
1297
1298 assert(scip != NULL);
1299 assert(propdata != NULL);
1300
1301 if( propdata->lbevents != NULL )
1302 {
1303 assert(propdata->ubevents != NULL);
1304 assert(propdata->lbeventsmap != NULL);
1305 assert(propdata->ubeventsmap != NULL);
1306
1307 SCIPhashmapFree(&(propdata->lbeventsmap));
1308 SCIPhashmapFree(&(propdata->ubeventsmap));
1309
1310 for( i = propdata->nlbevents - 1; i >= 0; i-- )
1311 {
1312 SCIP_CALL( freeEventData(scip, &(propdata->lbevents[i])) );
1313 }
1314
1315 for( i = propdata->nubevents - 1; i >= 0; i-- )
1316 {
1317 SCIP_CALL( freeEventData(scip, &(propdata->ubevents[i])) );
1318 }
1319
1320 SCIPfreeBlockMemoryArray(scip, &(propdata->ubevents), propdata->nubevents);
1321 SCIPfreeBlockMemoryArray(scip, &(propdata->lbevents), propdata->nlbevents);
1322 propdata->nlbevents = -1;
1323 propdata->nubevents = -1;
1324 }
1325
1326 assert(propdata->lbevents == NULL);
1327 assert(propdata->ubevents == NULL);
1328 assert(propdata->lbeventsmap == NULL);
1329 assert(propdata->ubeventsmap == NULL);
1330 assert(propdata->nlbevents == -1);
1331 assert(propdata->nubevents == -1);
1332
1333 return SCIP_OKAY;
1334}
1335
1336/** drops all events caught by genvbounds propagator and frees their data */
1337static
1339 SCIP* scip, /**< SCIP data structure */
1340 SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
1341 )
1342{
1343 int i;
1344
1345 SCIPdebugMsg(scip, "drop and free events\n");
1346
1347 assert(scip != NULL);
1348 assert(propdata != NULL);
1349 assert(propdata->eventhdlr != NULL);
1350
1351 if( propdata->lbevents != NULL )
1352 {
1353 assert(propdata->ubevents != NULL);
1354 assert(propdata->nlbevents >= 0);
1355 assert(propdata->nubevents >= 0);
1356
1357 for( i = propdata->nlbevents - 1; i >= 0; i-- )
1358 {
1359 /* drop event */
1360 SCIP_CALL( SCIPdropVarEvent(scip, propdata->lbevents[i]->var, SCIP_EVENTTYPE_LBTIGHTENED, propdata->eventhdlr,
1361 propdata->lbevents[i], -1) );
1362 }
1363
1364 for( i = propdata->nubevents - 1; i >= 0; i-- )
1365 {
1366 /* drop event */
1367 SCIP_CALL( SCIPdropVarEvent(scip, propdata->ubevents[i]->var, SCIP_EVENTTYPE_UBTIGHTENED, propdata->eventhdlr,
1368 propdata->ubevents[i], -1) );
1369 }
1370
1371 /* free event data */
1372 SCIP_CALL( freeAllEventData(scip, propdata) );
1373 }
1374
1375 assert(propdata->lbevents == NULL);
1376 assert(propdata->ubevents == NULL);
1377 assert(propdata->nlbevents == -1);
1378 assert(propdata->nubevents == -1);
1379
1380 return SCIP_OKAY;
1381}
1382
1383/** returns the corresponding event data entry in the corresponding array, if there is one; if not: allocates a new
1384 * event data entry, stores it in the array and returns its adress
1385 */
1386static
1388 SCIP* scip, /**< SCIP data structure */
1389 SCIP_PROPDATA* propdata, /**< data of the genvbounds propagator */
1390 SCIP_VAR* var, /**< variable */
1391 SCIP_BOUNDTYPE boundtype, /**< type of bound */
1392 SCIP_EVENTDATA** eventdata /**< event data to return */
1393 )
1394{
1395 SCIP_HASHMAP* hashmap;
1396
1397 assert(scip != NULL);
1398 assert(propdata != NULL);
1399 assert(var != NULL);
1400
1401 hashmap = boundtype == SCIP_BOUNDTYPE_LOWER ? propdata->lbeventsmap : propdata->ubeventsmap;
1402
1403 if( SCIPhashmapExists(hashmap, var) )
1404 *eventdata = (SCIP_EVENTDATA*) SCIPhashmapGetImage(hashmap, var);
1405 else
1406 {
1407 /* set up new eventdata entry */
1408 SCIP_CALL( SCIPallocBlockMemory(scip, eventdata) );
1409 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &((*eventdata)->startcomponents), propdata->ncomponents) );
1410 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &((*eventdata)->startindices), propdata->ncomponents) );
1411 (*eventdata)->startindicessize = propdata->ncomponents;
1412 (*eventdata)->nstarts = 0;
1413 (*eventdata)->var = var;
1414 (*eventdata)->prop = propdata->prop;
1415
1416 /* store event data in eventarray */
1417 if( boundtype == SCIP_BOUNDTYPE_LOWER )
1418 {
1419 propdata->lbevents[propdata->nlbevents] = *eventdata;
1420 propdata->nlbevents++;
1421 }
1422 else
1423 {
1424 propdata->ubevents[propdata->nubevents] = *eventdata;
1425 propdata->nubevents++;
1426 }
1427
1428 /* store hashmap entry */
1429 SCIP_CALL( SCIPhashmapInsert(hashmap, var, (*eventdata)) );
1430 }
1431
1432 return SCIP_OKAY;
1433}
1434
1435/** adds an event to the event array lbevents (if boundtype == SCIP_BOUNDTYPE_LOWER) or ubevents (if boundtype ==
1436 * SCIP_BOUNDTYPE_UPPER)
1437 */
1438static
1440 SCIP* scip, /**< SCIP data structure */
1441 SCIP_PROPDATA* propdata, /**< data of the genvbounds propagator */
1442 SCIP_VAR* var, /**< variable thats event to be added */
1443 int startindex, /**< starting index */
1444 int startcomponent, /**< starting components index */
1445 SCIP_BOUNDTYPE boundtype /**< type of bound */
1446 )
1447{
1448 SCIP_EVENTDATA* eventdata;
1449
1450 assert(scip != NULL);
1451 assert(propdata != NULL);
1452 assert(var != NULL);
1453 assert(startindex >= 0);
1454 assert(startcomponent >= 0);
1455
1456 /* get eventdata entry */
1457 SCIP_CALL( getEventData(scip, propdata, var, boundtype, &eventdata) );
1458 assert(eventdata != NULL);
1459
1460 if( eventdata->nstarts > 0 && eventdata->startcomponents[eventdata->nstarts - 1] == startcomponent )
1461 {
1462 /* if there is already a starting index for startcomponent stored at the last entry of eventdata->startindices,
1463 * it should be smaller; this relies on the implementation of setUpEvents(), calling addEventData() in
1464 * topological order
1465 */
1466 assert(eventdata->startindices[eventdata->nstarts - 1] < startindex);
1467 }
1468 else
1469 {
1470 /* append starting information */
1471 eventdata->startcomponents[eventdata->nstarts] = startcomponent;
1472 eventdata->startindices[eventdata->nstarts] = startindex;
1473
1474 /* increase counter */
1475 eventdata->nstarts++;
1476 }
1477
1478 return SCIP_OKAY;
1479}
1480
1481static
1483 SCIP* scip, /**< SCIP data structure */
1484 SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
1485 )
1486{
1487 int nprobvars;
1488 int i;
1489
1490 assert(scip != NULL);
1491 assert(propdata != NULL);
1492 assert(propdata->eventhdlr != NULL);
1493 assert(propdata->lbevents == NULL);
1494 assert(propdata->ubevents == NULL);
1495 assert(propdata->issorted);
1496 assert(propdata->nlbevents == -1);
1497 assert(propdata->nubevents == -1);
1498
1499 SCIPdebugMsg(scip, "set up events\n");
1500
1501 /* allocate lbevents, ubevents, and their hashmaps */
1502 nprobvars = SCIPgetNVars(scip) + SCIPgetNFixedVars(scip);
1503 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(propdata->lbevents), nprobvars) );
1504 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(propdata->ubevents), nprobvars) );
1505 SCIP_CALL( SCIPhashmapCreate(&(propdata->lbeventsmap), SCIPblkmem(scip), nprobvars) );
1506 SCIP_CALL( SCIPhashmapCreate(&(propdata->ubeventsmap), SCIPblkmem(scip), nprobvars) );
1507 propdata->nlbevents = 0;
1508 propdata->nubevents = 0;
1509
1510 /* loop over all components of genvboundstore */
1511 for( i = 0; i < propdata->ncomponents; i++ )
1512 {
1513 int j;
1514
1515 /* loop over all genvbounds in this component */
1516 for( j = propdata->componentsstart[i]; j < propdata->componentsstart[i+1]; j++ ) /*lint !e679*/
1517 {
1518 GENVBOUND* genvbound;
1519 int k;
1520
1521 assert(j < propdata->ngenvbounds);
1522
1523 genvbound = propdata->genvboundstore[j];
1524 assert(genvbound != NULL);
1525
1526 /* loop over all coefficients in this genvbound */
1527 for( k = 0; k < genvbound->ncoefs; k++ )
1528 {
1529 if( SCIPisPositive(scip, genvbound->coefs[k]) )
1530 {
1531 SCIP_CALL( addEventData(scip, propdata, genvbound->vars[k], j, i, SCIP_BOUNDTYPE_LOWER) );
1532 }
1533 else
1534 {
1535 SCIP_CALL( addEventData(scip, propdata, genvbound->vars[k], j, i, SCIP_BOUNDTYPE_UPPER) );
1536 }
1537 }
1538 }
1539 }
1540
1541 /* resize lbevents and ubevents array */
1542 assert(propdata->nlbevents <= nprobvars);
1543 assert(propdata->nubevents <= nprobvars);
1544 if( propdata->nlbevents < nprobvars )
1545 {
1546 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(propdata->lbevents), nprobvars, propdata->nlbevents) );
1547 }
1548 if( propdata->nubevents < nprobvars )
1549 {
1550 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(propdata->ubevents), nprobvars, propdata->nubevents) );
1551 }
1552
1553 /* resize and register lower bound events */
1554 for( i = 0; i < propdata->nlbevents; i++ )
1555 {
1556 SCIP_EVENTDATA* eventdata = propdata->lbevents[i];
1557
1558 assert(eventdata != NULL);
1559 assert(eventdata->nstarts > 0);
1560 assert(eventdata->startcomponents != NULL);
1561 assert(eventdata->startindices != NULL);
1562
1563 /* resize arrays stored in eventdata */
1564 if( eventdata->startindicessize != eventdata->nstarts )
1565 {
1566 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(eventdata->startcomponents), eventdata->startindicessize, \
1567 eventdata->nstarts) );
1568 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(eventdata->startindices), eventdata->startindicessize, \
1569 eventdata->nstarts) );
1570 eventdata->startindicessize = eventdata->nstarts;
1571 }
1572
1573 /* register event */
1574 SCIP_CALL( SCIPcatchVarEvent(scip, eventdata->var, SCIP_EVENTTYPE_LBTIGHTENED, propdata->eventhdlr, eventdata, \
1575 NULL) );
1576 }
1577
1578 /* resize and register upper bound events */
1579 for( i = 0; i < propdata->nubevents; i++ )
1580 {
1581 SCIP_EVENTDATA* eventdata = propdata->ubevents[i];
1582
1583 assert(eventdata != NULL);
1584 assert(eventdata->nstarts > 0);
1585 assert(eventdata->startcomponents != NULL);
1586 assert(eventdata->startindices != NULL);
1587
1588 /* resize arrays stored in eventdata */
1589 if( eventdata->startindicessize != eventdata->nstarts )
1590 {
1591 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(eventdata->startcomponents), eventdata->startindicessize, \
1592 eventdata->nstarts) );
1593 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(eventdata->startindices), eventdata->startindicessize, \
1594 eventdata->nstarts) );
1595 eventdata->startindicessize = eventdata->nstarts;
1596 }
1597 /* register event */
1598 SCIP_CALL( SCIPcatchVarEvent(scip, eventdata->var, SCIP_EVENTTYPE_UBTIGHTENED, propdata->eventhdlr, eventdata,
1599 NULL) );
1600 }
1601
1602 return SCIP_OKAY;
1603}
1604
1605/** performs a topological sort on genvboundstore array
1606 *
1607 * The genvbounds graph is defined as follows: Given two genvbounds
1608 *
1609 * (genvbound1) c1 * x_i1 >= RHS1
1610 *
1611 * and
1612 *
1613 * (genvbound2) c2 * x_i2 >= RHS2,
1614 *
1615 * there is an arc from genvbound1 to genvbound2 iff c1 = +1 and x_i1 appears with positive coefficient in RHS2 or
1616 * c1 = -1 and x_i1 appears with negative coefficient in RHS2; in this case, a bound change of x_i1 deduced from
1617 * genvbound1 improves genvbound2's minactivity in RHS2.
1618 *
1619 * The method computes the strongly connected components and sorts them topologically. The order of the nodes in an
1620 * strongly connected component is arbitrary.
1621 */
1622static
1624 SCIP* scip, /**< SCIP data structure */
1625 SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
1626 )
1627{
1628 GENVBOUND** genvboundssorted; /* array to store the sorted genvbounds */
1629 SCIP_DIGRAPH* graph;
1630 int* strongcomponents;
1631 int* strongcompstartidx;
1632 int sortedindex;
1633 int i;
1634
1635 assert(scip != NULL);
1636 assert(propdata != NULL);
1637 assert(propdata->componentsstart == NULL);
1638
1639 SCIPdebugMsg(scip, "(re-)sort genvbounds topologically\n");
1640
1641 /* create digraph */
1642 SCIP_CALL( SCIPcreateDigraph(scip, &graph, propdata->ngenvbounds) );
1643
1644 /* add outgoing arcs for each genvbound */
1645 for( i = 0; i < propdata->ngenvbounds; i++ )
1646 {
1647 GENVBOUND* genvbound;
1648 int j;
1649
1650 assert(i < propdata->ngenvbounds);
1651
1652 genvbound = propdata->genvboundstore[i];
1653
1654 for( j = 0; j < genvbound->ncoefs; j++ )
1655 {
1656 if( SCIPisPositive(scip, genvbound->coefs[j]) &&
1657 SCIPhashmapExists(propdata->lbgenvbounds, genvbound->vars[j]) )
1658 {
1659 int from = ((GENVBOUND*) SCIPhashmapGetImage(propdata->lbgenvbounds, genvbound->vars[j]))->index;
1660 SCIP_CALL( SCIPdigraphAddArc(graph, from, i, NULL) );
1661 }
1662 else if( SCIPisNegative(scip, genvbound->coefs[j]) &&
1663 SCIPhashmapExists(propdata->ubgenvbounds, genvbound->vars[j]) )
1664 {
1665 int from = ((GENVBOUND*) SCIPhashmapGetImage(propdata->ubgenvbounds, genvbound->vars[j]))->index;
1666 SCIP_CALL( SCIPdigraphAddArc(graph, from, i, NULL) );
1667 }
1668 }
1669 }
1670
1671 /* perform the topological sort */
1672 SCIP_CALL( SCIPdigraphComputeUndirectedComponents(graph, 1, NULL, &(propdata->ncomponents)) );
1674 assert(SCIPdigraphGetNComponents(graph) == propdata->ncomponents);
1675
1676 /* allocate memory for genvboundssorted and componentsstart array */
1677 SCIP_CALL( SCIPallocBufferArray(scip, &genvboundssorted, propdata->ngenvbounds) );
1678 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(propdata->componentsstart), propdata->ncomponents + 1) );
1679 propdata->componentsstartsize = propdata->ncomponents + 1;
1680
1681 /* allocate memory for strong component arrays */
1682 SCIP_CALL( SCIPallocBufferArray(scip, &strongcomponents, SCIPdigraphGetNNodes(graph)) ); /*lint !e666*/
1683 SCIP_CALL( SCIPallocBufferArray(scip, &strongcompstartidx, SCIPdigraphGetNNodes(graph) + 1) ); /*lint !e666*/
1684
1685 /* compute sorted genvbounds array, fill componentsstart array */
1686 sortedindex = 0;
1687 propdata->componentsstart[propdata->ncomponents] = propdata->ngenvbounds;
1688 for( i = 0; i < propdata->ncomponents; i++ )
1689 {
1690 int j;
1691 int *nodes;
1692 int nnodes;
1693 int nstrongcomponents;
1694
1695 SCIPdigraphGetComponent(graph, i, &nodes, &nnodes);
1696 propdata->componentsstart[i] = sortedindex;
1697
1698 /* compute the strong components of the i-th undirected component */
1699 if( nnodes > 2 )
1700 {
1701 SCIP_CALL( SCIPdigraphComputeDirectedComponents(graph, i, strongcomponents, strongcompstartidx,
1702 &nstrongcomponents) );
1703
1704 for( j = 0; j < nnodes; ++j )
1705 {
1706 int node;
1707
1708 /* take the nodes at the end of the strong components array first to respect the topological
1709 * order of the different strong components
1710 */
1711 node = strongcomponents[nnodes - j - 1];
1712
1713 assert(node < propdata->ngenvbounds);
1714 genvboundssorted[sortedindex] = propdata->genvboundstore[node];
1715 sortedindex++;
1716 }
1717 }
1718 else
1719 {
1720 for( j = 0; j < nnodes; j++ )
1721 {
1722 assert(nodes[j] < propdata->ngenvbounds);
1723 genvboundssorted[sortedindex] = propdata->genvboundstore[nodes[j]];
1724 sortedindex++;
1725 }
1726 }
1727 }
1728 assert(sortedindex == propdata->ngenvbounds);
1729
1730 /* copy sorted genvbounds into genvboundstore */
1731 for( i = 0; i < propdata->ngenvbounds; i++ )
1732 {
1733 assert(genvboundssorted[i] != NULL);
1734
1735 propdata->genvboundstore[i] = genvboundssorted[i];
1736 propdata->genvboundstore[i]->index = i;
1737 }
1738
1739 /* free strong component arrays */
1740 SCIPfreeBufferArray(scip, &strongcompstartidx);
1741 SCIPfreeBufferArray(scip, &strongcomponents);
1742
1743 SCIPfreeBufferArray(scip, &(genvboundssorted));
1744
1745 /* free digraph */
1746 SCIPdigraphFree(&graph);
1747
1748 /* remember genvboundstore as sorted */
1749 propdata->issorted = TRUE;
1750
1751#ifdef SCIP_DEBUG
1752 SCIPdebugMsg(scip, "genvbounds got: %d\n", propdata->ngenvbounds);
1753 for( i = 0; i < propdata->ncomponents; i++ )
1754 {
1755 int j;
1756
1757 SCIPdebugMsg(scip, "{\n");
1758
1759 for( j = propdata->componentsstart[i]; j < propdata->componentsstart[i+1]; j++ )
1760 {
1761 SCIPdebugMsg(scip, " [%d] ", j);
1762 printGenVBound(scip, propdata->genvboundstore[j]);
1763 }
1764
1765 SCIPdebugMsg(scip, "}\n");
1766 }
1767#endif
1768
1769 return SCIP_OKAY;
1770}
1771
1772/** apply propagation of generalized variable bounds */
1773static
1775 SCIP* scip, /**< SCIP data structure */
1776 SCIP_PROP* prop, /**< genvbounds propagator */
1777 SCIP_Bool global, /**< use global variable bounds for propagation? */
1778 SCIP_RESULT* result, /**< result pointer */
1779 int* nchgbds /**< counter to increase by the number of changed bounds */
1780 )
1781{
1782 SCIP_PROPDATA* propdata;
1783 int* startingcomponents;
1784 int* startingindices;
1785 int nindices;
1786 int i;
1787
1788 SCIPdebugMsg(scip, "applying %s genvbound propagation in depth %d\n", global ?
1789 "global" : "local", SCIPgetDepth(scip));
1790
1791 assert(scip != NULL);
1792 assert(prop != NULL);
1793 assert(result != NULL);
1794
1795 propdata = SCIPpropGetData(prop);
1796 assert(propdata != NULL);
1797 assert(propdata->genvboundstore != NULL);
1798
1799 if( *result == SCIP_DIDNOTRUN )
1801
1802 /* if the genvbounds are not sorted, i.e. if root node processing has not been finished, yet, we just propagate in
1803 * the order in which they have been added to genvboundstore
1804 */
1805 if( !propdata->issorted )
1806 {
1807 int j;
1808
1809 assert(!propdata->sort || SCIPinProbing(scip) || SCIPgetDepth(scip) == 0);
1810
1811 for( j = 0; j < propdata->ngenvbounds && *result != SCIP_CUTOFF; j++ )
1812 {
1813 if( ! SCIPvarIsActive(propdata->genvboundstore[j]->var) )
1814 {
1815 /**@todo resolve multiaggregation in exitpre */
1816 }
1817 else
1818 {
1819 SCIPdebugMsg(scip, "applying genvbound with index %d (unsorted mode)\n", j);
1820 SCIP_CALL( applyGenVBound(scip, prop, propdata->genvboundstore[j], global, result, nchgbds) );
1821 }
1822 }
1823
1824 return SCIP_OKAY;
1825 }
1826
1827 /* otherwise, we propagate only components affected by the latest bound changes */
1828 startingcomponents = global ? propdata->gstartcomponents : propdata->startcomponents;
1829 startingindices = global ? propdata->gstartindices : propdata->startindices;
1830 nindices = global ? propdata->ngindices : propdata->nindices;
1831
1832 for( i = 0; i < nindices && *result != SCIP_CUTOFF; i++ )
1833 {
1834 int j;
1835
1836 SCIPdebugMsg(scip, "starting in component %d at index %d\n", startingcomponents[i], startingindices[i]);
1837 for( j = startingindices[i]; j < propdata->componentsstart[startingcomponents[i] + 1] &&
1838 *result != SCIP_CUTOFF; j++ ) /*lint !e679*/
1839 {
1840 assert(j < propdata->ngenvbounds);
1841
1842 if( ! SCIPvarIsActive(propdata->genvboundstore[j]->var) )
1843 {
1844 /**@todo resolve multiaggregation in exitpre */
1845 }
1846 else
1847 {
1848 SCIPdebugMsg(scip, "applying genvbound with index %d, component %d\n", j, startingcomponents[i]);
1849 SCIP_CALL( applyGenVBound(scip, prop, propdata->genvboundstore[j], global, result, nchgbds) );
1850 }
1851 }
1852 }
1853
1854 /* we dont want to run again caused by this starting data */
1855 if( !global )
1856 {
1858 }
1859
1860 return SCIP_OKAY;
1861}
1862
1863/** initialize propagator data */
1864static
1866 SCIP* scip, /**< SCIP data structure */
1867 SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
1868 )
1869{
1870 int nprobvars;
1871
1872 assert(scip != NULL);
1873 assert(propdata != NULL);
1874 assert(propdata->eventhdlr != NULL);
1875 assert(propdata->ngenvbounds == -1);
1876
1877 SCIPdebugMsg(scip, "init propdata\n");
1878
1879 nprobvars = SCIPgetNVars(scip);
1880
1881 /* init genvboundstore */
1882 propdata->genvboundstoresize = 2 * nprobvars;
1883 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(propdata->genvboundstore), propdata->genvboundstoresize) );
1884 BMSclearMemoryArray(propdata->genvboundstore, propdata->genvboundstoresize);
1885 propdata->ngenvbounds = 0;
1886
1887 /* init genvboundstore hashmaps */
1888 SCIP_CALL( SCIPhashmapCreate(&(propdata->lbgenvbounds), SCIPblkmem(scip), nprobvars) );
1889 SCIP_CALL( SCIPhashmapCreate(&(propdata->ubgenvbounds), SCIPblkmem(scip), nprobvars) );
1890
1891 return SCIP_OKAY;
1892}
1893
1894/** adds a new genvbound to genvboundstore array and sets a hashmap entry */
1895static
1897 SCIP* scip, /**< SCIP data structure */
1898 SCIP_PROP* prop, /**< genvbounds propagator */
1899 SCIP_PROPDATA* propdata, /**< data of the genvbounds propagator */
1900 GENVBOUND* genvbound /**< genvbound to be added */
1901 )
1902{
1903 SCIP_HASHMAP* hashmap;
1904
1905 assert(scip != NULL);
1906 assert(propdata != NULL);
1907 assert(genvbound != NULL);
1908 assert(getGenVBound(scip, propdata, genvbound->var, genvbound->boundtype) == NULL);
1909
1910 hashmap = genvbound->boundtype == SCIP_BOUNDTYPE_LOWER ? propdata->lbgenvbounds : propdata->ubgenvbounds;
1911
1912 /* e.g., during presolving after a restart, new variables might have been created; in this case, we need to extend
1913 * the genvboundstore; the new size may even exceed 2*SCIPgetNVars() if we have genvbounds with nonactive left-hand
1914 * side variables
1915 */
1916 assert(propdata->ngenvbounds <= propdata->genvboundstoresize);
1917 if( propdata->ngenvbounds == propdata->genvboundstoresize )
1918 {
1919 int oldsize = propdata->genvboundstoresize;
1920 propdata->genvboundstoresize = 2*propdata->genvboundstoresize + 1;
1921 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(propdata->genvboundstore), oldsize, propdata->genvboundstoresize) );
1922 }
1923
1924 /* enable genvbounds propagator */
1925 if( propdata->ngenvbounds == 0 )
1926 SCIPpropSetTimingmask(prop, propdata->inittiming);
1927
1928 /* new index is propdata->ngenvbounds */
1929 SCIP_CALL( SCIPhashmapInsert(hashmap, genvbound->var, genvbound) );
1930 propdata->genvboundstore[propdata->ngenvbounds] = genvbound;
1931 genvbound->index = propdata->ngenvbounds;
1932 propdata->ngenvbounds++;
1933
1934 assert(propdata->ngenvbounds <= propdata->genvboundstoresize);
1935
1936 return SCIP_OKAY;
1937}
1938
1939/** runs propagation routine */
1940static
1942 SCIP* scip, /**< SCIP data structure */
1943 SCIP_PROPDATA* propdata, /**< data of the genvbounds propagator */
1944 SCIP_RESULT* result, /**< result pointer */
1945 SCIP_Bool local, /**< should local propagation be applied? */
1946 int* nchgbds /**< counter to increase by the number of changed bounds */
1947 )
1948{
1949 assert(scip != NULL);
1950 assert(propdata != NULL);
1951 assert(propdata->prop != NULL);
1952 assert(result != NULL);
1953
1954 /* we only sort after the root node is finished; this avoids having to sort again after adding more genvbounds; if
1955 * the genvbounds are not sorted, we will simply propagate all of them in the order given
1956 */
1957 if( propdata->sort && !SCIPinProbing(scip) && SCIPgetDepth(scip) > 0 )
1958 {
1959 if( !propdata->issorted )
1960 {
1962
1963 SCIPdebugMsg(scip, "genvbounds are not sorted\n");
1964
1965 /* drop and free old events */
1966 SCIP_CALL( dropAndFreeEvents(scip, propdata) );
1967
1968 /* free old starting data */
1969 SCIP_CALL( freeStartingData(scip, propdata) );
1970
1971 /* free sorted components data */
1972 SCIP_CALL( freeComponentsData(scip, propdata) );
1973
1974 /* sort genvbounds */
1975 SCIP_CALL( sortGenVBounds(scip, propdata) );
1976
1977 /* create starting data */
1978 SCIP_CALL( createStartingData(scip, propdata) );
1979
1980 /* fill global starting data */
1982 }
1983
1984 /* set up new events to catch (if not done so far) */
1985 if( propdata->lbevents == NULL )
1986 {
1987 SCIP_CALL( setUpEvents(scip, propdata) );
1988 }
1989 }
1990
1991 /* apply global propagation if primal bound has improved */
1992 if( propdata->global && SCIPgetDepth(scip) > 0 && SCIPisFeasLT(scip, SCIPgetCutoffbound(scip), propdata->lastcutoff) )
1993 {
1994 if( propdata->ngindices > 0 )
1995 {
1996 SCIP_CALL( applyGenVBounds(scip, propdata->prop, TRUE, result, nchgbds) );
1998 }
1999
2000 /* within the tree, the objective function should not change anymore, hence the cutoff bound should be a stable
2001 * point of reference
2002 */
2003 propdata->lastcutoff = SCIPgetCutoffbound(scip);
2004 }
2005
2006 /* apply local propagation if allowed */
2007 if( local && *result != SCIP_CUTOFF )
2008 {
2009 /* check if local propagation in root node is allowed */
2010 if( SCIPgetDepth(scip) > 0 || propdata->propinrootnode )
2011 {
2012 /* if genvbounds are already sorted, check if bound change events were caught; otherwise apply all genvbounds */
2013 if( !propdata->issorted
2014 || ( SCIPnodeGetNumber(SCIPgetCurrentNode(scip)) == propdata->lastnodenumber && propdata->nindices > 0 ) )
2015 {
2016 SCIP_CALL( applyGenVBounds(scip, propdata->prop, FALSE, result, nchgbds) );
2018 }
2019 }
2020 }
2021
2022 return SCIP_OKAY;
2023}
2024
2025/* adds all genvbounds in the genvboundstore as constraints to the problem; afterwards clears the genvboundstore */
2026static
2028 SCIP* scip, /**< SCIP data structure */
2029 SCIP_PROP* prop, /**< genvbounds propagator */
2030 SCIP_PROPDATA* propdata /**< data of the genvbounds propagator */
2031 )
2032{
2033 int i;
2034
2035 assert(scip != NULL);
2036 assert(propdata != NULL);
2037 assert(propdata->propasconss);
2038
2039 /* ensure that the cutoffboundvar is available */
2040 if( propdata->cutoffboundvar == NULL )
2041 {
2042 SCIP_Real ub;
2043 char name[16];
2044
2045 /* set the upper bound to the best primal value in the original problem */
2047
2048 SCIPdebugMsg(scip, "initialize cutoffboundvar with UB = %e\n", ub);
2049
2050 (void) SCIPsnprintf(name, 16, "cutoffboundvar");
2051 SCIP_CALL( SCIPcreateVarBasic(scip, &propdata->cutoffboundvar, name, -SCIPinfinity(scip), ub, 0.0, SCIP_VARTYPE_CONTINUOUS) );
2052 SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, propdata->cutoffboundvar) );
2053
2054 SCIP_CALL( SCIPaddVar(scip, propdata->cutoffboundvar) );
2055
2056 /* lock the variable because it should not be subject to dual presolving reductions; because we create the
2057 * linear constraints as non-check constraints, the cutoffboundvar will not be locked by the linear constraint
2058 * handler
2059 */
2060 SCIP_CALL( SCIPaddVarLocksType(scip, propdata->cutoffboundvar, SCIP_LOCKTYPE_MODEL, 1, 1) );
2061 }
2062
2063 assert(propdata->cutoffboundvar != NULL);
2064
2065 /* now iterate over all genvbounds in the store and construct a linear constraint for each of them */
2066 for( i = 0; i < propdata->ngenvbounds; ++i )
2067 {
2068 GENVBOUND* genvbound;
2069 SCIP_CONS* cons;
2070 SCIP_VAR** vars;
2071 SCIP_Real* vals;
2072 char name[SCIP_MAXSTRLEN];
2073 int nvars;
2074 int j;
2075
2076 genvbound = propdata->genvboundstore[i];
2077 assert(genvbound != NULL);
2078
2079 nvars = genvbound->ncoefs + 2;
2082
2083 SCIPdebugMsgPrint(scip, "add cons: ");
2084
2085 /* copy the coefs/vars array */
2086 for( j = 0; j < genvbound->ncoefs; j++ )
2087 {
2088 vars[j] = genvbound->vars[j];
2089 vals[j] = genvbound->coefs[j];
2090 SCIPdebugMsgPrint(scip, "%e%s + ", vals[j], SCIPvarGetName(vars[j]));
2091 }
2092
2093 /* add the variable and the coefficient of the genvbound */
2094 vars[genvbound->ncoefs] = genvbound->var;
2095 vals[genvbound->ncoefs] = (genvbound->boundtype == SCIP_BOUNDTYPE_LOWER) ? -1.0 : 1.0;
2096
2097 SCIPdebugMsgPrint(scip, "%e%s + ", vals[genvbound->ncoefs], SCIPvarGetName(vars[genvbound->ncoefs]));
2098
2099 /* add cutoffcoef * cutoffboundvar */
2100 vars[genvbound->ncoefs + 1] = propdata->cutoffboundvar;
2101 vals[genvbound->ncoefs + 1] = genvbound->cutoffcoef;
2102
2103 SCIPdebugMsgPrint(scip, "%e%s <= %e\n", vals[genvbound->ncoefs + 1], SCIPvarGetName(vars[genvbound->ncoefs + 1]), -1.0*genvbound->constant);
2104
2105 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "genvbound_cons%d", genvbound->index);
2106
2107 /* create linear constraint with only propagate flag as TRUE */
2108 SCIP_CALL( SCIPcreateConsLinear(scip, &cons, name, nvars, vars, vals, -SCIPinfinity(scip), -genvbound->constant,
2110
2111 SCIP_CALL( SCIPaddCons(scip, cons) );
2112 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
2113
2114 /* free memory */
2116 SCIPfreeBufferArray(scip, &vals);
2117 }
2118
2119 /* now delete all genvbounds in the genvboundstore */
2120 if( propdata->genvboundstore != NULL )
2121 {
2122 /* disable genvbounds propagator */
2123 if( propdata->ngenvbounds >= 1 )
2125
2126 for( i = propdata->ngenvbounds - 1; i >= 0; i-- )
2127 {
2128 SCIP_CALL( freeGenVBound(scip, propdata->genvboundstore[i]) );
2129 }
2130
2131 /* free genvboundstore hashmaps */
2132 SCIPhashmapFree(&(propdata->lbgenvbounds));
2133 SCIPhashmapFree(&(propdata->ubgenvbounds));
2134
2135 /* drop and free all events */
2136 SCIP_CALL( dropAndFreeEvents(scip, propdata) );
2137
2138 /* free componentsstart array */
2139 SCIP_CALL( freeComponentsData(scip, propdata) );
2140
2141 /* free starting indices data */
2142 SCIP_CALL( freeStartingData(scip, propdata) );
2143
2144 SCIPfreeBlockMemoryArray(scip, &(propdata->genvboundstore), propdata->genvboundstoresize);
2145 propdata->genvboundstore = NULL;
2146 propdata->genvboundstoresize = 0;
2147 propdata->ngenvbounds = 0;
2148 }
2149
2150 return SCIP_OKAY;
2151}
2152
2153
2154
2155/*
2156 * Public methods
2157 */
2158
2159/** adds a generalized variable bound to the genvbounds propagator; if there is already a genvbound for the bound
2160 * "boundtype" of variable "var", it will be replaced
2161 */
2163 SCIP* scip, /**< SCIP data structure */
2164 SCIP_PROP* genvboundprop, /**< genvbound propagator */
2165 SCIP_VAR** vars, /**< array of RHSs variables */
2166 SCIP_VAR* var, /**< LHSs variable */
2167 SCIP_Real* coefs, /**< array of coefficients for the RHSs variables */
2168 int ncoefs, /**< size of coefs array */
2169 SCIP_Real coefcutoffbound, /**< nonpositive value of the cutoff bounds multiplier */
2170 SCIP_Real constant, /**< constant term */
2171 SCIP_BOUNDTYPE boundtype /**< type of bound provided by the genvbound */
2172 )
2173{
2174 /**@todo in debug mode: check if genvbound is nontrivial */
2175
2176 SCIP_PROPDATA* propdata;
2177 GENVBOUND* genvbound;
2178 SCIP_Bool newgenvbound;
2179 int i;
2180
2181 assert(scip != NULL);
2182 assert(genvboundprop != NULL);
2183 assert(vars != NULL);
2184 assert(var != NULL);
2185 assert(coefs != NULL);
2186 assert(ncoefs >= 0);
2187 assert(coefcutoffbound <= 0.0);
2188 assert(!SCIPisInfinity(scip, -constant));
2189
2191
2192 if( ncoefs < 0 || coefcutoffbound > 0.0 || SCIPisInfinity(scip, -constant) )
2193 {
2194 SCIPerrorMessage("cannot create generalized variable bound from invalid data\n");
2195 return SCIP_INVALIDDATA;
2196 }
2197
2198 propdata = SCIPpropGetData(genvboundprop);
2199 assert(propdata != NULL);
2200
2201 /* initialize propdata if not done yet */
2202 if( propdata->genvboundstore == NULL )
2203 {
2204 SCIP_CALL( initPropdata(scip, propdata) );
2205 }
2206
2207 genvbound = getGenVBound(scip, propdata, var, boundtype);
2208 newgenvbound = (genvbound == NULL);
2209
2210 /* release previous variables */
2211 if( !newgenvbound )
2212 {
2213 for( i = 0; i < genvbound->ncoefs; ++i )
2214 {
2215 assert(genvbound->vars[i] != NULL);
2216 SCIP_CALL( SCIPreleaseVar(scip, &(genvbound->vars[i])) );
2217 }
2218 }
2219
2220 /* check if there already is a genvbound corresponding to this bound, freeing its data and overwriting it */
2221 if( !newgenvbound && genvbound->ncoefs < ncoefs )
2222 {
2223 /* do not realloc since we do not want to keep and possibly copy the old entries */
2224 SCIPfreeBlockMemoryArray(scip, &(genvbound->coefs), genvbound->coefssize);
2225 SCIPfreeBlockMemoryArray(scip, &(genvbound->vars), genvbound->coefssize);
2226
2227 /* allocate and copy arrays in genvbound */
2228 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(genvbound->coefs), coefs, ncoefs) );
2229 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(genvbound->vars), vars, ncoefs) );
2230 genvbound->coefssize = ncoefs;
2231 }
2232 else if( !newgenvbound && genvbound->ncoefs == ncoefs )
2233 {
2234 /* just update entries */
2235 for( i = 0; i < ncoefs; i++ )
2236 {
2237 genvbound->coefs[i] = coefs[i];
2238 genvbound->vars[i] = vars[i];
2239 }
2240 }
2241 else if( !newgenvbound && genvbound->ncoefs > ncoefs )
2242 {
2243 /* reallocate memory for arrays in genvbound to free unused memory */
2244 if( genvbound->coefssize < ncoefs )
2245 {
2246 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(genvbound->coefs), genvbound->coefssize, ncoefs) );
2247 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(genvbound->vars), genvbound->coefssize, ncoefs) );
2248 genvbound->coefssize = ncoefs;
2249 }
2250
2251 /* update entries */
2252 for( i = 0; i < ncoefs; i++ )
2253 {
2254 genvbound->coefs[i] = coefs[i];
2255 genvbound->vars[i] = vars[i];
2256 }
2257 }
2258 else if( newgenvbound )
2259 {
2260 /* allocate memory for genvbound data */
2261 SCIP_CALL( SCIPallocBlockMemory(scip, &genvbound) );
2262
2263 /* allocate and copy arrays in genvbound */
2264 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(genvbound->coefs), coefs, ncoefs) );
2265 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(genvbound->vars), vars, ncoefs) );
2266 genvbound->coefssize = ncoefs;
2267 }
2268
2269 /* set up data for genvbound */
2270 genvbound->boundtype = boundtype;
2271 genvbound->var = var;
2272 genvbound->ncoefs = ncoefs;
2273 genvbound->constant = constant;
2274 genvbound->relaxonly = SCIPvarIsRelaxationOnly(genvbound->var);
2275
2276 /* capture variables and check for relax-only vars */
2277 for( i = 0; i < genvbound->ncoefs; ++i )
2278 {
2279 assert(genvbound->vars[i] != NULL);
2280 SCIP_CALL( SCIPcaptureVar(scip, genvbound->vars[i]) );
2281 if( SCIPvarIsRelaxationOnly(genvbound->vars[i]) )
2282 genvbound->relaxonly = TRUE;
2283 }
2284 if( newgenvbound )
2285 {
2286 assert(genvbound->var != NULL);
2287 SCIP_CALL( SCIPcaptureVar(scip, genvbound->var) );
2288 }
2289
2290 /* the cutoff bound is valid w.r.t. the current objective function in the transformed problem; during presolving,
2291 * however, the objective function can change (e.g., when a variable is fixed, its contribution in the objective
2292 * is subtracted from the cutoff bound and added to the objective offset); we solve this by transforming the
2293 * contribution of the cutoff bound in the generalized variable bound to the original problem as follows:
2294 *
2295 * +/- var >= ... + z * SCIPgetCutoffbound() + constant
2296 *
2297 * becomes
2298 *
2299 * +/- var >= ... + (z / SCIPgetTransObjscale()) * origcutoffbound + (constant - z * SCIPgetTransObjoffset())
2300 *
2301 * with SCIPgetCutoffbound() = origcutoffbound / SCIPgetTransObjscale() - SCIPgetTransObjoffset(); in the
2302 * propagation later, we will use (SCIPgetCutoffbound() + SCIPgetTransObjoffset()) * SCIPgetTransObjscale(), see
2303 * function getCutoffboundGenVBound()
2304 */
2305 if( SCIPisNegative(scip, coefcutoffbound) )
2306 {
2308 genvbound->cutoffcoef = coefcutoffbound / SCIPgetTransObjscale(scip);
2309 genvbound->constant -= (coefcutoffbound * SCIPgetTransObjoffset(scip));
2310 }
2311 else
2312 genvbound->cutoffcoef = 0.0;
2313
2314 /* if genvbound is not overwritten, create a new entry in genvboundstore */
2315 if( newgenvbound )
2316 {
2317 SCIP_CALL( addNewGenVBound(scip, genvboundprop, propdata, genvbound) );
2318 }
2319
2320 /* mark genvbounds array to be re-sorted */
2321 propdata->issorted = FALSE;
2322
2323 /* debug message */
2324 SCIPdebugMsg(scip, "added genvbound ");
2325 SCIPdebug( printGenVBound(scip, genvbound) );
2326#ifdef WITH_DEBUG_SOLUTION
2327 SCIP_CALL( checkDebugSolutionGenVBound(scip, genvbound) );
2328#endif
2329
2330 return SCIP_OKAY;
2331}
2332
2333
2334/*
2335 * Callback methods of propagator
2336 */
2337
2338/** copy method for propagator plugins (called when SCIP copies plugins)
2339 *
2340 * @note The UG framework assumes that all default plug-ins of SCIP implement a copy callback.
2341 */
2342static
2343SCIP_DECL_PROPCOPY(propCopyGenvbounds)
2344{ /*lint --e{715}*/
2345 assert(scip != NULL);
2346 assert(prop != NULL);
2347
2349
2350 /* call inclusion method of constraint handler */
2352
2353 return SCIP_OKAY;
2354}
2355
2356/** initialization method of propagator (called after problem was transformed) */
2357static
2358SCIP_DECL_PROPINIT(propInitGenvbounds)
2359{ /*lint --e{715}*/
2360 SCIP_PROPDATA* propdata;
2361
2362 assert(scip != NULL);
2363 assert(prop != NULL);
2364
2366
2367 /* get propagator data */
2368 propdata = SCIPpropGetData(prop);
2369 assert(propdata != NULL);
2370
2371 propdata->genvboundstore = NULL;
2372 propdata->genvboundstoresize = 0;
2373 propdata->lbevents = NULL;
2374 propdata->ubevents = NULL;
2375 propdata->lbgenvbounds = NULL;
2376 propdata->ubgenvbounds = NULL;
2377 propdata->lbeventsmap = NULL;
2378 propdata->ubeventsmap = NULL;
2379 propdata->startmap = NULL;
2380 propdata->componentsstart = NULL;
2381 propdata->startindices = NULL;
2382 propdata->startcomponents = NULL;
2383 propdata->gstartindices = NULL;
2384 propdata->gstartcomponents = NULL;
2385 propdata->lastcutoff = SCIPinfinity(scip);
2386 propdata->lastnodenumber = -1;
2387 propdata->cutoffboundvar = NULL;
2388 propdata->ngenvbounds = -1;
2389 propdata->ncomponents = -1;
2390 propdata->nindices = -1;
2391 propdata->ngindices = -1;
2392 propdata->nlbevents = -1;
2393 propdata->nubevents = -1;
2394 propdata->issorted = FALSE;
2395
2396 propdata->prop = prop;
2397
2398 /* store genvbounds timing */
2399 propdata->inittiming = SCIPpropGetTimingmask(prop);
2400
2401 /* disable genvbounds propagator, enabled when genvbounds are added */
2403
2404 return SCIP_OKAY;
2405}
2406
2407
2408/** presolving method of propagator */
2409static
2410SCIP_DECL_PROPPRESOL(propPresolGenvbounds)
2411{ /*lint --e{715}*/
2412 SCIP_PROPDATA* propdata;
2413
2414 assert(scip != NULL);
2415 assert(prop != NULL);
2416 assert(result != NULL);
2417
2419
2421
2422 /* get propagator data */
2423 propdata = SCIPpropGetData(prop);
2424 assert(propdata != NULL);
2425
2426 /* do not run if no genvbounds were added yet */
2427 if( propdata->ngenvbounds < 1 )
2428 return SCIP_OKAY;
2429
2431 return SCIP_OKAY;
2432
2433 SCIPdebugMsg(scip, "proppresol in problem <%s>\n", SCIPgetProbName(scip));
2434
2435 /* propagate */
2436 SCIP_CALL( execGenVBounds(scip, propdata, result, TRUE, nchgbds) );
2437
2438 return SCIP_OKAY;
2439}
2440
2441
2442/** presolving initialization method of propagator (called when presolving is about to begin) */
2443static
2444SCIP_DECL_PROPINITPRE(propInitpreGenvbounds)
2445{ /*lint --e{715}*/
2446 SCIP_PROPDATA* propdata;
2447
2448 assert(scip != NULL);
2449 assert(prop != NULL);
2450
2452
2453 /* get propagator data */
2454 propdata = SCIPpropGetData(prop);
2455 assert(propdata != NULL);
2456
2457 /* lock the variable because it should not be deleted after a restart */
2458 if( propdata->cutoffboundvar != NULL )
2459 {
2460 SCIPdebugMsg(scip, "propinitpre in problem <%s>: locking cutoffboundvar (current downlocks=%d, uplocks=%d)\n",
2462 SCIPvarGetNLocksUpType(propdata->cutoffboundvar, SCIP_LOCKTYPE_MODEL));
2463
2464 SCIP_CALL( SCIPaddVarLocksType(scip, propdata->cutoffboundvar, SCIP_LOCKTYPE_MODEL, 1, 1) );
2465 }
2466
2467 return SCIP_OKAY;
2468}
2469
2470
2471/** presolving deinitialization method of propagator (called after presolving has been finished) */
2472static
2473SCIP_DECL_PROPEXITPRE(propExitpreGenvbounds)
2474{ /*lint --e{715}*/
2475 SCIP_VAR** vars;
2476 SCIP_PROPDATA* propdata;
2477 int i;
2478
2479 assert(scip != NULL);
2480 assert(prop != NULL);
2481
2483
2484 SCIPdebugMsg(scip, "propexitpre in problem <%s>: removing fixed, aggregated, negated, and multi-aggregated variables from right-hand side\n",
2486
2487 /* get propagator data */
2488 propdata = SCIPpropGetData(prop);
2489 assert(propdata != NULL);
2490
2491 /* there should be no events on the right-hand side variables */
2492 assert(propdata->lbevents == NULL);
2493 assert(propdata->ubevents == NULL);
2494
2495 /* allocate memory to store new variables */
2497
2498 for( i = 0; i < propdata->ngenvbounds; )
2499 {
2500 GENVBOUND* genvbound;
2501 int requiredsize;
2502 int nvars;
2503 int j;
2504
2505 genvbound = propdata->genvboundstore[i];
2506 assert(genvbound != NULL);
2507
2508 /* store variables of the genvbound to release them properly */
2509 assert(genvbound->ncoefs <= SCIPgetNTotalVars(scip));
2510 BMScopyMemoryArray(vars, genvbound->vars, genvbound->ncoefs);
2511 nvars = genvbound->ncoefs;
2512
2513 /* replace non-active by active variables and update constant; note that this may result in coefficients where
2514 * SCIPisZero() is true; this should not create any problems
2515 */
2516 SCIP_CALL( SCIPgetProbvarLinearSum(scip, genvbound->vars, genvbound->coefs, &genvbound->ncoefs, genvbound->ncoefs, &genvbound->constant, &requiredsize) );
2517
2518 /* if space was not enough we need to resize the buffers */
2519 if( requiredsize > genvbound->ncoefs )
2520 {
2521 /* reallocate memory for arrays in genvbound to free unused memory */
2522 if( genvbound->coefssize < requiredsize )
2523 {
2524 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(genvbound->coefs), genvbound->coefssize, requiredsize) );
2525 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(genvbound->vars), genvbound->coefssize, requiredsize) );
2526 genvbound->coefssize = requiredsize;
2527 }
2528
2529 SCIP_CALL( SCIPgetProbvarLinearSum(scip, genvbound->vars, genvbound->coefs, &genvbound->ncoefs, requiredsize, &genvbound->constant, &requiredsize) );
2530 assert(requiredsize <= genvbound->coefssize);
2531 }
2532 assert(requiredsize == genvbound->ncoefs);
2533
2534 /* capture new and release old variables */
2535 for( j = 0; j < genvbound->ncoefs; ++j )
2536 {
2537 assert(genvbound->vars[j] != NULL);
2538 SCIP_CALL( SCIPcaptureVar(scip, genvbound->vars[j]) );
2539 }
2540 for( j = 0; j < nvars; ++j )
2541 {
2542 assert(vars[j] != NULL);
2544 }
2545
2546 /* if the resulting genvbound is trivial, remove it */
2547 /* we remove all genvbounds with an aggregated or multi-aggregated genvbound->var; tightening aggregated variables
2548 * might lead to some asserts in tree.c if the active variable has been already tightened (see !398);
2549 *
2550 * @todo replace aggregated variable by their active part
2551 */
2552 if( (genvbound->ncoefs == 0 && SCIPisZero(scip, genvbound->cutoffcoef))
2555 {
2556 SCIP_HASHMAP* hashmap;
2557
2558 hashmap = genvbound->boundtype == SCIP_BOUNDTYPE_LOWER ? propdata->lbgenvbounds : propdata->ubgenvbounds;
2559
2560 /* remove genvbound from hashmap */
2561 assert(SCIPhashmapExists(hashmap, genvbound->var));
2562 SCIP_CALL( SCIPhashmapRemove(hashmap, genvbound->var) );
2563
2564 /* free genvbound and fill gap */
2565 SCIP_CALL( freeGenVBound(scip, propdata->genvboundstore[i]) );
2566 --(propdata->ngenvbounds);
2567
2568 /* move the last genvbound to the i-th position */
2569 if( i < propdata->ngenvbounds )
2570 {
2571 propdata->genvboundstore[i] = propdata->genvboundstore[propdata->ngenvbounds];
2572 propdata->genvboundstore[i]->index = i;
2573
2574 /* mark genvbounds array to be re-sorted */
2575 propdata->issorted = FALSE;
2576 }
2577 }
2578 else
2579 ++i;
2580 }
2581
2583
2584 /* disable genvbounds propagator */
2585 if( propdata->ngenvbounds == 0 )
2587
2588 return SCIP_OKAY;
2589}
2590
2591/** deinitialization method of propagator (called before transformed problem is freed) */
2592static
2593SCIP_DECL_PROPEXIT(propExitGenvbounds)
2594{
2595 SCIP_PROPDATA* propdata;
2596
2597 assert(scip != NULL);
2598 assert(prop != NULL);
2599
2601
2602 /* get propagator data */
2603 propdata = SCIPpropGetData(prop);
2604 assert(propdata != NULL);
2605
2606 /* free remaining genvbounds */
2607 SCIP_CALL( freeGenVBounds(scip, prop, propdata) );
2608
2609 /* reset genvbounds timing */
2610 SCIPpropSetTimingmask(prop, propdata->inittiming);
2611
2612 return SCIP_OKAY;
2613}
2614
2615/** execution method of propagator */
2616static
2617SCIP_DECL_PROPEXEC(propExecGenvbounds)
2618{ /*lint --e{715}*/
2619 SCIP_PROPDATA* propdata;
2620
2621 assert(scip != NULL);
2622 assert(prop != NULL);
2623 assert(result != NULL);
2624
2626
2628
2629 /* get propagator data */
2630 propdata = SCIPpropGetData(prop);
2631 assert(propdata != NULL);
2632 assert(propdata->ngenvbounds >= 1);
2633
2634 /* do not run if propagation w.r.t. current objective is not allowed */
2636 return SCIP_OKAY;
2637
2638 /* update upper bound of the cutoffboundvar */
2639 if( propdata->cutoffboundvar != NULL )
2640 {
2641 SCIP_Real newub;
2642 SCIP_Real oldub;
2643 SCIP_Bool infeasible;
2644 SCIP_Bool tightened;
2645
2646 assert(propdata->propasconss);
2647
2648 /* compute the primal bound in the original problem */
2650 oldub = SCIPvarGetUbLocal(propdata->cutoffboundvar);
2651
2652 if( SCIPisInfinity(scip, newub) == FALSE && SCIPisFeasLT(scip, newub, oldub) )
2653 {
2654 SCIP_CALL( SCIPtightenVarUbGlobal(scip, propdata->cutoffboundvar, newub, FALSE, &infeasible, &tightened) );
2655
2656 if( tightened )
2657 {
2658 SCIPdebugMsg(scip, "tightened UB of cutoffboundvar to %e (old: %e, infeas: %u, tightened: %u)\n",
2659 newub, oldub, infeasible, tightened);
2660 }
2661
2662 assert(infeasible == FALSE);
2663 }
2664 }
2665
2666 SCIPdebugMsg(scip, "propexec in problem <%s> at depth %d%s\n", SCIPgetProbName(scip), SCIPgetDepth(scip),
2667 SCIPinProbing(scip) ? " in probing" : "");
2668
2669 /* add the genvbounds in the genvboundstore as constraints to the problem; afterwards clear the genvboundstore */
2670 if( propdata->propasconss )
2671 {
2672 SCIP_CALL( createConstraints(scip, prop, propdata) );
2673 return SCIP_OKAY;
2674 }
2675
2676 /* propagate locally and globally */
2678
2679 /* when called in presolving stage the result is set to SCIP_SUCCESS instead of SCIP_REDUCEDDOM, this is corrected
2680 * here
2681 */
2682 if( *result == SCIP_SUCCESS )
2684
2685 SCIPdebugMsg(scip, "end of exec\n");
2686
2687 return SCIP_OKAY;
2688}
2689
2690/** propagation conflict resolving method of propagator */
2691static
2692SCIP_DECL_PROPRESPROP(propRespropGenvbounds)
2693{ /*lint --e{715}*/
2694 SCIP_PROPDATA* propdata;
2695 GENVBOUND* genvbound;
2696 SCIP_Real boundval;
2697 SCIP_Bool success;
2698
2699 SCIPdebugMsg(scip, "explain %s bound change of variable <%s>\n",
2700 boundtype == SCIP_BOUNDTYPE_LOWER ? "lower" : "upper", SCIPvarGetName(infervar));
2701
2702 /* get propagator data */
2703 propdata = SCIPpropGetData(prop);
2704 assert(propdata != NULL);
2705 assert(propdata->genvboundstore != NULL);
2706
2707 /* as inferinfo we passed the index of the genvbound that was used for propagation; the genvbound might have been
2708 * replaced, but also the new genvbound at this position has the same variable on the left-hand side
2709 */
2710 assert(inferinfo >= 0);
2711 assert(inferinfo < propdata->ngenvbounds);
2712
2714
2715 /* check also in optimized mode that inferinfo is correct */
2716 if( inferinfo >= propdata->ngenvbounds)
2717 {
2718 SCIPerrorMessage("generalized variable bounds propagator received inferinfo out of range; propagation not resolved, safe to continue\n");
2719 return SCIP_OKAY;
2720 }
2721
2722 /* get genvbound responsible for the bound change */
2723 genvbound = propdata->genvboundstore[inferinfo];
2724 assert(genvbound != NULL);
2725 assert(genvbound->var == infervar);
2726
2727 /* check also in optimized mode that inferinfo is correct */
2728 if( genvbound->var != infervar )
2729 {
2730 SCIPerrorMessage("generalized variable bounds propagator received incorrect inferinfo; propagation not resolved, but it's safe to continue\n");
2731 return SCIP_OKAY;
2732 }
2733
2734 /* get value of bound change on left-hand side */
2735 boundval = genvbound->boundtype == SCIP_BOUNDTYPE_LOWER
2736 ? SCIPgetVarLbAtIndex(scip, genvbound->var, bdchgidx, TRUE)
2737 : -SCIPgetVarUbAtIndex(scip, genvbound->var, bdchgidx, TRUE);
2738
2739 /* if left-hand side variable is integral, it suffices to explain a bound change greater than boundval - 1 */
2740 if( SCIPvarIsIntegral(genvbound->var) )
2741 {
2742 SCIP_Real roundedboundval;
2743
2744 assert(SCIPisIntegral(scip, boundval));
2745
2746 roundedboundval = SCIPfeasCeil(scip, boundval - 1.0) + 2 * SCIPfeastol(scip);
2747 boundval = MIN(boundval, roundedboundval);
2748 }
2749
2750 /* resolve propagation */
2751 SCIP_CALL( resolveGenVBoundPropagation(scip, genvbound, bdchgidx, &boundval, &success) );
2752
2753 if( success )
2755
2756 return SCIP_OKAY;
2757}
2758
2759/** solving process deinitialization method of propagator (called before branch and bound process data is freed) */
2760static
2761SCIP_DECL_PROPEXITSOL(propExitsolGenvbounds)
2762{ /*lint --e{715}*/
2763 SCIP_PROPDATA* propdata;
2764
2765 assert(scip != NULL);
2766 assert(prop != NULL);
2767
2769
2770 SCIPdebugMsg(scip, "propexitsol in problem <%s>\n", SCIPgetProbName(scip));
2771
2772 /* get propagator data */
2773 propdata = SCIPpropGetData(prop);
2774 assert(propdata != NULL);
2775
2776 if( !SCIPisInRestart(scip) )
2777 {
2778 /* free all genvbounds if we are not in a restart */
2779 SCIP_CALL( freeGenVBounds(scip, prop, propdata) );
2780 }
2781 else
2782 {
2783 /* free all genvbounds that use relax-only variables if we are in a restart */
2784 SCIP_CALL( freeGenVBoundsRelaxOnly(scip, prop, propdata) );
2785 }
2786
2787 /* drop and free all events */
2788 SCIP_CALL( dropAndFreeEvents(scip, propdata) );
2789
2790 return SCIP_OKAY;
2791}
2792
2793/** destructor of propagator to free user data (called when SCIP is exiting) */
2794static
2795SCIP_DECL_PROPFREE(propFreeGenvbounds)
2796{ /*lint --e{715}*/
2797 SCIP_PROPDATA* propdata;
2798
2800
2801 /* free propagator data */
2802 propdata = SCIPpropGetData(prop);
2803 assert(propdata != NULL);
2804
2805 SCIPfreeBlockMemory(scip, &propdata);
2806
2807 SCIPpropSetData(prop, NULL);
2808
2809 return SCIP_OKAY;
2810}
2811
2812
2813/*
2814 * Callback methods of event handler
2815 */
2816
2817static
2818SCIP_DECL_EVENTEXEC(eventExecGenvbounds)
2819{ /*lint --e{715}*/
2820 SCIP_PROPDATA* propdata;
2822 int i;
2823
2826 assert(eventdata != NULL);
2827 assert(eventdata->startcomponents != NULL);
2828 assert(eventdata->startindices != NULL);
2829 assert(eventdata->nstarts > 0);
2830 assert(eventdata->prop != NULL);
2831
2832 /* ignore final events */
2833 if( node == NULL )
2834 return SCIP_OKAY;
2835
2836 propdata = SCIPpropGetData(eventdata->prop);
2837 assert(propdata != NULL);
2838
2839 assert(propdata->startcomponents != NULL);
2840 assert(propdata->startmap != NULL);
2841 assert(propdata->startindices != NULL);
2842
2843 SCIPdebugMsg(scip, "catching eventdata:\n");
2844 SCIPdebug( printEventData(eventdata, SCIPeventGetType(event) == SCIP_EVENTTYPE_LBTIGHTENED ?
2846
2847 /**@todo find a way to identify when we are at a new probing node; in probing mode, the node number is always zero,
2848 * so we may miss resetting the starting data and may propagate more than necessary
2849 */
2850 /* check if we need to reset old local starting indices data */
2851 if( SCIPnodeGetNumber(node) != propdata->lastnodenumber )
2852 {
2854 propdata->lastnodenumber = SCIPnodeGetNumber(node);
2855 }
2856
2857 for( i = 0; i < eventdata->nstarts; i++ )
2858 {
2859 int component;
2860 int startidx;
2861
2862 component = eventdata->startcomponents[i];
2863 assert(component >= 0);
2864 startidx = eventdata->startindices[i];
2865
2866 /* there is already an entry for this component */
2867 if( SCIPhashmapExists(propdata->startmap, (void*)(size_t) (component + 1)) )
2868 {
2869 int componentidx;
2870
2871 /* get its index */
2872 componentidx = (SCIPhashmapGetImageInt(propdata->startmap, (void*)(size_t) (component + 1))) - 1; /*lint !e571 !e776*/
2873 assert(componentidx >= 0);
2874 assert(propdata->startcomponents[componentidx] == component);
2875
2876 if( propdata->startindices[componentidx] > startidx )
2877 propdata->startindices[componentidx] = startidx;
2878 }
2879 else
2880 {
2881 /* get a new entry */
2882 int componentidx;
2883 componentidx = propdata->nindices;
2884
2885 /* store index */
2886 propdata->startcomponents[componentidx] = component;
2887 propdata->startindices[componentidx] = startidx;
2888
2889 /* store component in hashmap */
2890 SCIP_CALL( SCIPhashmapInsertInt(propdata->startmap, (void*)(size_t) (component + 1), componentidx + 1) ); /*lint !e571 !e776*/
2891
2892 /* increase number of starting indices */
2893 propdata->nindices++;
2894 }
2895 }
2896
2897 return SCIP_OKAY;
2898}
2899
2900/*
2901 * propagator specific interface methods
2902 */
2903
2904/** creates the genvbounds propagator and includes it in SCIP */
2906 SCIP* scip /**< SCIP data structure */
2907 )
2908{
2909 SCIP_PROPDATA* propdata;
2910 SCIP_PROP* prop;
2911
2912 /* create genvbounds propagator data */
2913 SCIP_CALL( SCIPallocBlockMemory(scip, &propdata) );
2914 propdata->inittiming = PROP_TIMING;
2915
2916 /* include propagator */
2918 propExecGenvbounds, propdata) );
2919
2920 SCIP_CALL( SCIPsetPropCopy(scip, prop, propCopyGenvbounds) );
2921 SCIP_CALL( SCIPsetPropFree(scip, prop, propFreeGenvbounds) );
2922 SCIP_CALL( SCIPsetPropInit(scip, prop, propInitGenvbounds) );
2923 SCIP_CALL( SCIPsetPropInitpre(scip, prop, propInitpreGenvbounds) );
2924 SCIP_CALL( SCIPsetPropExitpre(scip, prop, propExitpreGenvbounds) );
2925 SCIP_CALL( SCIPsetPropExit(scip, prop, propExitGenvbounds) );
2926 SCIP_CALL( SCIPsetPropExitsol(scip, prop, propExitsolGenvbounds) );
2927 SCIP_CALL( SCIPsetPropPresol(scip, prop, propPresolGenvbounds, PROP_PRESOL_PRIORITY,
2929 SCIP_CALL( SCIPsetPropResprop(scip, prop, propRespropGenvbounds) );
2930
2931 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/global",
2932 "apply global propagation?",
2933 &propdata->global, TRUE, DEFAULT_GLOBAL_PROPAGATION, NULL, NULL) );
2934
2935 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/propinrootnode",
2936 "apply genvbounds in root node if no new incumbent was found?",
2937 &propdata->propinrootnode, TRUE, DEFAULT_PROPAGATE_IN_ROOT_NODE, NULL, NULL) );
2938
2939 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/sort",
2940 "sort genvbounds and wait for bound change events?",
2941 &propdata->sort, TRUE, DEFAULT_SORT, NULL, NULL) );
2942
2943 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/propasconss",
2944 "should genvbounds be transformed to (linear) constraints?",
2945 &propdata->propasconss, TRUE, DEFAULT_PROPASCONSS, NULL, NULL) );
2946
2947 /* include event handler */
2948 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &propdata->eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecGenvbounds, NULL) );
2949
2950 return SCIP_OKAY;
2951}
static long bound
#define EVENTHDLR_NAME
#define EVENTHDLR_DESC
Constraint handler for linear constraints in their most general form, .
methods for debugging
#define SCIPdebugCheckLbGlobal(scip, var, lb)
Definition debug.h:299
#define SCIPdebugGetSolVal(scip, var, val)
Definition debug.h:313
#define SCIPdebugCheckUbGlobal(scip, var, ub)
Definition debug.h:300
#define NULL
Definition def.h:257
#define SCIP_MAXSTRLEN
Definition def.h:278
#define SCIP_Longint
Definition def.h:150
#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 SCIP_UNKNOWN
Definition def.h:188
#define TRUE
Definition def.h:102
#define FALSE
Definition def.h:103
#define MAX(x, y)
Definition def.h:229
#define REALABS(x)
Definition def.h:191
#define SCIP_CALL(x)
Definition def.h:364
#define nnodes
Definition gastrans.c:74
SCIP_RETCODE SCIPcreateConsLinear(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)
SCIP_RETCODE SCIPdigraphComputeUndirectedComponents(SCIP_DIGRAPH *digraph, int minsize, int *components, int *ncomponents)
Definition misc.c:8165
int SCIPdigraphGetNNodes(SCIP_DIGRAPH *digraph)
Definition misc.c:7823
void SCIPdigraphGetComponent(SCIP_DIGRAPH *digraph, int compidx, int **nodes, int *nnodes)
Definition misc.c:8374
SCIP_RETCODE SCIPdigraphAddArc(SCIP_DIGRAPH *digraph, int startnode, int endnode, void *data)
Definition misc.c:7739
SCIP_RETCODE SCIPdigraphTopoSortComponents(SCIP_DIGRAPH *digraph)
Definition misc.c:8295
SCIP_RETCODE SCIPdigraphComputeDirectedComponents(SCIP_DIGRAPH *digraph, int compidx, int *strongcomponents, int *strongcompstartidx, int *nstrongcomponents)
Definition misc.c:8506
void SCIPdigraphFree(SCIP_DIGRAPH **digraph)
Definition misc.c:7645
int SCIPdigraphGetNComponents(SCIP_DIGRAPH *digraph)
Definition misc.c:8361
SCIP_RETCODE SCIPcreateDigraph(SCIP *scip, SCIP_DIGRAPH **digraph, int nnodes)
SCIP_STAGE SCIPgetStage(SCIP *scip)
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition scip_prob.c:1907
const char * SCIPgetProbName(SCIP *scip)
Definition scip_prob.c:1242
SCIP_Real SCIPgetTransObjoffset(SCIP *scip)
Definition scip_prob.c:1606
int SCIPgetNVars(SCIP *scip)
Definition scip_prob.c:2246
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition scip_prob.c:3274
int SCIPgetNFixedVars(SCIP *scip)
Definition scip_prob.c:2705
int SCIPgetNTotalVars(SCIP *scip)
Definition scip_prob.c:3064
SCIP_Real SCIPgetTransObjscale(SCIP *scip)
Definition scip_prob.c:1629
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition misc.c:3095
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3304
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3284
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition misc.c:3143
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 SCIPhashmapRemoveAll(SCIP_HASHMAP *hashmap)
Definition misc.c:3676
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3482
#define SCIPdebugMsgPrint
#define SCIPdebugMsg
SCIP_RETCODE SCIPgenVBoundAdd(SCIP *scip, SCIP_PROP *genvboundprop, SCIP_VAR **vars, SCIP_VAR *var, SCIP_Real *coefs, int ncoefs, SCIP_Real coefcutoffbound, SCIP_Real constant, SCIP_BOUNDTYPE boundtype)
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
SCIP_RETCODE SCIPincludePropGenvbounds(SCIP *scip)
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
SCIP_RETCODE SCIPaddConflictRelaxedLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedlb)
SCIP_RETCODE SCIPanalyzeConflict(SCIP *scip, int validdepth, SCIP_Bool *success)
SCIP_RETCODE SCIPaddConflictRelaxedUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedub)
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
SCIP_Real SCIPgetConflictVarUb(SCIP *scip, SCIP_VAR *var)
SCIP_Real SCIPgetConflictVarLb(SCIP *scip, SCIP_VAR *var)
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition scip_cons.c:1173
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
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition scip_mem.h:110
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition scip_mem.c:57
#define SCIPallocBufferArray(scip, ptr, num)
Definition scip_mem.h:124
#define SCIPfreeBufferArray(scip, ptr)
Definition scip_mem.h:136
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition scip_mem.h:93
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition scip_mem.h:99
#define SCIPfreeBlockMemory(scip, ptr)
Definition scip_mem.h:108
#define SCIPallocBlockMemory(scip, ptr)
Definition scip_mem.h:89
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition scip_mem.h:105
SCIP_Longint SCIPnodeGetNumber(SCIP_NODE *node)
Definition tree.c:8513
SCIP_Bool SCIPinProbing(SCIP *scip)
SCIP_RETCODE SCIPsetPropInitpre(SCIP *scip, SCIP_PROP *prop,)
Definition scip_prop.c:251
void SCIPpropSetData(SCIP_PROP *prop, SCIP_PROPDATA *propdata)
Definition prop.c:801
SCIP_RETCODE SCIPsetPropExitpre(SCIP *scip, SCIP_PROP *prop,)
Definition scip_prop.c:267
SCIP_RETCODE SCIPsetPropCopy(SCIP *scip, SCIP_PROP *prop,)
Definition scip_prop.c:155
SCIP_PROPDATA * SCIPpropGetData(SCIP_PROP *prop)
Definition prop.c:791
SCIP_RETCODE SCIPsetPropPresol(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPPRESOL((*proppresol)), int presolpriority, int presolmaxrounds, SCIP_PRESOLTIMING presoltiming)
Definition scip_prop.c:283
SCIP_RETCODE SCIPsetPropExitsol(SCIP *scip, SCIP_PROP *prop,)
Definition scip_prop.c:235
const char * SCIPpropGetName(SCIP_PROP *prop)
Definition prop.c:951
void SCIPpropSetTimingmask(SCIP_PROP *prop, SCIP_PROPTIMING timingmask)
Definition prop.c:1296
SCIP_RETCODE SCIPsetPropResprop(SCIP *scip, SCIP_PROP *prop,)
Definition scip_prop.c:316
SCIP_RETCODE SCIPsetPropFree(SCIP *scip, SCIP_PROP *prop,)
Definition scip_prop.c:171
SCIP_RETCODE SCIPsetPropInit(SCIP *scip, SCIP_PROP *prop,)
Definition scip_prop.c:187
SCIP_RETCODE SCIPsetPropExit(SCIP *scip, SCIP_PROP *prop,)
Definition scip_prop.c:203
SCIP_RETCODE SCIPincludePropBasic(SCIP *scip, SCIP_PROP **propptr, const char *name, const char *desc, int priority, int freq, SCIP_Bool delay, SCIP_PROPTIMING timingmask, SCIP_DECL_PROPEXEC((*propexec)), SCIP_PROPDATA *propdata)
Definition scip_prop.c:118
SCIP_PROPTIMING SCIPpropGetTimingmask(SCIP_PROP *prop)
Definition prop.c:1286
SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
Definition scip_sol.c:2003
SCIP_Bool SCIPisInRestart(SCIP *scip)
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
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 SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPfeastol(SCIP *scip)
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_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int SCIPgetDepth(SCIP *scip)
Definition scip_tree.c:672
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition scip_tree.c:91
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition var.c:23674
SCIP_RETCODE SCIPinferVarUbProp(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_PROP *inferprop, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:7699
SCIP_RETCODE SCIPtightenVarUbGlobal(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:8257
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition var.c:23418
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition var.c:4380
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition var.c:24300
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition var.c:24174
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition scip_var.c:5118
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition scip_var.c:2872
const char * SCIPvarGetName(SCIP_VAR *var)
Definition var.c:23299
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition scip_var.c:1887
SCIP_RETCODE SCIPgetProbvarLinearSum(SCIP *scip, SCIP_VAR **vars, SCIP_Real *scalars, int *nvars, int varssize, SCIP_Real *constant, int *requiredsize)
Definition scip_var.c:2378
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition var.c:23522
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition var.c:24266
SCIP_Bool SCIPvarIsRelaxationOnly(SCIP_VAR *var)
Definition var.c:23632
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition var.c:24152
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition scip_var.c:11057
SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition scip_var.c:2736
SCIP_RETCODE SCIPcreateVarBasic(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype)
Definition scip_var.c:184
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition var.c:4322
SCIP_Bool SCIPallowWeakDualReds(SCIP *scip)
Definition scip_var.c:10998
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 SCIPtightenVarLbGlobal(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:8026
SCIP_RETCODE SCIPinferVarLbProp(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_PROP *inferprop, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:7584
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition misc.c:10827
return SCIP_OKAY
assert(minobj< SCIPgetCutoffbound(scip))
int nvars
SCIP_VAR * var
static SCIP_VAR ** vars
memory allocation routines
#define BMScopyMemoryArray(ptr, source, num)
Definition memory.h:134
#define BMSclearMemoryArray(ptr, num)
Definition memory.h:130
#define PROP_PRESOL_MAXROUNDS
#define PROP_PRESOLTIMING
#define PROP_DESC
#define PROP_NAME
#define PROP_DELAY
#define PROP_TIMING
#define PROP_FREQ
#define PROP_PRIORITY
#define PROP_PRESOL_PRIORITY
static SCIP_RETCODE addEventData(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_VAR *var, int startindex, int startcomponent, SCIP_BOUNDTYPE boundtype)
static SCIP_RETCODE freeComponentsData(SCIP *scip, SCIP_PROPDATA *propdata)
#define DEFAULT_PROPAGATE_IN_ROOT_NODE
static SCIP_RETCODE analyzeGenVBoundConflict(SCIP *scip, GENVBOUND *genvbound)
static SCIP_RETCODE freeGenVBoundsRelaxOnly(SCIP *scip, SCIP_PROP *prop, SCIP_PROPDATA *propdata)
static SCIP_RETCODE execGenVBounds(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_RESULT *result, SCIP_Bool local, int *nchgbds)
static SCIP_Real getGenVBoundsMinActivityConflict(SCIP *scip, SCIP_VAR **vars, SCIP_Real *coefs, int nvars, SCIP_BDCHGIDX *bdchgidx)
static SCIP_Real getGenVBoundsMinActivity(SCIP *scip, SCIP_VAR **vars, SCIP_Real *coefs, int nvars, SCIP_Bool global)
static SCIP_Real getGenVBoundsBound(SCIP *scip, GENVBOUND *genvbound, SCIP_Bool global)
static SCIP_RETCODE freeEventData(SCIP *scip, SCIP_EVENTDATA **eventdata)
static SCIP_RETCODE dropAndFreeEvents(SCIP *scip, SCIP_PROPDATA *propdata)
#define DEFAULT_PROPASCONSS
static SCIP_RETCODE setUpEvents(SCIP *scip, SCIP_PROPDATA *propdata)
static SCIP_RETCODE sortGenVBounds(SCIP *scip, SCIP_PROPDATA *propdata)
#define DEFAULT_SORT
static SCIP_RETCODE fillGlobalStartingData(SCIP *scip, SCIP_PROPDATA *propdata)
static SCIP_RETCODE resetLocalStartingData(SCIP *scip, SCIP_PROPDATA *propdata)
static GENVBOUND * getGenVBound(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_VAR *var, SCIP_BOUNDTYPE boundtype)
static SCIP_RETCODE freeGenVBound(SCIP *scip, GENVBOUND *genvbound)
static SCIP_Real getCutoffboundGenVBound(SCIP *scip)
static SCIP_RETCODE createConstraints(SCIP *scip, SCIP_PROP *prop, SCIP_PROPDATA *propdata)
static SCIP_RETCODE applyGenVBounds(SCIP *scip, SCIP_PROP *prop, SCIP_Bool global, SCIP_RESULT *result, int *nchgbds)
#define DEFAULT_GLOBAL_PROPAGATION
static SCIP_RETCODE freeStartingData(SCIP *scip, SCIP_PROPDATA *propdata)
static SCIP_RETCODE addNewGenVBound(SCIP *scip, SCIP_PROP *prop, SCIP_PROPDATA *propdata, GENVBOUND *genvbound)
static SCIP_RETCODE getEventData(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_VAR *var, SCIP_BOUNDTYPE boundtype, SCIP_EVENTDATA **eventdata)
static SCIP_RETCODE createStartingData(SCIP *scip, SCIP_PROPDATA *propdata)
struct GenVBound GENVBOUND
static SCIP_RETCODE applyGenVBound(SCIP *scip, SCIP_PROP *prop, GENVBOUND *genvbound, SCIP_Bool global, SCIP_RESULT *result, int *nchgbds)
static SCIP_RETCODE freeAllEventData(SCIP *scip, SCIP_PROPDATA *propdata)
static SCIP_RETCODE freeGenVBounds(SCIP *scip, SCIP_PROP *prop, SCIP_PROPDATA *propdata)
static SCIP_RETCODE resolveGenVBoundPropagation(SCIP *scip, GENVBOUND *genvbound, SCIP_BDCHGIDX *bdchgidx, SCIP_Real *boundval, SCIP_Bool *success)
static SCIP_RETCODE initPropdata(SCIP *scip, SCIP_PROPDATA *propdata)
generalized variable bounds propagator
public methods for managing events
public methods for message output
#define SCIPerrorMessage
Definition pub_message.h:64
#define SCIPdebug(x)
Definition pub_message.h:93
#define SCIPdebugMessage
Definition pub_message.h:96
#define SCIPdebugPrintf
Definition pub_message.h:99
public data structures and miscellaneous methods
public methods for propagators
public methods for branch and bound tree
public methods for problem variables
public methods for conflict handler plugins and conflict analysis
public methods for constraint handler plugins and constraints
public methods for data structures
public methods for event handler plugins and event handlers
general public methods
public methods for memory management
public methods for message handling
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 propagator plugins
public methods for solutions
public solving methods
public methods for querying solving statistics
public methods for the branch-and-bound tree
public methods for SCIP variables
SCIP_BOUNDTYPE boundtype
SCIP_Real constant
SCIP_Real * coefs
SCIP_VAR * var
SCIP_VAR ** vars
SCIP_Real cutoffcoef
SCIP_Bool relaxonly
@ SCIP_CONFTYPE_PROPAGATION
struct SCIP_Cons SCIP_CONS
Definition type_cons.h:63
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_DECL_EVENTEXEC(x)
Definition type_event.h:259
#define SCIP_EVENTTYPE_LBTIGHTENED
Definition type_event.h:77
@ SCIP_BOUNDTYPE_UPPER
Definition type_lp.h:58
@ SCIP_BOUNDTYPE_LOWER
Definition type_lp.h:57
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition type_lp.h:60
struct SCIP_HashMap SCIP_HASHMAP
Definition type_misc.h:106
struct SCIP_Digraph SCIP_DIGRAPH
Definition type_misc.h:145
#define SCIP_DECL_PROPCOPY(x)
Definition type_prop.h:61
#define SCIP_DECL_PROPEXITPRE(x)
Definition type_prop.h:114
#define SCIP_DECL_PROPINIT(x)
Definition type_prop.h:77
#define SCIP_DECL_PROPFREE(x)
Definition type_prop.h:69
#define SCIP_DECL_PROPEXITSOL(x)
Definition type_prop.h:141
#define SCIP_DECL_PROPEXIT(x)
Definition type_prop.h:85
struct SCIP_Prop SCIP_PROP
Definition type_prop.h:51
#define SCIP_DECL_PROPPRESOL(x)
Definition type_prop.h:193
#define SCIP_DECL_PROPINITPRE(x)
Definition type_prop.h:99
#define SCIP_DECL_PROPRESPROP(x)
Definition type_prop.h:258
struct SCIP_PropData SCIP_PROPDATA
Definition type_prop.h:52
#define SCIP_DECL_PROPEXEC(x)
Definition type_prop.h:217
@ SCIP_DIDNOTRUN
Definition type_result.h:42
@ SCIP_CUTOFF
Definition type_result.h:48
@ SCIP_REDUCEDDOM
Definition type_result.h:51
@ SCIP_DIDNOTFIND
Definition type_result.h:44
@ SCIP_SUCCESS
Definition type_result.h:58
enum SCIP_Result SCIP_RESULT
Definition type_result.h:61
@ SCIP_INVALIDDATA
@ SCIP_INVALIDCALL
enum SCIP_Retcode SCIP_RETCODE
struct Scip SCIP
Definition type_scip.h:39
@ SCIP_STAGE_PRESOLVING
Definition type_set.h:49
struct SCIP_Sol SCIP_SOL
Definition type_sol.h:57
#define SCIP_PROPTIMING_NONE
Definition type_timing.h:65
unsigned int SCIP_PROPTIMING
Definition type_timing.h:75
struct SCIP_Node SCIP_NODE
Definition type_tree.h:63
struct SCIP_Var SCIP_VAR
Definition type_var.h:166
struct SCIP_BdChgIdx SCIP_BDCHGIDX
Definition type_var.h:151
@ SCIP_VARTYPE_CONTINUOUS
Definition type_var.h:71
@ SCIP_VARSTATUS_MULTAGGR
Definition type_var.h:56
@ SCIP_VARSTATUS_AGGREGATED
Definition type_var.h:55
@ SCIP_LOCKTYPE_MODEL
Definition type_var.h:141