SCIP Doxygen Documentation
Loading...
Searching...
No Matches
prop_obbt.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_obbt.c
26 * @ingroup DEFPLUGINS_PROP
27 * @brief optimization-based bound tightening propagator
28 * @author Stefan Weltge
29 * @author Benjamin Mueller
30 */
31
32/**@todo if bound tightenings of other propagators are the reason for lpsolstat != SCIP_LPSOLSTAT_OPTIMAL, resolve LP */
33/**@todo only run more than once in root node if primal bound improved or many cuts were added to the LP */
34/**@todo filter bounds of a variable already if SCIPisLbBetter()/SCIPisUbBetter() would return FALSE */
35/**@todo improve warmstarting of LP solving */
36/**@todo include bound value (finite/infinite) into getScore() function */
37/**@todo use unbounded ray in filtering */
38/**@todo do we want to run if the LP is unbounded, maybe for infinite variable bounds? */
39/**@todo add first filter round in direction of objective function */
40/**@todo implement conflict resolving callback by calling public method of genvbounds propagator, since the reason are
41 * exactly the variable bounds with nonnegative reduced costs stored in the right-hand side of the generated
42 * generalized variable bound (however, this only makes sense if we run locally)
43 */
44
45/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
46
47#include "scip/cons_indicator.h"
48#include "scip/cons_linear.h"
49#include "scip/cons_nonlinear.h"
52#include "scip/prop_obbt.h"
53#include "scip/pub_cons.h"
54#include "scip/pub_lp.h"
55#include "scip/pub_message.h"
56#include "scip/pub_misc.h"
57#include "scip/pub_misc_sort.h"
58#include "scip/pub_nlp.h"
59#include "scip/pub_prop.h"
60#include "scip/pub_tree.h"
61#include "scip/pub_var.h"
62#include "scip/scip_cons.h"
63#include "scip/scip_copy.h"
64#include "scip/scip_cut.h"
65#include "scip/scip_general.h"
66#include "scip/scip_lp.h"
67#include "scip/scip_mem.h"
68#include "scip/scip_message.h"
69#include "scip/scip_nlp.h"
70#include "scip/scip_numerics.h"
71#include "scip/scip_param.h"
72#include "scip/scip_prob.h"
73#include "scip/scip_probing.h"
74#include "scip/scip_prop.h"
77#include "scip/scip_tree.h"
78#include "scip/scip_var.h"
79
80#define PROP_NAME "obbt"
81#define PROP_DESC "optimization-based bound tightening propagator"
82#define PROP_TIMING SCIP_PROPTIMING_AFTERLPLOOP
83#define PROP_PRIORITY -1000000 /**< propagator priority */
84#define PROP_FREQ 0 /**< propagator frequency */
85#define PROP_DELAY TRUE /**< should propagation method be delayed, if other propagators
86 * found reductions? */
87
88#define DEFAULT_CREATE_GENVBOUNDS TRUE /**< should obbt try to provide genvbounds if possible? */
89#define DEFAULT_FILTERING_NORM TRUE /**< should coefficients in filtering be normalized w.r.t. the
90 * domains sizes? */
91#define DEFAULT_APPLY_FILTERROUNDS FALSE /**< try to filter bounds in so-called filter rounds by solving
92 * auxiliary LPs? */
93#define DEFAULT_APPLY_TRIVIALFITLERING TRUE /**< should obbt try to use the LP solution to filter some bounds? */
94#define DEFAULT_GENVBDSDURINGFILTER TRUE /**< try to genrate genvbounds during trivial and aggressive filtering? */
95#define DEFAULT_DUALFEASTOL 1e-9 /**< feasibility tolerance for reduced costs used in obbt; this value
96 * is used if SCIP's dual feastol is greater */
97#define DEFAULT_CONDITIONLIMIT -1.0 /**< maximum condition limit used in LP solver (-1.0: no limit) */
98#define DEFAULT_BOUNDSTREPS 0.001 /**< minimal relative improve for strengthening bounds */
99#define DEFAULT_FILTERING_MIN 2 /**< minimal number of filtered bounds to apply another filter
100 * round */
101#define DEFAULT_ITLIMITFACTOR 10.0 /**< multiple of root node LP iterations used as total LP iteration
102 * limit for obbt (<= 0: no limit ) */
103#define DEFAULT_MINITLIMIT 5000L /**< minimum LP iteration limit */
104#define DEFAULT_ONLYNONCONVEXVARS TRUE /**< only apply obbt on non-convex variables */
105#define DEFAULT_INDICATORS FALSE /**< apply obbt on variables of indicator constraints? (independent of convexity) */
106#define DEFAULT_INDICATORTHRESHOLD 1e6 /**< variables of indicator constraints with smaller upper bound are not considered
107 * and upper bound is tightened only if new bound is smaller */
108#define DEFAULT_TIGHTINTBOUNDSPROBING TRUE /**< should bounds of integral variables be tightened during
109 * the probing mode? */
110#define DEFAULT_TIGHTCONTBOUNDSPROBING FALSE /**< should bounds of continuous variables be tightened during
111 * the probing mode? */
112#define DEFAULT_ORDERINGALGO 1 /**< which type of ordering algorithm should we use?
113 * (0: no, 1: greedy, 2: greedy reverse) */
114#define OBBT_SCOREBASE 5 /**< base that is used to calculate a bounds score value */
115#define GENVBOUND_PROP_NAME "genvbounds"
116
117#define DEFAULT_SEPARATESOL FALSE /**< should the obbt LP solution be separated? note that that by
118 * separating solution OBBT will apply all bound tightenings
119 * immediatly */
120#define DEFAULT_SEPAMINITER 0 /**< minimum number of iteration spend to separate an obbt LP solution */
121#define DEFAULT_SEPAMAXITER 10 /**< maximum number of iteration spend to separate an obbt LP solution */
122#define DEFAULT_GENVBDSDURINGSEPA TRUE /**< try to create genvbounds during separation process? */
123#define DEFAULT_PROPAGATEFREQ 0 /**< trigger a propagation round after that many bound tightenings
124 * (0: no propagation) */
125#define DEFAULT_CREATE_BILININEQS TRUE /**< solve auxiliary LPs in order to find valid inequalities for bilinear terms? */
126#define DEFAULT_CREATE_LINCONS FALSE /**< create linear constraints from inequalities for bilinear terms? */
127#define DEFAULT_ITLIMITFAC_BILININEQS 3.0 /**< multiple of OBBT LP limit used as total LP iteration limit for solving bilinear inequality LPs (< 0 for no limit) */
128#define DEFAULT_MINNONCONVEXITY 1e-1 /**< minimum nonconvexity for choosing a bilinear term */
129#define DEFAULT_RANDSEED 149 /**< initial random seed */
130
131/*
132 * Data structures
133 */
134
135/** bound data */
136struct Bound
137{
138 SCIP_VAR* var; /**< variable */
139 SCIP_Real newval; /**< stores a probably tighter value for this bound */
140 SCIP_BOUNDTYPE boundtype; /**< type of bound */
141 unsigned int score; /**< score value that is used to group bounds */
142 unsigned int filtered:1; /**< thrown out during pre-filtering step */
143 unsigned int found:1; /**< stores whether a probably tighter value for this bound was found */
144 unsigned int done:1; /**< has this bound been processed already? */
145 unsigned int nonconvex:1; /**< is this bound affecting a nonconvex term? */
146 unsigned int indicator:1; /**< is this bound affecting an indicator constraint? */
147 int index; /**< unique index */
148};
149typedef struct Bound BOUND;
150
151/* all possible corners of a rectangular domain */
160typedef enum Corner CORNER;
161
162/** bilinear bound data */
164{
165 SCIP_EXPR* expr; /**< product expression */
166 int filtered; /**< corners that could be thrown out during pre-filtering step */
167 unsigned int done:1; /**< has this bilinear term been processed already? */
168 SCIP_Real score; /**< score value that is used to group bilinear term bounds */
169};
170typedef struct BilinBound BILINBOUND;
171
172/** propagator data */
173struct SCIP_PropData
174{
175 BOUND** bounds; /**< array of interesting bounds */
176 BILINBOUND** bilinbounds; /**< array of interesting bilinear bounds */
177 SCIP_ROW* cutoffrow; /**< pointer to current objective cutoff row */
178 SCIP_PROP* genvboundprop; /**< pointer to genvbound propagator */
179 SCIP_RANDNUMGEN* randnumgen; /**< random number generator */
180 SCIP_Longint lastnode; /**< number of last node where obbt was performed */
181 SCIP_Longint npropagatedomreds; /**< number of domain reductions found during propagation */
182 SCIP_Longint nprobingiterations; /**< number of LP iterations during the probing mode */
183 SCIP_Longint nfilterlpiters; /**< number of LP iterations spend for filtering */
184 SCIP_Longint minitlimit; /**< minimum LP iteration limit */
185 SCIP_Longint itlimitbilin; /**< total LP iterations limit for solving bilinear inequality LPs */
186 SCIP_Longint itusedbilin; /**< total LP iterations used for solving bilinear inequality LPs */
187 SCIP_Real dualfeastol; /**< feasibility tolerance for reduced costs used in obbt; this value is
188 * used if SCIP's dual feastol is greater */
189 SCIP_Real conditionlimit; /**< maximum condition limit used in LP solver (-1.0: no limit) */
190 SCIP_Real boundstreps; /**< minimal relative improve for strengthening bounds */
191 SCIP_Real itlimitfactor; /**< LP iteration limit for obbt will be this factor times total LP
192 * iterations in root node */
193 SCIP_Real itlimitfactorbilin; /**< multiple of OBBT LP limit used as total LP iteration limit for solving bilinear inequality LPs (< 0 for no limit) */
194 SCIP_Real minnonconvexity; /**< lower bound on minimum absolute value of nonconvex eigenvalues for a bilinear term */
195 SCIP_Real indicatorthreshold; /**< threshold whether upper bounds of vars of indicator conss are considered or tightened */
196 SCIP_Bool applyfilterrounds; /**< apply filter rounds? */
197 SCIP_Bool applytrivialfilter; /**< should obbt try to use the LP solution to filter some bounds? */
198 SCIP_Bool genvbdsduringfilter;/**< should we try to generate genvbounds during trivial and aggressive
199 * filtering? */
200 SCIP_Bool genvbdsduringsepa; /**< try to create genvbounds during separation process? */
201 SCIP_Bool creategenvbounds; /**< should obbt try to provide genvbounds if possible? */
202 SCIP_Bool normalize; /**< should coefficients in filtering be normalized w.r.t. the domains
203 * sizes? */
204 SCIP_Bool onlynonconvexvars; /**< only apply obbt on non-convex variables */
205 SCIP_Bool indicators; /**< apply obbt on variables of indicator constraints? (independent of convexity) */
206 SCIP_Bool tightintboundsprobing; /**< should bounds of integral variables be tightened during
207 * the probing mode? */
208 SCIP_Bool tightcontboundsprobing;/**< should bounds of continuous variables be tightened during
209 * the probing mode? */
210 SCIP_Bool separatesol; /**< should the obbt LP solution be separated? note that that by
211 * separating solution OBBT will apply all bound tightenings
212 * immediatly */
213 SCIP_Bool createbilinineqs; /**< solve auxiliary LPs in order to find valid inequalities for bilinear terms? */
214 SCIP_Bool createlincons; /**< create linear constraints from inequalities for bilinear terms? */
215 int orderingalgo; /**< which type of ordering algorithm should we use?
216 * (0: no, 1: greedy, 2: greedy reverse) */
217 int nbounds; /**< length of interesting bounds array */
218 int nbilinbounds; /**< length of interesting bilinear bounds array */
219 int bilinboundssize; /**< size of bilinear bounds array */
220 int boundssize; /**< size of bounds array */
221 int nminfilter; /**< minimal number of filtered bounds to apply another filter round */
222 int nfiltered; /**< number of filtered bounds by solving auxiliary variables */
223 int ntrivialfiltered; /**< number of filtered bounds because the LP value was equal to the bound */
224 int nsolvedbounds; /**< number of solved bounds during the loop in applyObbt() */
225 int ngenvboundsprobing; /**< number of non-trivial genvbounds generated and added during obbt */
226 int ngenvboundsaggrfil; /**< number of non-trivial genvbounds found during aggressive filtering */
227 int ngenvboundstrivfil; /**< number of non-trivial genvbounds found during trivial filtering */
228 int lastidx; /**< index to store the last undone and unfiltered bound */
229 int lastbilinidx; /**< index to store the last undone and unfiltered bilinear bound */
230 int sepaminiter; /**< minimum number of iteration spend to separate an obbt LP solution */
231 int sepamaxiter; /**< maximum number of iteration spend to separate an obbt LP solution */
232 int propagatefreq; /**< trigger a propagation round after that many bound tightenings
233 * (0: no propagation) */
234 int propagatecounter; /**< number of bound tightenings since the last propagation round */
235};
236
237
238/*
239 * Local methods
240 */
241
242/** solves the LP and handles errors */
243static
245 SCIP* scip, /**< SCIP data structure */
246 int itlimit, /**< maximal number of LP iterations to perform, or -1 for no limit */
247 SCIP_Bool* error, /**< pointer to store whether an unresolved LP error occurred */
248 SCIP_Bool* optimal /**< was the LP solved to optimalilty? */
249 )
250{
252 SCIP_RETCODE retcode;
253
254 assert(scip != NULL);
255 assert(itlimit == -1 || itlimit >= 0);
256 assert(error != NULL);
257 assert(optimal != NULL);
258
259 *optimal = FALSE;
260 *error = FALSE;
261
262 retcode = SCIPsolveProbingLP(scip, itlimit, error, NULL);
263
265
266 /* an error should not kill the overall solving process */
267 if( retcode != SCIP_OKAY )
268 {
269 SCIPwarningMessage(scip, " error while solving LP in obbt propagator; LP solve terminated with code <%d>\n", retcode);
270 SCIPwarningMessage(scip, " this does not affect the remaining solution procedure --> continue\n");
271
272 *error = TRUE;
273
274 return SCIP_OKAY;
275 }
276
278 {
279 assert(!*error);
280 *optimal = TRUE;
281 }
282#ifdef SCIP_DEBUG
283 else
284 {
285 switch( lpsolstat )
286 {
288 SCIPdebugMsg(scip, " reached lp iteration limit\n");
289 break;
291 SCIPdebugMsg(scip, " reached time limit while solving lp\n");
292 break;
294 SCIPdebugMsg(scip, " lp was unbounded\n");
295 break;
297 SCIPdebugMsg(scip, " lp was not solved\n");
298 break;
300 SCIPdebugMsg(scip, " an error occurred during solving lp\n");
301 break;
304 case SCIP_LPSOLSTAT_OPTIMAL: /* should not appear because it is handled earlier */
305 default:
306 SCIPdebugMsg(scip, " received an unexpected solstat during solving lp: %d\n", lpsolstat);
307 }
308 }
309#endif
310
311 return SCIP_OKAY;
312}
313
314/** adds the objective cutoff to the LP; must be in probing mode */
315static
317 SCIP* scip, /**< SCIP data structure */
318 SCIP_PROPDATA* propdata /**< data of the obbt propagator */
319 )
320{
321 SCIP_ROW* row;
322 SCIP_VAR** vars;
323 char rowname[SCIP_MAXSTRLEN];
324
325 int nvars;
326 int i;
327
328 assert(scip != NULL);
330 assert(propdata != NULL);
331 assert(propdata->cutoffrow == NULL);
332
334 {
335 SCIPdebugMsg(scip, "no objective cutoff since there is no cutoff bound\n");
336 return SCIP_OKAY;
337 }
338
339 SCIPdebugMsg(scip, "create objective cutoff and add it to the LP\n");
340
341 /* get variables data */
343
344 /* create objective cutoff row; set local flag to FALSE since primal cutoff is globally valid */
345 (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "obbt_objcutoff");
348
349 for( i = 0; i < nvars; i++ )
350 {
352 }
354
355 /* add row to the LP */
357
358 propdata->cutoffrow = row;
359 assert(SCIProwIsInLP(propdata->cutoffrow));
360
361 return SCIP_OKAY;
362}
363
364/** determines, whether a variable is already locally fixed */
365static
367 SCIP* scip, /**< SCIP data structure */
368 SCIP_VAR* var /**< variable to check */
369 )
370{
372}
373
374/** sets objective to minimize or maximize a single variable */
375static
377 SCIP* scip,
378 SCIP_PROPDATA* propdata,
379 BOUND* bound,
380 SCIP_Real coef
381 )
382{
383#ifdef SCIP_DEBUG
384 SCIP_VAR** vars;
385 int nvars;
386 int counter;
387 int i;
388#endif
389
390 assert( scip != NULL );
391 assert( propdata != NULL );
392 assert( bound != NULL );
393
394 /* set the objective for bound->var */
395 if( bound->boundtype == SCIP_BOUNDTYPE_LOWER )
396 {
398 }
399 else
400 {
401 SCIP_CALL( SCIPchgVarObjProbing(scip, bound->var, -coef) );
402 }
403
404#ifdef SCIP_DEBUG
407 counter = 0;
408
409 for( i = 0; i < nvars; ++i )
410 {
411 if( SCIPgetVarObjProbing(scip, vars[i]) != 0.0 )
412 ++counter;
413 }
414
415 assert((counter == 0 && coef == 0.0) || (counter == 1 && coef != 0.0));
416#endif
417
418 return SCIP_OKAY;
419}
420
421/** determines whether variable should be included in the right-hand side of the generalized variable bound */
422static
424 SCIP* scip, /**< SCIP data structure */
425 SCIP_VAR* var /**< variable to check */
426 )
427{
428 SCIP_Real redcost;
429
430 assert(scip != NULL);
431 assert(var != NULL);
432
434 return FALSE;
435
436 redcost = SCIPgetVarRedcost(scip, var);
437 assert(redcost != SCIP_INVALID); /*lint !e777 */
438
439 if( redcost == SCIP_INVALID ) /*lint !e777 */
440 return FALSE;
441
442 if( redcost < SCIPdualfeastol(scip) && redcost > -SCIPdualfeastol(scip) )
443 return FALSE;
444
445 return TRUE;
446}
447
448/** returns number of LP iterations left (-1: no limit ) */
449static
451 SCIP* scip, /**< SCIP data structure */
452 SCIP_Longint nolditerations, /**< iterations count at the beginning of the corresponding function */
453 SCIP_Longint itlimit /**< LP iteration limit (-1: no limit) */
454 )
455{
456 SCIP_Longint itsleft;
457
458 assert(scip != NULL);
459 assert(nolditerations >= 0);
460 assert(itlimit == -1 || itlimit >= 0);
461
462 if( itlimit == -1 )
463 {
464 SCIPdebugMsg(scip, "iterations left: unlimited\n");
465 return -1;
466 }
467 else
468 {
469 itsleft = itlimit - ( SCIPgetNLPIterations(scip) - nolditerations );
470 itsleft = MAX(itsleft, 0);
471 itsleft = MIN(itsleft, INT_MAX);
472
473 SCIPdebugMsg(scip, "iterations left: %d\n", (int) itsleft);
474 return (int) itsleft;
475 }
476}
477
478/** returns the objective coefficient for a variable's bound that will be chosen during filtering */
479static
481 SCIP* scip, /**< SCIP data structure */
482 SCIP_PROPDATA* propdata, /**< data of the obbt propagator */
483 SCIP_VAR* var, /**< variable */
484 SCIP_BOUNDTYPE boundtype /**< boundtype to be filtered? */
485 )
486{
487 SCIP_Real lb;
488 SCIP_Real ub;
489
490 assert(scip != NULL);
491 assert(propdata != NULL);
492 assert(var != NULL);
493
496
497 /* this function should not be called for fixed variables */
499
500 /* infinite bounds will not be reached */
501 if( boundtype == SCIP_BOUNDTYPE_LOWER && SCIPisInfinity(scip, -lb) )
502 return 0.0;
503 if( boundtype == SCIP_BOUNDTYPE_UPPER && SCIPisInfinity(scip, ub) )
504 return 0.0;
505
506 if( propdata->normalize )
507 {
508 /* if the length of the domain is too large then the coefficient should be set to +/- 1.0 */
509 if( boundtype == SCIP_BOUNDTYPE_LOWER && SCIPisInfinity(scip, ub) )
510 return 1.0;
511 if( boundtype == SCIP_BOUNDTYPE_UPPER && SCIPisInfinity(scip, -lb) )
512 return -1.0;
513
514 /* otherwise the coefficient is +/- 1.0 / ( ub - lb ) */
515 return boundtype == SCIP_BOUNDTYPE_LOWER ? 1.0 / (ub - lb) : -1.0 / (ub - lb);
516 }
517 else
518 {
519 return boundtype == SCIP_BOUNDTYPE_LOWER ? 1.0 : -1.0;
520 }
521}
522
523/** creates a genvbound if the dual LP solution provides such information
524 *
525 * Consider the problem
526 *
527 * min { +/- x_i : obj * x <= z, lb <= Ax <= ub, l <= x <= u },
528 *
529 * where z is the current cutoff bound. Let (mu, nu, gamma, alpha, beta) >= 0 be the optimal solution of the dual of
530 * problem (P), where the variables correspond to the primal inequalities in the following way:
531 *
532 * Ax >= lb <-> mu
533 * -Ax >= -ub <-> nu
534 * -obj * x >= -z <-> gamma
535 * x >= l <-> alpha
536 * -x >= -u <-> beta
537 *
538 * Fixing these multipliers, by weak duality, we obtain the inequality
539 *
540 * +/- x_i >= lb*mu - ub*nu - z*gamma + l*alpha - u*beta
541 *
542 * that holds for all primal feasible points x with objective value at least z. Setting
543 *
544 * c = lb*mu - ub*nu, redcost_k = alpha_k - beta_k
545 *
546 * we obtain the inequality
547 *
548 * +/- x_i >= sum ( redcost_k * x_k ) + (-gamma) * cutoff_bound + c,
549 *
550 * that holds for all primal feasible points with objective value at least cutoff_bound. Therefore, the latter
551 * inequality can be added as a generalized variable bound.
552 */
553static
555 SCIP* scip, /**< SCIP data structure */
556 SCIP_PROPDATA* propdata, /**< data of the obbt propagator */
557 BOUND* bound, /**< bound of x_i */
558 SCIP_Bool* found /**< pointer to store if we have found a non-trivial genvbound */
559 )
560{
561 assert(scip != NULL);
562 assert(bound != NULL);
563 assert(propdata != NULL);
564 assert(propdata->genvboundprop != NULL);
565 assert(found != NULL);
566
567 *found = FALSE;
568
569 /* make sure we are in probing mode having an optimal LP solution */
571
573
574 /* only genvbounds created in the root node are globally valid
575 *
576 * note: depth changes to one if we use the probing mode to solve the obbt LPs
577 */
579
580 SCIPdebugMsg(scip, " try to create a genvbound for <%s>...\n", SCIPvarGetName(bound->var));
581
582 /* a genvbound with a multiplier for x_i would not help us */
584 {
585 SCIP_VAR** vars; /* global variables array */
586 SCIP_VAR** genvboundvars; /* genvbound variables array */
587
588 SCIP_VAR* xi; /* variable x_i */
589
590 SCIP_Real* genvboundcoefs; /* genvbound coefficients array */
591
592 SCIP_Real gamma_dual; /* dual multiplier of objective cutoff */
593
594 int k; /* variable for indexing global variables array */
595 int ncoefs; /* number of nonzero coefficients in genvbound */
596 int nvars; /* number of global variables */
597
598 /* set x_i */
599 xi = bound->var;
600
601 /* get variable data */
603
604 /* count nonzero coefficients in genvbound */
605 ncoefs = 0;
606 for( k = 0; k < nvars; k++ )
607 {
608 if( includeVarGenVBound(scip, vars[k]) )
609 {
610 assert(vars[k] != xi);
611 ncoefs++;
612 }
613 }
614
615 /* get dual multiplier for the objective cutoff (set to zero if there is no) */
616 if( propdata->cutoffrow == NULL )
617 {
618 gamma_dual = 0.0;
619 }
620 else
621 {
623
624 /* note that the objective cutoff is of the form
625 * -inf <= obj * x <= cutoff_bound
626 * but we want the positive dual multiplier!
627 */
628 gamma_dual = -SCIProwGetDualsol(propdata->cutoffrow);
629
630 /* we need to treat gamma to be exactly 0 if it is below the dual feasibility tolerance, see #2914 */
631 if( EPSZ(gamma_dual, SCIPdualfeastol(scip)) )
632 gamma_dual = 0.0;
633 }
634
635 /* we need at least one nonzero coefficient or a nonzero dual multiplier for the objective cutoff */
636 if( ncoefs > 0 || gamma_dual != 0.0 )
637 {
638 SCIP_Bool addgenvbound; /* if everything is fine with the redcosts and the bounds, add the genvbound */
639 SCIP_Real c; /* helper variable to calculate constant term in genvbound */
640 int idx; /* variable for indexing genvbound's coefficients array */
641
642 /* add the bound if the bool is still TRUE after the loop */
643 addgenvbound = TRUE;
644
645 /* there should be no coefficient for x_i */
647
648 /* allocate memory for storing the genvbounds right-hand side variables and coefficients */
649 SCIP_CALL( SCIPallocBufferArray(scip, &(genvboundvars), ncoefs) );
650 SCIP_CALL( SCIPallocBufferArray(scip, &(genvboundcoefs), ncoefs) );
651
652 /* set c = lb*mu - ub*nu - z*gamma + l*alpha - u*beta */
654
655 /* subtract ( - z * gamma ) from c */
656 c += SCIPgetCutoffbound(scip) * gamma_dual;
657
658 /* subtract ( l*alpha - u*beta ) from c and set the coefficients of the variables */
659 idx = 0;
660 for( k = 0; k < nvars; k++ )
661 {
662 SCIP_VAR* xk;
663
664 xk = vars[k];
665
666 if( includeVarGenVBound(scip, xk) )
667 {
668 SCIP_Real redcost;
669
670 redcost = SCIPgetVarRedcost(scip, xk);
671
672 assert(redcost != SCIP_INVALID); /*lint !e777 */
673 assert(xk != xi);
674
675 /* in this case dont add a genvbound */
676 if( ( (redcost > SCIPdualfeastol(scip)) && SCIPisInfinity(scip, -SCIPvarGetLbLocal(xk)) ) ||
677 ( (redcost < -SCIPdualfeastol(scip)) && SCIPisInfinity(scip, SCIPvarGetUbLocal(xk)) ) )
678 {
679 addgenvbound = FALSE;
680 break;
681 }
682
683 /* store coefficients */
684 assert(idx < ncoefs);
685 genvboundvars[idx] = xk;
686 genvboundcoefs[idx] = redcost;
687 idx++;
688
689 /* if redcost > 0, then redcost = alpha_k, otherwise redcost = - beta_k */
690 assert(redcost <= 0 || !SCIPisInfinity(scip, -SCIPvarGetLbLocal(xk)));
691 assert(redcost >= 0 || !SCIPisInfinity(scip, SCIPvarGetUbLocal(xk)));
692 c -= redcost > 0 ? redcost * SCIPvarGetLbLocal(xk) : redcost * SCIPvarGetUbLocal(xk);
693 }
694 }
695
696 assert(!addgenvbound || idx == ncoefs);
697
698 /* add genvbound */
699 if( addgenvbound && !SCIPisInfinity(scip, -c) )
700 {
701#ifndef NDEBUG
702 /* check whether the activity of the LVB in the optimal solution of the LP is equal to the LP objective value */
703 SCIP_Real activity = c - gamma_dual * SCIPgetCutoffbound(scip);
704
705 for( k = 0; k < ncoefs; ++k )
706 activity += genvboundcoefs[k] * SCIPvarGetLPSol(genvboundvars[k]);
707
708 SCIPdebugMsg(scip, "LVB activity = %g lpobj = %g\n", activity, SCIPgetLPObjval(scip));
710#endif
711
712 SCIPdebugMsg(scip, " adding genvbound\n");
713 SCIP_CALL( SCIPgenVBoundAdd(scip, propdata->genvboundprop, genvboundvars, xi, genvboundcoefs, ncoefs,
714 gamma_dual < SCIPdualfeastol(scip) ? 0.0 : -gamma_dual, c, bound->boundtype) );
715 *found = TRUE;
716 }
717
718 /* free arrays */
719 SCIPfreeBufferArray(scip, &genvboundcoefs);
720 SCIPfreeBufferArray(scip, &genvboundvars);
721 }
722 else
723 {
724 SCIPdebugMsg(scip, " trivial genvbound, skipping\n");
725 }
726 }
727 else
728 {
729 SCIPdebugMsg(scip, " found multiplier for <%s>: %g, skipping\n",
731 }
732
733 return SCIP_OKAY;
734}
735
736/** exchange a bound which has been processed and updates the last undone and unfiltered bound index
737 * NOTE: this method has to be called after filtering or processing a bound
738 */
739static
741 SCIP_PROPDATA* propdata, /**< propagator data */
742 int i /**< bound that was filtered or processed */
743 )
744{
745 assert(i >= 0 && i < propdata->nbounds);
746 assert(propdata->lastidx >= 0 && propdata->lastidx < propdata->nbounds);
747
748 /* exchange the bounds */
749 if( propdata->lastidx != i )
750 {
751 BOUND* tmp;
752
753 tmp = propdata->bounds[i];
754 propdata->bounds[i] = propdata->bounds[propdata->lastidx];
755 propdata->bounds[propdata->lastidx] = tmp;
756 }
757
758 propdata->lastidx -= 1;
759}
760
761/** helper function to return a corner of the domain of two variables */
762static
764 SCIP_VAR* x, /**< first variable */
765 SCIP_VAR* y, /**< second variable */
766 CORNER corner, /**< corner */
767 SCIP_Real* px, /**< buffer to store point for x */
768 SCIP_Real* py /**< buffer to store point for y */
769 )
770{
771 assert(x != NULL);
772 assert(y != NULL);
773 assert(px != NULL);
774 assert(py != NULL);
775
776 switch( corner )
777 {
778 case LEFTBOTTOM:
779 *px = SCIPvarGetLbGlobal(x);
780 *py = SCIPvarGetLbGlobal(y);
781 break;
782 case RIGHTBOTTOM:
783 *px = SCIPvarGetUbGlobal(x);
784 *py = SCIPvarGetLbGlobal(y);
785 break;
786 case LEFTTOP:
787 *px = SCIPvarGetLbGlobal(x);
788 *py = SCIPvarGetUbGlobal(y);
789 break;
790 case RIGHTTOP:
791 *px = SCIPvarGetUbGlobal(x);
792 *py = SCIPvarGetUbGlobal(y);
793 break;
794 case FILTERED:
795 SCIPABORT();
796 }
797}
798
799/** helper function to return the two end points of a diagonal */
800static
802 SCIP_VAR* x, /**< first variable */
803 SCIP_VAR* y, /**< second variable */
804 CORNER corner, /**< corner */
805 SCIP_Real* xs, /**< buffer to store start point for x */
806 SCIP_Real* ys, /**< buffer to store start point for y */
807 SCIP_Real* xt, /**< buffer to store end point for x */
808 SCIP_Real* yt /**< buffer to store end point for y */
809 )
810{
811 assert(x != NULL);
812 assert(y != NULL);
813 assert(xs != NULL);
814 assert(ys != NULL);
815 assert(xt != NULL);
816 assert(yt != NULL);
817
818 /* get end point */
819 getCorner(x,y, corner, xt, yt);
820
821 /* get start point */
822 switch( corner )
823 {
824 case LEFTBOTTOM:
825 getCorner(x,y, RIGHTTOP, xs, ys);
826 break;
827 case RIGHTBOTTOM:
828 getCorner(x,y, LEFTTOP, xs, ys);
829 break;
830 case LEFTTOP:
831 getCorner(x,y, RIGHTBOTTOM, xs, ys);
832 break;
833 case RIGHTTOP:
834 getCorner(x,y, LEFTBOTTOM, xs, ys);
835 break;
836 case FILTERED:
837 SCIPABORT();
838 }
839}
840
841/** returns the first variable of a bilinear bound */
842static
844 BILINBOUND* bilinbound /**< bilinear bound */
845 )
846{
847 assert(bilinbound->expr != NULL);
848 assert(SCIPexprGetNChildren(bilinbound->expr) == 2);
849
851}
852
853/** returns the second variable of a bilinear bound */
854static
856 BILINBOUND* bilinbound /**< bilinear bound */
857 )
858{
859 assert(bilinbound->expr != NULL);
860 assert(SCIPexprGetNChildren(bilinbound->expr) == 2);
861
863}
864
865/** returns the negative locks of the expression in a bilinear bound */
866static
868 BILINBOUND* bilinbound /**< bilinear bound */
869 )
870{
871 assert(bilinbound->expr != NULL);
872
873 return SCIPgetExprNLocksNegNonlinear(bilinbound->expr);
874}
875
876/** returns the positive locks of the expression in a bilinear bound */
877static
879 BILINBOUND* bilinbound /**< bilinear bound */
880 )
881{
882 assert(bilinbound->expr != NULL);
883
884 return SCIPgetExprNLocksPosNonlinear(bilinbound->expr);
885}
886
887/** computes the score of a bilinear term bound */
888static
890 SCIP* scip, /**< SCIP data structure */
891 SCIP_RANDNUMGEN* randnumgen, /**< random number generator */
892 BILINBOUND* bilinbound /**< bilinear bound */
893 )
894{
895 SCIP_VAR* x = bilinboundGetX(bilinbound);
896 SCIP_VAR* y = bilinboundGetY(bilinbound);
901 SCIP_Real score;
902
903 assert(scip != NULL);
904 assert(randnumgen != NULL);
905 assert(bilinbound != NULL);
906
907 /* consider how often a bilinear term is present in the problem */
908 score = bilinboundGetLocksNeg(bilinbound) + bilinboundGetLocksPos(bilinbound);
909
910 /* penalize small variable domains; TODO tune the factor in the logarithm, maybe add a parameter for it */
911 if( ubx - lbx < 0.5 )
912 score += log(2.0*(ubx-lbx) + SCIPepsilon(scip));
913 if( uby - lby < 0.5 )
914 score += log(2.0*(uby-lby) + SCIPepsilon(scip));
915
916 /* consider interiority of variables in the LP solution */
918 {
921 SCIP_Real interiorityx = MIN(solx-lbx, ubx-solx) / MAX(ubx-lbx, SCIPepsilon(scip)); /*lint !e666*/
922 SCIP_Real interiorityy = MIN(soly-lby, uby-soly) / MAX(uby-lby, SCIPepsilon(scip)); /*lint !e666*/
923
924 score += interiorityx + interiorityy;
925 }
926
927 /* randomize score */
928 score *= 1.0 + SCIPrandomGetReal(randnumgen, -SCIPepsilon(scip), SCIPepsilon(scip));
929
930 return score;
931}
932
933/** determines whether a variable of an indicator constraint is (still) interesting
934 *
935 * A variable is interesting if it is not only part of indicator constraints or if the upper bound is greater than the given threshold.
936 */
937static
939 SCIP* scip, /**< SCIP data structure */
940 SCIP_VAR* var, /**< variable to check */
941 int nlcount, /**< number of nonlinear constraints containing the variable
942 * or number of non-convex terms containing the variable
943 * (depends on propdata->onlynonconvexvars) */
944 int nindcount, /**< number of indicator constraints containing the variable
945 * or 0 (depends on propdata->indicators) */
946 SCIP_Real threshold /**< variables with smaller upper bound are not interesting */
947 )
948{
949 /* if variable is only part of indicator constraints, consider current upper bound */
950 if( nlcount == 0 && nindcount > 0 )
951 {
952 if( SCIPisLE(scip, SCIPvarGetUbLocal(var), threshold) )
953 return FALSE;
954 }
955
956 return TRUE;
957}
958
959/** trying to filter some bounds using the existing LP solution */
960static
962 SCIP* scip, /**< original SCIP data structure */
963 SCIP_PROPDATA* propdata, /**< data of the obbt propagator */
964 int* nfiltered, /**< how many bounds were filtered this round? */
965 BOUND* currbound /**< bound for which OBBT LP was solved (Note: might be NULL) */
966 )
967{
968 int i;
969
970 assert(scip != NULL);
971 assert(propdata != NULL);
972 assert(nfiltered != NULL);
973
974 *nfiltered = 0;
975
976 /* only apply filtering if an LP solution is at hand */
978 {
979 SCIPdebugMsg(scip, "can't filter using existing lp solution since it was not solved to optimality\n");
980 return SCIP_OKAY;
981 }
982
983 /* check if a bound is tight */
984 for( i = propdata->nbounds - 1; i >= 0; --i )
985 {
986 BOUND* bound; /* shortcut for current bound */
987
988 SCIP_Real solval; /* the variables value in the current solution */
989 SCIP_Real boundval; /* current local bound for the variable */
990
991 bound = propdata->bounds[i];
992 if( bound->filtered || bound->done )
993 continue;
994
995 boundval = bound->boundtype == SCIP_BOUNDTYPE_UPPER ?
997 solval = SCIPvarGetLPSol(bound->var);
998
999 /* bound is tight; since this holds for all fixed variables, those are filtered here automatically; if the lp solution
1000 * is infinity, then also the bound is tight */
1001 if( (bound->boundtype == SCIP_BOUNDTYPE_UPPER &&
1002 (SCIPisInfinity(scip, solval) || SCIPisFeasGE(scip, solval, boundval)))
1003 || (bound->boundtype == SCIP_BOUNDTYPE_LOWER &&
1004 (SCIPisInfinity(scip, -solval) || SCIPisFeasLE(scip, solval, boundval))) )
1005 {
1006 SCIP_BASESTAT basestat;
1007
1008 /* mark bound as filtered */
1009 bound->filtered = TRUE;
1010 SCIPdebugMsg(scip, "trivial filtered var: %s boundval=%e solval=%e\n", SCIPvarGetName(bound->var), boundval, solval);
1011
1012 /* get the basis status of the variable */
1013 basestat = SCIPcolGetBasisStatus(SCIPvarGetCol(bound->var));
1014
1015 /* solve corresponding OBBT LP and try to generate a nontrivial genvbound */
1016 if( propdata->genvbdsduringfilter && currbound != NULL && basestat == SCIP_BASESTAT_BASIC )
1017 {
1018#ifndef NDEBUG
1019 int j;
1020#endif
1021 SCIP_Bool optimal;
1022 SCIP_Bool error;
1023
1024 /* set objective coefficient of the bound */
1025 SCIP_CALL( SCIPchgVarObjProbing(scip, currbound->var, 0.0) );
1026 SCIP_CALL( setObjProbing(scip, propdata, bound, 1.0) );
1027
1028#ifndef NDEBUG
1029 for( j = 0; j < SCIPgetNVars(scip); ++j )
1030 {
1031 SCIP_VAR* var;
1032
1033 var = SCIPgetVars(scip)[j];
1034 assert(var != NULL);
1036 }
1037#endif
1038
1039 /* solve the OBBT LP */
1040 propdata->nprobingiterations -= SCIPgetNLPIterations(scip);
1041 SCIP_CALL( solveLP(scip, -1, &error, &optimal) );
1042 propdata->nprobingiterations += SCIPgetNLPIterations(scip);
1043 assert(propdata->nprobingiterations >= 0);
1044
1045 /* try to generate a genvbound if we have solved the OBBT LP */
1046 if( optimal && propdata->genvboundprop != NULL
1047 && (SCIPgetDepth(scip) == 0 || (SCIPinProbing(scip) && SCIPgetDepth(scip) == 1)) )
1048 {
1049 SCIP_Bool found;
1050
1051 assert(!error);
1052 SCIP_CALL( createGenVBound(scip, propdata, bound, &found) );
1053
1054 if( found )
1055 {
1056 propdata->ngenvboundstrivfil += 1;
1057 SCIPdebugMsg(scip, "found genvbound during trivial filtering\n");
1058 }
1059 }
1060
1061 /* restore objective function */
1062 SCIP_CALL( setObjProbing(scip, propdata, bound, 0.0) );
1063 SCIP_CALL( setObjProbing(scip, propdata, currbound, 1.0) );
1064 }
1065
1066 /* exchange bound i with propdata->bounds[propdata->lastidx] */
1067 if( propdata->lastidx >= 0 )
1068 exchangeBounds(propdata, i);
1069
1070 /* increase number of filtered variables */
1071 (*nfiltered)++;
1072 }
1073 }
1074
1075 /* try to filter bilinear bounds */
1076 for( i = propdata->lastbilinidx; i < propdata->nbilinbounds; ++i )
1077 {
1078 CORNER corners[4] = {LEFTTOP, LEFTBOTTOM, RIGHTTOP, RIGHTBOTTOM};
1079 BILINBOUND* bilinbound = propdata->bilinbounds[i];
1080 SCIP_Real solx;
1081 SCIP_Real soly;
1082 SCIPdebug(int oldfiltered;)
1083 int j;
1084
1085 /* skip processed and filtered bounds */
1086 if( bilinbound->done || bilinbound->filtered == FILTERED ) /*lint !e641*/
1087 continue;
1088
1089 SCIPdebug(oldfiltered = bilinbound->filtered;)
1090 solx = SCIPvarGetLPSol(bilinboundGetX(bilinbound));
1091 soly = SCIPvarGetLPSol(bilinboundGetY(bilinbound));
1092
1093 /* check cases of unbounded solution values */
1094 if( SCIPisInfinity(scip, solx) )
1095 bilinbound->filtered = bilinbound->filtered | RIGHTTOP | RIGHTBOTTOM; /*lint !e641*/
1096 else if( SCIPisInfinity(scip, -solx) )
1097 bilinbound->filtered = bilinbound->filtered | LEFTTOP | LEFTBOTTOM; /*lint !e641*/
1098
1099 if( SCIPisInfinity(scip, soly) )
1100 bilinbound->filtered = bilinbound->filtered | RIGHTTOP | LEFTTOP; /*lint !e641*/
1101 else if( SCIPisInfinity(scip, -soly) )
1102 bilinbound->filtered = bilinbound->filtered | RIGHTBOTTOM | LEFTBOTTOM; /*lint !e641*/
1103
1104 /* check all corners */
1105 for( j = 0; j < 4; ++j )
1106 {
1109
1110 getCorner(bilinboundGetX(bilinbound), bilinboundGetY(bilinbound), corners[j], &xt, &yt);
1111
1112 if( (SCIPisInfinity(scip, REALABS(solx)) || SCIPisFeasEQ(scip, xt, solx))
1113 && (SCIPisInfinity(scip, REALABS(soly)) || SCIPisFeasEQ(scip, yt, soly)) )
1114 bilinbound->filtered = bilinbound->filtered | corners[j]; /*lint !e641*/
1115 }
1116
1117#ifdef SCIP_DEBUG
1118 if( oldfiltered != bilinbound->filtered )
1119 {
1120 SCIP_VAR* x = bilinboundGetX(bilinbound);
1121 SCIP_VAR* y = bilinboundGetY(bilinbound);
1122 SCIPdebugMessage("filtered corners %d for (%s,%s) = (%g,%g) in [%g,%g]x[%g,%g]\n",
1123 bilinbound->filtered - oldfiltered, SCIPvarGetName(x), SCIPvarGetName(y), solx, soly,
1125 }
1126#endif
1127 }
1128
1129 return SCIP_OKAY;
1130}
1131
1132/** enforces one round of filtering */
1133static
1135 SCIP* scip, /**< SCIP data structure */
1136 SCIP_PROPDATA* propdata, /**< data of the obbt propagator */
1137 int itlimit, /**< LP iteration limit (-1: no limit) */
1138 int* nfiltered, /**< how many bounds were filtered this round */
1139 SCIP_Real* objcoefs, /**< array to store the nontrivial objective coefficients */
1140 int* objcoefsinds, /**< array to store bound indices for which their corresponding variables
1141 * has a nontrivial objective coefficient */
1142 int nobjcoefs /**< number of nontrivial objective coefficients */
1143 )
1144{
1145 SCIP_VAR** vars; /* array of the problems variables */
1146 SCIP_Bool error;
1147 SCIP_Bool optimal;
1148
1149 int nvars; /* number of the problems variables */
1150 int i;
1151
1152 assert(scip != NULL);
1154 assert(propdata != NULL);
1155 assert(itlimit == -1 || itlimit >= 0);
1156 assert(nfiltered != NULL);
1157 assert(objcoefs != NULL);
1158 assert(objcoefsinds != NULL);
1159 assert(nobjcoefs >= 0);
1160
1161 *nfiltered = 0;
1162
1163 /* get variable data */
1165
1166 /* solve LP */
1167 propdata->nfilterlpiters -= (int) SCIPgetNLPIterations(scip);
1168 SCIP_CALL( solveLP(scip, itlimit, &error, &optimal) );
1169 propdata->nfilterlpiters += (int) SCIPgetNLPIterations(scip);
1170 assert(propdata->nfilterlpiters >= 0);
1171
1172 if( !optimal )
1173 {
1174 SCIPdebugMsg(scip, "skipping filter round since the LP was not solved to optimality\n");
1175 return SCIP_OKAY;
1176 }
1177
1178 assert(!error);
1179
1180 /* check if a bound is tight */
1181 for( i = 0; i < propdata->nbounds; i++ )
1182 {
1183 BOUND* bound; /* shortcut for current bound */
1184
1185 SCIP_Real solval; /* the variables value in the current solution */
1186 SCIP_Real boundval; /* current local bound for the variable */
1187
1188 bound = propdata->bounds[i];
1189
1190 /* if bound is filtered it was handled already before */
1191 if( bound->filtered )
1192 continue;
1193
1194 boundval = bound->boundtype == SCIP_BOUNDTYPE_UPPER ?
1196 solval = SCIPvarGetLPSol(bound->var);
1197
1198 /* bound is tight */
1199 if( (bound->boundtype == SCIP_BOUNDTYPE_UPPER && SCIPisFeasGE(scip, solval, boundval))
1200 || (bound->boundtype == SCIP_BOUNDTYPE_LOWER && SCIPisFeasLE(scip, solval, boundval)) )
1201 {
1202 SCIP_Real objcoef;
1203 SCIP_BASESTAT basestat;
1204
1205 /* mark bound as filtered */
1206 bound->filtered = TRUE;
1207
1208 /* get the basis status of the variable */
1209 basestat = SCIPcolGetBasisStatus(SCIPvarGetCol(bound->var));
1210
1211 /* increase number of filtered variables */
1212 (*nfiltered)++;
1213
1214 /* solve corresponding OBBT LP and try to generate a nontrivial genvbound */
1215 if( propdata->genvbdsduringfilter && basestat == SCIP_BASESTAT_BASIC )
1216 {
1217 int j;
1218
1219 /* set all objective coefficients to zero */
1220 for( j = 0; j < nobjcoefs; ++j )
1221 {
1222 BOUND* filterbound;
1223
1224 filterbound = propdata->bounds[ objcoefsinds[j] ];
1225 assert(filterbound != NULL);
1226
1227 SCIP_CALL( SCIPchgVarObjProbing(scip, filterbound->var, 0.0) );
1228 }
1229
1230#ifndef NDEBUG
1231 for( j = 0; j < nvars; ++j )
1233#endif
1234
1235 /* set objective coefficient of the bound */
1236 SCIP_CALL( setObjProbing(scip, propdata, bound, 1.0) );
1237
1238 /* solve the OBBT LP */
1239 propdata->nfilterlpiters -= (int) SCIPgetNLPIterations(scip);
1240 SCIP_CALL( solveLP(scip, -1, &error, &optimal) );
1241 propdata->nfilterlpiters += (int) SCIPgetNLPIterations(scip);
1242 assert(propdata->nfilterlpiters >= 0);
1243
1244 /* try to generate a genvbound if we have solved the OBBT LP */
1245 if( optimal && propdata->genvboundprop != NULL
1246 && (SCIPgetDepth(scip) == 0 || (SCIPinProbing(scip) && SCIPgetDepth(scip) == 1)) )
1247 {
1248 SCIP_Bool found;
1249
1250 assert(!error);
1251 SCIP_CALL( createGenVBound(scip, propdata, bound, &found) );
1252
1253 if( found )
1254 {
1255 propdata->ngenvboundsaggrfil += 1;
1256 SCIPdebugMsg(scip, "found genvbound during aggressive filtering\n");
1257 }
1258 }
1259
1260 /* restore objective function */
1261 for( j = 0; j < nobjcoefs; ++j )
1262 {
1263 BOUND* filterbound;
1264
1265 filterbound = propdata->bounds[ objcoefsinds[j] ];
1266 assert(filterbound != NULL);
1267
1268 /* NOTE: only restore coefficients of nonfiltered bounds */
1269 if( !filterbound->filtered )
1270 {
1271 assert(!SCIPisZero(scip, objcoefs[j]));
1272 SCIP_CALL( SCIPchgVarObjProbing(scip, propdata->bounds[ objcoefsinds[j] ]->var, objcoefs[j]) );
1273 }
1274 }
1275 }
1276
1277 /* get the corresponding variable's objective coefficient */
1278 objcoef = SCIPgetVarObjProbing(scip, bound->var);
1279
1280 /* change objective coefficient if it was set up for this bound */
1281 if( (bound->boundtype == SCIP_BOUNDTYPE_UPPER && SCIPisNegative(scip, objcoef))
1282 || (bound->boundtype == SCIP_BOUNDTYPE_LOWER && SCIPisPositive(scip, objcoef)) )
1283 {
1285 }
1286 }
1287 }
1288
1289 return SCIP_OKAY;
1290}
1291
1292/** filter some bounds that are not improvable by solving auxiliary LPs */
1293static
1295 SCIP* scip, /**< SCIP data structure */
1296 SCIP_PROPDATA* propdata, /**< data of the obbt propagator */
1297 SCIP_Longint itlimit /**< LP iteration limit (-1: no limit) */
1298 )
1299{
1300 SCIP_VAR** vars;
1301 SCIP_Longint nolditerations;
1302 SCIP_Real* objcoefs; /* array to store the nontrivial objective coefficients */
1303 int* objcoefsinds; /* array to store bound indices for which the corresponding variable
1304 * has a nontrivial objective coefficient */
1305 int nobjcoefs; /* number of nontrivial objective coefficients */
1306 int nleftiterations;
1307 int i;
1308 int nfiltered;
1309 int ntotalfiltered;
1310 int nvars;
1311
1312 assert(scip != NULL);
1314 assert(propdata != NULL);
1315 assert(itlimit == -1 || itlimit >= 0);
1316
1317 ntotalfiltered = 0;
1318 nolditerations = SCIPgetNLPIterations(scip);
1319 nleftiterations = getIterationsLeft(scip, nolditerations, itlimit);
1320
1321 /* get variable data */
1323
1324 SCIPdebugMsg(scip, "start filter rounds\n");
1325
1326 SCIP_CALL( SCIPallocBufferArray(scip, &objcoefs, propdata->nbounds) );
1327 SCIP_CALL( SCIPallocBufferArray(scip, &objcoefsinds, propdata->nbounds) );
1328 nobjcoefs = 0;
1329
1330 /*
1331 * 1.) Filter bounds of variables that are only part of indicator constraints if they are not interesting any more
1332 */
1333 for( i = 0; i < propdata->nbounds; i++ )
1334 {
1335 if( !propdata->bounds[i]->filtered && !propdata->bounds[i]->done && propdata->bounds[i]->indicator && !propdata->bounds[i]->nonconvex )
1336 {
1337 if( !indicatorVarIsInteresting(scip, vars[i], (int)propdata->bounds[i]->nonconvex, (int)propdata->bounds[i]->indicator, propdata->indicatorthreshold) )
1338 {
1339 /* mark bound as filtered */
1340 propdata->bounds[i]->filtered = TRUE;
1341
1342 /* increase number of filtered variables */
1343 ntotalfiltered++;
1344 }
1345 }
1346 }
1347
1348 /*
1349 * 2.) Try first to filter lower bounds of interesting variables, whose bounds are not already filtered
1350 */
1351
1352 for( i = 0; i < nvars; i++ )
1353 {
1355 }
1356
1357 for( i = 0; i < propdata->nbounds; i++ )
1358 {
1359 if( propdata->bounds[i]->boundtype == SCIP_BOUNDTYPE_LOWER && !propdata->bounds[i]->filtered
1360 && !propdata->bounds[i]->done )
1361 {
1362 SCIP_Real objcoef;
1363
1364 objcoef = getFilterCoef(scip, propdata, propdata->bounds[i]->var, SCIP_BOUNDTYPE_LOWER);
1365
1366 if( !SCIPisZero(scip, objcoef) )
1367 {
1368 SCIP_CALL( SCIPchgVarObjProbing(scip, propdata->bounds[i]->var, objcoef) );
1369
1370 /* store nontrivial objective coefficients */
1371 objcoefs[nobjcoefs] = objcoef;
1372 objcoefsinds[nobjcoefs] = i;
1373 ++nobjcoefs;
1374 }
1375 }
1376 }
1377
1378 do
1379 {
1380 SCIPdebugMsg(scip, "doing a lower bounds round\n");
1381 SCIP_CALL( filterRound(scip, propdata, nleftiterations, &nfiltered, objcoefs, objcoefsinds, nobjcoefs) );
1382 ntotalfiltered += nfiltered;
1383 SCIPdebugMsg(scip, "filtered %d more bounds in lower bounds round\n", nfiltered);
1384
1385 /* update iterations left */
1386 nleftiterations = getIterationsLeft(scip, nolditerations, itlimit);
1387 }
1388 while( nfiltered >= propdata->nminfilter && ( nleftiterations == -1 || nleftiterations > 0 ) );
1389
1390 /*
1391 * 3.) Now try to filter the remaining upper bounds of interesting variables, whose bounds are not already filtered
1392 */
1393
1394 /* set all objective coefficients to zero */
1395 for( i = 0; i < nobjcoefs; i++ )
1396 {
1397 BOUND* bound;
1398
1399 assert(objcoefsinds[i] >= 0 && objcoefsinds[i] < propdata->nbounds);
1400 bound = propdata->bounds[ objcoefsinds[i] ];
1401 assert(bound != NULL);
1403 }
1404
1405 /* reset number of nontrivial objective coefficients */
1406 nobjcoefs = 0;
1407
1408#ifndef NDEBUG
1409 for( i = 0; i < nvars; ++i )
1411#endif
1412
1413 for( i = 0; i < propdata->nbounds; i++ )
1414 {
1415 if( propdata->bounds[i]->boundtype == SCIP_BOUNDTYPE_UPPER && !propdata->bounds[i]->filtered )
1416 {
1417 SCIP_Real objcoef;
1418
1419 objcoef = getFilterCoef(scip, propdata, propdata->bounds[i]->var, SCIP_BOUNDTYPE_UPPER);
1420
1421 if( !SCIPisZero(scip, objcoef) )
1422 {
1423 SCIP_CALL( SCIPchgVarObjProbing(scip, propdata->bounds[i]->var, objcoef) );
1424
1425 /* store nontrivial objective coefficients */
1426 objcoefs[nobjcoefs] = objcoef;
1427 objcoefsinds[nobjcoefs] = i;
1428 ++nobjcoefs;
1429 }
1430 }
1431 }
1432
1433 do
1434 {
1435 SCIPdebugMsg(scip, "doing an upper bounds round\n");
1436 SCIP_CALL( filterRound(scip, propdata, nleftiterations, &nfiltered, objcoefs, objcoefsinds, nobjcoefs) );
1437 SCIPdebugMsg(scip, "filtered %d more bounds in upper bounds round\n", nfiltered);
1438 ntotalfiltered += nfiltered;
1439 /* update iterations left */
1440 nleftiterations = getIterationsLeft(scip, nolditerations, itlimit);
1441 }
1442 while( nfiltered >= propdata->nminfilter && ( nleftiterations == -1 || nleftiterations > 0 ) );
1443
1444 SCIPdebugMsg(scip, "filtered %d this round\n", ntotalfiltered);
1445 propdata->nfiltered += ntotalfiltered;
1446
1447 /* free array */
1448 SCIPfreeBufferArray(scip, &objcoefsinds);
1449 SCIPfreeBufferArray(scip, &objcoefs);
1450
1451 return SCIP_OKAY;
1452}
1453
1454/** applies possible bound changes that were found */
1455static
1457 SCIP* scip, /**< SCIP data structure */
1458 SCIP_PROPDATA* propdata, /**< data of the obbt propagator */
1459 SCIP_RESULT* result /**< result pointer */
1460 )
1461{
1462#ifdef SCIP_DEBUG
1463 int ntightened; /* stores the number of successful bound changes */
1464#endif
1465 int i;
1466
1467 assert(scip != NULL);
1469 assert(propdata != NULL);
1470 assert(result != NULL);
1472
1473 SCIPdebug( ntightened = 0 );
1474
1475 for( i = 0; i < propdata->nbounds; i++ )
1476 {
1477 BOUND* bound; /* shortcut to the current bound */
1478 SCIP_Bool infeas; /* stores wether a tightening approach forced an infeasibilty */
1479 SCIP_Bool tightened; /* stores wether a tightening approach was successful */
1480
1481 bound = propdata->bounds[i];
1482 infeas = FALSE;
1483
1484 if( bound->found )
1485 {
1486 SCIPdebug( double oldbound = (bound->boundtype == SCIP_BOUNDTYPE_LOWER)
1487 ? SCIPvarGetLbLocal(bound->var)
1488 : SCIPvarGetUbLocal(bound->var) );
1489
1490 if( bound->boundtype == SCIP_BOUNDTYPE_LOWER )
1491 {
1492 SCIP_CALL( SCIPtightenVarLb(scip, bound->var, bound->newval, FALSE, &infeas, &tightened) );
1493 }
1494 else
1495 {
1496 /* tighten only if new bound is small enough due to numerical reasons */
1497 if( SCIPisLE(scip, bound->newval, propdata->indicatorthreshold) )
1498 {
1499 SCIP_CALL( SCIPtightenVarUb(scip, bound->var, bound->newval, FALSE, &infeas, &tightened) );
1500 }
1501 else
1502 tightened = FALSE;
1503 }
1504
1505 /* handle information about the success */
1506 if( infeas )
1507 {
1509 SCIPdebugMsg(scip, "cut off\n");
1510 break;
1511 }
1512
1513 if( tightened )
1514 {
1515 SCIPdebug( SCIPdebugMsg(scip, "tightended: %s old: %e new: %e\n" , SCIPvarGetName(bound->var), oldbound,
1516 bound->newval) );
1517
1519 SCIPdebug( ntightened++ );
1520 }
1521 }
1522 }
1523
1524 SCIPdebug( SCIPdebugMsg(scip, "tightened bounds: %d\n", ntightened) );
1525
1526 return SCIP_OKAY;
1527}
1528
1529/** tries to tighten a bound in probing mode */
1530static
1532 SCIP* scip, /**< SCIP data structure */
1533 BOUND* bound, /**< bound that could be tightened */
1534 SCIP_Real newval, /**< new bound value */
1535 SCIP_Bool* tightened /**< was tightening successful? */
1536 )
1537{
1538 SCIP_Real lb;
1539 SCIP_Real ub;
1540
1541 assert(scip != NULL);
1543 assert(bound != NULL);
1544 assert(tightened != NULL);
1545
1546 *tightened = FALSE;
1547
1548 /* get old bounds */
1549 lb = SCIPvarGetLbLocal(bound->var);
1550 ub = SCIPvarGetUbLocal(bound->var);
1551
1552 if( bound->boundtype == SCIP_BOUNDTYPE_LOWER )
1553 {
1554 /* round bounds new value if variable is integral */
1555 if( SCIPvarIsIntegral(bound->var) )
1556 newval = SCIPceil(scip, newval);
1557
1558 /* ensure that we give consistent bounds to the LP solver */
1559 if( newval > ub )
1560 newval = ub;
1561
1562 /* tighten if really better */
1563 if( SCIPisLbBetter(scip, newval, lb, ub) )
1564 {
1565 SCIP_CALL( SCIPchgVarLbProbing(scip, bound->var, newval) );
1566 *tightened = TRUE;
1567 }
1568 }
1569 else
1570 {
1571 /* round bounds new value if variable is integral */
1572 if( SCIPvarIsIntegral(bound->var) )
1573 newval = SCIPfloor(scip, newval);
1574
1575 /* ensure that we give consistent bounds to the LP solver */
1576 if( newval < lb )
1577 newval = lb;
1578
1579 /* tighten if really better */
1580 if( SCIPisUbBetter(scip, newval, lb, ub) )
1581 {
1582 SCIP_CALL( SCIPchgVarUbProbing(scip, bound->var, newval) );
1583 *tightened = TRUE;
1584 }
1585 }
1586
1587 return SCIP_OKAY;
1588}
1589
1590/** comparison method for two bounds w.r.t. their scores */
1591static
1593{
1594 BOUND* bound1 = (BOUND*) elem1;
1595 BOUND* bound2 = (BOUND*) elem2;
1596
1597 return bound1->score == bound2->score ? 0 : ( bound1->score > bound2->score ? 1 : -1 );
1598}
1599
1600/** comparison method for two bilinear term bounds w.r.t. their scores */
1601static
1602SCIP_DECL_SORTPTRCOMP(compBilinboundsScore)
1603{
1604 BILINBOUND* bound1 = (BILINBOUND*) elem1;
1605 BILINBOUND* bound2 = (BILINBOUND*) elem2;
1606
1607 return bound1->score == bound2->score ? 0 : ( bound1->score > bound2->score ? 1 : -1 ); /*lint !e777*/
1608}
1609
1610/** comparison method for two bounds w.r.t. their boundtype */
1611static
1612SCIP_DECL_SORTPTRCOMP(compBoundsBoundtype)
1613{
1614 int diff;
1615 BOUND* bound1 = (BOUND*) elem1;
1616 BOUND* bound2 = (BOUND*) elem2;
1617
1618 /* prioritize undone bounds */
1619 diff = (!bound1->done ? 1 : 0) - (!bound2->done ? 1 : 0);
1620 if( diff != 0 )
1621 return diff;
1622
1623 /* prioritize unfiltered bounds */
1624 diff = (!bound1->filtered ? 1 : 0) - (!bound2->filtered ? 1 : 0);
1625 if( diff != 0 )
1626 return diff;
1627
1628 diff = (bound1->boundtype == SCIP_BOUNDTYPE_LOWER ? 1 : 0) - (bound2->boundtype == SCIP_BOUNDTYPE_LOWER ? 1 : 0);
1629 if( diff != 0 )
1630 return diff;
1631
1632 return (bound1->score == bound2->score) ? 0 : (bound1->score > bound2->score ? 1 : -1);
1633}
1634
1635/** sort the propdata->bounds array with their distance or their boundtype key */
1636static
1638 SCIP* scip, /**< SCIP data structure */
1639 SCIP_PROPDATA* propdata /**< propagator data */
1640 )
1641{
1642 assert(scip != NULL);
1643 assert(propdata != NULL);
1644
1645 SCIPdebugMsg(scip, "sort bounds\n");
1646 SCIPsortDownPtr((void**) propdata->bounds, compBoundsBoundtype, propdata->nbounds);
1647
1648 return SCIP_OKAY;
1649}
1650
1651/** evaluates a bound for the current LP solution */
1652static
1654 SCIP* scip,
1655 BOUND* bound
1656 )
1657{
1658 assert(scip != NULL);
1659 assert(bound != NULL);
1660
1661 if( bound->boundtype == SCIP_BOUNDTYPE_LOWER )
1662 return REALABS( SCIPvarGetLPSol(bound->var) - SCIPvarGetLbLocal(bound->var) );
1663 else
1664 return REALABS( SCIPvarGetUbLocal(bound->var) - SCIPvarGetLPSol(bound->var) );
1665}
1666
1667/** returns the index of the next undone and unfiltered bound with the smallest distance */
1668static
1670 SCIP* scip, /**< SCIP data structure */
1671 SCIP_PROPDATA* propdata, /**< data of the obbt propagator */
1672 SCIP_Bool convexphase /**< consider only convex variables? */
1673 )
1674{
1675 SCIP_Real bestval;
1676 int bestidx;
1677 int k;
1678
1679 assert(scip != NULL);
1680 assert(propdata != NULL);
1681
1682 bestidx = -1;
1683 bestval = SCIPinfinity(scip);
1684
1685 for( k = 0; k <= propdata->lastidx; ++k )
1686 {
1687 BOUND* tmpbound;
1688 tmpbound = propdata->bounds[k];
1689
1690 assert(tmpbound != NULL);
1691
1692 /* variables of indicator constraints are considered as nonconvex */
1693 if( !tmpbound->filtered && !tmpbound->done && (tmpbound->nonconvex == !convexphase || tmpbound->indicator == !convexphase) )
1694 {
1695 SCIP_Real boundval;
1696
1697 /* return the next bound which is not done or unfiltered yet */
1698 if( propdata->orderingalgo == 0 )
1699 return k;
1700
1701 boundval = evalBound(scip, tmpbound);
1702
1703 /* negate boundval if we use the reverse greedy algorithm */
1704 boundval = (propdata->orderingalgo == 2) ? -1.0 * boundval : boundval;
1705
1706 if( bestidx == -1 || boundval < bestval )
1707 {
1708 bestidx = k;
1709 bestval = boundval;
1710 }
1711 }
1712 }
1713
1714 return bestidx; /*lint !e438*/
1715}
1716
1717/** try to separate the solution of the last OBBT LP in order to learn better variable bounds; we apply additional
1718 * separation rounds as long as the routine finds better bounds; because of dual degeneracy we apply a minimum number of
1719 * separation rounds
1720 */
1721static
1723 SCIP* scip, /**< SCIP data structure */
1724 SCIP_PROPDATA* propdata, /**< data of the obbt propagator */
1725 BOUND* currbound, /**< current bound */
1726 SCIP_Longint* nleftiterations, /**< number of left iterations (-1 for no limit) */
1727 SCIP_Bool* success /**< pointer to store if we have found a better bound */
1728 )
1729{
1730 SCIP_Bool inroot;
1731 int i;
1732
1733 assert(nleftiterations != NULL);
1734 assert(success != NULL);
1736
1737 *success = FALSE;
1738
1739 /* check if we are originally in the root node */
1740 inroot = SCIPgetDepth(scip) == 1;
1741
1742 for( i = 0; i <= propdata->sepamaxiter; ++i )
1743 {
1744 SCIPdebug( SCIP_Longint nlpiter; )
1745 SCIP_Real oldval;
1747 SCIP_Bool delayed;
1748 SCIP_Bool error;
1749 SCIP_Bool optimal;
1750 SCIP_Bool tightened;
1751
1752 oldval = SCIPvarGetLPSol(currbound->var);
1753
1754 /* find and store cuts to separate the current LP solution */
1755 SCIP_CALL( SCIPseparateSol(scip, NULL, inroot, TRUE, FALSE, &delayed, &cutoff) );
1756 SCIPdebugMsg(scip, "applySeparation() - ncuts = %d\n", SCIPgetNCuts(scip));
1757
1758 /* leave if we did not found any cut */
1759 if( SCIPgetNCuts(scip) == 0 )
1760 break;
1761
1762 /* apply cuts and resolve LP */
1764 assert(SCIPgetNCuts(scip) == 0);
1765 SCIPdebug( nlpiter = SCIPgetNLPIterations(scip); )
1766 SCIP_CALL( solveLP(scip, (int) *nleftiterations, &error, &optimal) );
1767 SCIPdebug( nlpiter = SCIPgetNLPIterations(scip) - nlpiter; )
1768 SCIPdebug( SCIPdebugMsg(scip, "applySeparation() - optimal=%u error=%u lpiter=%" SCIP_LONGINT_FORMAT "\n", optimal, error, nlpiter); )
1769 SCIPdebugMsg(scip, "oldval = %e newval = %e\n", oldval, SCIPvarGetLPSol(currbound->var));
1770
1771 /* leave if we did not solve the LP to optimality or an error occurred */
1772 if( error || !optimal )
1773 break;
1774
1775 /* try to generate a genvbound */
1776 if( inroot && propdata->genvboundprop != NULL && propdata->genvbdsduringsepa )
1777 {
1778 SCIP_Bool found;
1779 SCIP_CALL( createGenVBound(scip, propdata, currbound, &found) );
1780 propdata->ngenvboundsprobing += found ? 1 : 0;
1781 }
1782
1783 /* try to tight the variable bound */
1784 tightened = FALSE;
1785 if( !SCIPisEQ(scip, oldval, SCIPvarGetLPSol(currbound->var)) )
1786 {
1787 SCIP_CALL( tightenBoundProbing(scip, currbound, SCIPvarGetLPSol(currbound->var), &tightened) );
1788 SCIPdebugMsg(scip, "apply separation - tightened=%u oldval=%e newval=%e\n", tightened, oldval,
1789 SCIPvarGetLPSol(currbound->var));
1790
1791 *success |= tightened;
1792 }
1793
1794 /* leave the separation if we did not tighten the bound and proceed at least propdata->sepaminiter iterations */
1795 if( !tightened && i >= propdata->sepaminiter )
1796 break;
1797 }
1798
1799 return SCIP_OKAY;
1800}
1801
1802/** finds new variable bounds until no iterations left or all bounds have been checked */
1803static
1805 SCIP* scip, /**< SCIP data structure */
1806 SCIP_PROPDATA* propdata, /**< data of the obbt propagator */
1807 SCIP_Longint* nleftiterations, /**< pointer to store the number of left iterations */
1808 SCIP_Bool convexphase /**< consider only convex variables? */
1809 )
1810{
1811 SCIP_Longint nolditerations;
1812 SCIP_Bool iterationsleft;
1813 BOUND* currbound;
1814 SCIP_Longint itlimit;
1815 int nextboundidx;
1816
1817 assert(scip != NULL);
1818 assert(propdata != NULL);
1819 assert(nleftiterations != NULL);
1820
1821 /* update the number of left iterations */
1822 nolditerations = SCIPgetNLPIterations(scip);
1823 itlimit = *nleftiterations;
1824 assert(*nleftiterations == getIterationsLeft(scip, nolditerations, itlimit));
1825 iterationsleft = (*nleftiterations == -1) || (*nleftiterations > 0);
1826
1827 /* To improve the performance we sort the bound in such a way that the undone and
1828 * unfiltered bounds are at the end of propdata->bounds. We calculate and update
1829 * the position of the last unfiltered and undone bound in propdata->lastidx
1830 */
1831 if( !convexphase )
1832 {
1833 /* sort bounds */
1834 SCIP_CALL( sortBounds(scip, propdata) );
1835
1836 /* if the first bound is filtered or done then there is no bound left */
1837 if( propdata->bounds[0]->done || propdata->bounds[0]->filtered )
1838 {
1839 SCIPdebugMsg(scip, "no unprocessed/unfiltered bound left\n");
1840 return SCIP_OKAY;
1841 }
1842
1843 /* compute the last undone and unfiltered node */
1844 propdata->lastidx = 0;
1845 while( propdata->lastidx < propdata->nbounds - 1 && !propdata->bounds[propdata->lastidx]->done &&
1846 !propdata->bounds[propdata->lastidx]->filtered )
1847 ++propdata->lastidx;
1848
1849 SCIPdebugMsg(scip, "lastidx = %d\n", propdata->lastidx);
1850 }
1851
1852 /* find the first unprocessed bound */
1853 nextboundidx = nextBound(scip, propdata, convexphase);
1854
1855 /* skip if there is no bound left */
1856 if( nextboundidx == -1 )
1857 {
1858 SCIPdebugMsg(scip, "no unprocessed/unfiltered bound left\n");
1859 return SCIP_OKAY;
1860 }
1861
1862 currbound = propdata->bounds[nextboundidx];
1863 assert(!currbound->done && !currbound->filtered);
1864
1865 /* main loop */
1866 while( iterationsleft && !SCIPisStopped(scip) )
1867 {
1868 SCIP_Bool optimal;
1869 SCIP_Bool error;
1870 int nfiltered;
1871
1872 assert(currbound != NULL);
1873 assert(currbound->done == FALSE);
1874 assert(currbound->filtered == FALSE);
1875
1876 /* do not visit currbound more than once */
1877 currbound->done = TRUE;
1878 exchangeBounds(propdata, nextboundidx);
1879
1880 /* set objective for curr */
1881 SCIP_CALL( setObjProbing(scip, propdata, currbound, 1.0) );
1882
1883 SCIPdebugMsg(scip, "before solving Boundtype: %d , LB: %e , UB: %e\n",
1884 currbound->boundtype == SCIP_BOUNDTYPE_LOWER, SCIPvarGetLbLocal(currbound->var),
1885 SCIPvarGetUbLocal(currbound->var) );
1886 SCIPdebugMsg(scip, "before solving var <%s>, LP value: %f\n",
1887 SCIPvarGetName(currbound->var), SCIPvarGetLPSol(currbound->var));
1888
1889 SCIPdebugMsg(scip, "probing iterations before solve: %lld \n", SCIPgetNLPIterations(scip));
1890
1891 propdata->nprobingiterations -= SCIPgetNLPIterations(scip);
1892
1893 /* now solve the LP */
1894 SCIP_CALL( solveLP(scip, (int) *nleftiterations, &error, &optimal) );
1895
1896 propdata->nprobingiterations += SCIPgetNLPIterations(scip);
1897 propdata->nsolvedbounds++;
1898
1899 SCIPdebugMsg(scip, "probing iterations after solve: %lld \n", SCIPgetNLPIterations(scip));
1900 SCIPdebugMsg(scip, "OPT: %u ERROR: %u\n" , optimal, error);
1901 SCIPdebugMsg(scip, "after solving Boundtype: %d , LB: %e , UB: %e\n",
1902 currbound->boundtype == SCIP_BOUNDTYPE_LOWER, SCIPvarGetLbLocal(currbound->var),
1903 SCIPvarGetUbLocal(currbound->var) );
1904 SCIPdebugMsg(scip, "after solving var <%s>, LP value: %f\n",
1905 SCIPvarGetName(currbound->var), SCIPvarGetLPSol(currbound->var));
1906
1907 /* update nleftiterations */
1908 *nleftiterations = getIterationsLeft(scip, nolditerations, itlimit);
1909 iterationsleft = (*nleftiterations == -1) || (*nleftiterations > 0);
1910
1911 if( error )
1912 {
1913 SCIPdebugMsg(scip, "ERROR during LP solving\n");
1914
1915 /* set the objective of currbound to zero to null the whole objective; otherwise the objective is wrong when
1916 * we call findNewBounds() for the convex phase
1917 */
1918 SCIP_CALL( SCIPchgVarObjProbing(scip, currbound->var, 0.0) );
1919
1920 return SCIP_OKAY;
1921 }
1922
1923 if( optimal )
1924 {
1925 SCIP_Bool success;
1926
1927 currbound->newval = SCIPvarGetLPSol(currbound->var);
1928 currbound->found = TRUE;
1929
1930 /* in root node we may want to create a genvbound (independent of tightening success) */
1931 if( (SCIPgetDepth(scip) == 0 || (SCIPinProbing(scip) && SCIPgetDepth(scip) == 1))
1932 && propdata->genvboundprop != NULL )
1933 {
1934 SCIP_Bool found;
1935
1936 SCIP_CALL( createGenVBound(scip, propdata, currbound, &found) );
1937
1938 if( found )
1939 propdata->ngenvboundsprobing += 1;
1940 }
1941
1942 /* try to tighten bound in probing mode */
1943 success = FALSE;
1944 if( propdata->tightintboundsprobing && SCIPvarIsIntegral(currbound->var) )
1945 {
1946 SCIPdebugMsg(scip, "tightening bound %s = %e bounds: [%e, %e]\n", SCIPvarGetName(currbound->var),
1947 currbound->newval, SCIPvarGetLbLocal(currbound->var), SCIPvarGetUbLocal(currbound->var) );
1948 SCIP_CALL( tightenBoundProbing(scip, currbound, currbound->newval, &success) );
1949 SCIPdebugMsg(scip, "tightening bound %s\n", success ? "successful" : "not successful");
1950 }
1951 else if( propdata->tightcontboundsprobing && !SCIPvarIsIntegral(currbound->var) )
1952 {
1953 SCIPdebugMsg(scip, "tightening bound %s = %e bounds: [%e, %e]\n", SCIPvarGetName(currbound->var),
1954 currbound->newval, SCIPvarGetLbLocal(currbound->var), SCIPvarGetUbLocal(currbound->var) );
1955 SCIP_CALL( tightenBoundProbing(scip, currbound, currbound->newval, &success) );
1956 SCIPdebugMsg(scip, "tightening bound %s\n", success ? "successful" : "not successful");
1957 }
1958
1959 /* separate current OBBT LP solution */
1960 if( iterationsleft && propdata->separatesol )
1961 {
1962 propdata->nprobingiterations -= SCIPgetNLPIterations(scip);
1963 SCIP_CALL( applySeparation(scip, propdata, currbound, nleftiterations, &success) );
1964 propdata->nprobingiterations += SCIPgetNLPIterations(scip);
1965
1966 /* remember best solution value after solving additional separations LPs */
1967 if( success )
1968 {
1969#ifndef NDEBUG
1970 SCIP_Real newval = SCIPvarGetLPSol(currbound->var);
1971
1972 /* round new bound if the variable is integral */
1973 if( SCIPvarIsIntegral(currbound->var) )
1974 newval = currbound->boundtype == SCIP_BOUNDTYPE_LOWER ?
1975 SCIPceil(scip, newval) : SCIPfloor(scip, newval);
1976
1977 assert((currbound->boundtype == SCIP_BOUNDTYPE_LOWER &&
1978 SCIPisGT(scip, newval, currbound->newval))
1979 || (currbound->boundtype == SCIP_BOUNDTYPE_UPPER &&
1980 SCIPisLT(scip, newval, currbound->newval)));
1981#endif
1982
1983 currbound->newval = SCIPvarGetLPSol(currbound->var);
1984 }
1985 }
1986
1987 /* filter bound candidates by using the current LP solution */
1988 if( propdata->applytrivialfilter )
1989 {
1990 SCIP_CALL( filterExistingLP(scip, propdata, &nfiltered, currbound) );
1991 SCIPdebugMsg(scip, "filtered %d bounds via inspecting present LP solution\n", nfiltered);
1992 propdata->ntrivialfiltered += nfiltered;
1993 }
1994
1995 propdata->propagatecounter += success ? 1 : 0;
1996
1997 /* propagate if we have found enough bound tightenings */
1998 if( propdata->propagatefreq != 0 && propdata->propagatecounter >= propdata->propagatefreq )
1999 {
2000 SCIP_Longint ndomredsfound;
2002
2003 SCIP_CALL( SCIPpropagateProbing(scip, 0, &cutoff, &ndomredsfound) );
2004 SCIPdebugMsg(scip, "propagation - cutoff %u ndomreds %" SCIP_LONGINT_FORMAT "\n", cutoff, ndomredsfound);
2005
2006 propdata->npropagatedomreds += ndomredsfound;
2007 propdata->propagatecounter = 0;
2008 }
2009 }
2010
2011 /* set objective to zero */
2012 SCIP_CALL( setObjProbing(scip, propdata, currbound, 0.0) );
2013
2014 /* find the first unprocessed bound */
2015 nextboundidx = nextBound(scip, propdata, convexphase);
2016
2017 /* check if there is no unprocessed and unfiltered node left */
2018 if( nextboundidx == -1 )
2019 {
2020 SCIPdebugMsg(scip, "NO unvisited/unfiltered bound left!\n");
2021 break;
2022 }
2023
2024 currbound = propdata->bounds[nextboundidx];
2025 assert(!currbound->done && !currbound->filtered);
2026 }
2027
2028 if( iterationsleft )
2029 {
2030 SCIPdebugMsg(scip, "still iterations left: %" SCIP_LONGINT_FORMAT "\n", *nleftiterations);
2031 }
2032 else
2033 {
2034 SCIPdebugMsg(scip, "no iterations left\n");
2035 }
2036
2037 return SCIP_OKAY;
2038}
2039
2040
2041/** main function of obbt */
2042static
2044 SCIP* scip, /**< SCIP data structure */
2045 SCIP_PROPDATA* propdata, /**< data of the obbt propagator */
2046 SCIP_Longint itlimit, /**< LP iteration limit (-1: no limit) */
2047 SCIP_RESULT* result /**< result pointer */
2048 )
2049{
2050 SCIP_VAR** vars;
2051 SCIP_Real* oldlbs;
2052 SCIP_Real* oldubs;
2053 SCIP_Longint lastnpropagatedomreds;
2054 SCIP_Longint nleftiterations;
2055 SCIP_Real oldconditionlimit;
2056 SCIP_Real oldboundstreps;
2057 SCIP_Real olddualfeastol;
2058 SCIP_Bool hasconditionlimit;
2059 SCIP_Bool continuenode;
2060 SCIP_Bool boundleft;
2061 int oldpolishing;
2062 int nfiltered;
2063 int nvars;
2064 int i;
2065
2066 assert(scip != NULL);
2067 assert(propdata != NULL);
2068 assert(itlimit == -1 || itlimit >= 0);
2069
2070 SCIPdebugMsg(scip, "apply obbt\n");
2071
2072 oldlbs = NULL;
2073 oldubs = NULL;
2074 lastnpropagatedomreds = propdata->npropagatedomreds;
2075 nleftiterations = itlimit;
2076 continuenode = SCIPnodeGetNumber(SCIPgetCurrentNode(scip)) == propdata->lastnode;
2077 propdata->lastidx = -1;
2078 boundleft = FALSE;
2080
2081 /* store old variable bounds if we use propagation during obbt */
2082 if( propdata->propagatefreq > 0 )
2083 {
2084 SCIP_CALL( SCIPallocBufferArray(scip, &oldlbs, propdata->nbounds) );
2085 SCIP_CALL( SCIPallocBufferArray(scip, &oldubs, propdata->nbounds) );
2086 }
2087
2088 /* reset bound data structure flags; fixed variables are marked as filtered */
2089 for( i = 0; i < propdata->nbounds; i++ )
2090 {
2091 BOUND* bound = propdata->bounds[i];
2092 bound->found = FALSE;
2093
2094 /* store old variable bounds */
2095 if( oldlbs != NULL && oldubs != NULL )
2096 {
2097 oldlbs[bound->index] = SCIPvarGetLbLocal(bound->var);
2098 oldubs[bound->index] = SCIPvarGetUbLocal(bound->var);
2099 }
2100
2101 /* reset 'done' and 'filtered' flag in a new B&B node */
2102 if( !continuenode )
2103 {
2104 bound->done = FALSE;
2105 bound->filtered = FALSE;
2106 }
2107
2108 /* mark fixed variables as filtered */
2109 bound->filtered |= varIsFixedLocal(scip, bound->var);
2110
2111 /* check for an unprocessed bound */
2112 if( !bound->filtered && !bound->done )
2113 boundleft = TRUE;
2114 }
2115
2116 /* no bound left to check */
2117 if( !boundleft )
2118 goto TERMINATE;
2119
2120 /* filter variables via inspecting present LP solution */
2121 if( propdata->applytrivialfilter && !continuenode )
2122 {
2123 SCIP_CALL( filterExistingLP(scip, propdata, &nfiltered, NULL) );
2124 SCIPdebugMsg(scip, "filtered %d bounds via inspecting present LP solution\n", nfiltered);
2125 propdata->ntrivialfiltered += nfiltered;
2126 }
2127
2128 /* store old dualfeasibletol */
2129 olddualfeastol = SCIPdualfeastol(scip);
2130
2131 /* start probing */
2133 SCIPdebugMsg(scip, "start probing\n");
2134
2135 /* tighten dual feastol */
2136 if( propdata->dualfeastol < olddualfeastol )
2137 {
2138 SCIP_CALL( SCIPchgDualfeastol(scip, propdata->dualfeastol) );
2139 }
2140
2141 /* tighten condition limit */
2142 hasconditionlimit = (SCIPgetRealParam(scip, "lp/conditionlimit", &oldconditionlimit) == SCIP_OKAY);
2143 if( !hasconditionlimit )
2144 {
2145 SCIPwarningMessage(scip, "obbt propagator could not set condition limit in LP solver - running without\n");
2146 }
2147 else if( propdata->conditionlimit > 0.0 && (oldconditionlimit < 0.0 || propdata->conditionlimit < oldconditionlimit) )
2148 {
2149 SCIP_CALL( SCIPsetRealParam(scip, "lp/conditionlimit", propdata->conditionlimit) );
2150 }
2151
2152 /* tighten relative bound improvement limit */
2153 SCIP_CALL( SCIPgetRealParam(scip, "numerics/boundstreps", &oldboundstreps) );
2154 if( !SCIPisEQ(scip, oldboundstreps, propdata->boundstreps) )
2155 {
2156 SCIP_CALL( SCIPsetRealParam(scip, "numerics/boundstreps", propdata->boundstreps) );
2157 }
2158
2159 /* add objective cutoff */
2160 SCIP_CALL( addObjCutoff(scip, propdata) );
2161
2162 /* deactivate LP polishing */
2163 SCIP_CALL( SCIPgetIntParam(scip, "lp/solutionpolishing", &oldpolishing) );
2164 SCIP_CALL( SCIPsetIntParam(scip, "lp/solutionpolishing", 0) );
2165
2166 /* apply filtering */
2167 if( propdata->applyfilterrounds )
2168 {
2169 SCIP_CALL( filterBounds(scip, propdata, nleftiterations) );
2170 }
2171
2172 /* set objective coefficients to zero */
2175 for( i = 0; i < nvars; ++i )
2176 {
2177 /* note that it is not possible to change the objective of non-column variables during probing; we have to take
2178 * care of the objective contribution of loose variables in createGenVBound()
2179 */
2181 {
2183 }
2184 }
2185
2186 /* find new bounds for the variables */
2187 SCIP_CALL( findNewBounds(scip, propdata, &nleftiterations, FALSE) );
2188
2189 if( nleftiterations > 0 || itlimit < 0 )
2190 {
2191 SCIP_CALL( findNewBounds(scip, propdata, &nleftiterations, TRUE) );
2192 }
2193
2194 /* reset dual feastol and condition limit */
2195 SCIP_CALL( SCIPchgDualfeastol(scip, olddualfeastol) );
2196 if( hasconditionlimit )
2197 {
2198 SCIP_CALL( SCIPsetRealParam(scip, "lp/conditionlimit", oldconditionlimit) );
2199 }
2200
2201 /* update bound->newval if we have learned additional bound tightenings during SCIPpropagateProbing() */
2202 if( oldlbs != NULL && oldubs != NULL && propdata->npropagatedomreds - lastnpropagatedomreds > 0 )
2203 {
2204 assert(propdata->propagatefreq > 0);
2205 for( i = 0; i < propdata->nbounds; ++i )
2206 {
2207 BOUND* bound = propdata->bounds[i];
2208
2209 /* it might be the case that a bound found by the additional propagation is better than the bound found after solving an OBBT
2210 * LP
2211 */
2212 if( bound->found )
2213 {
2214 if( bound->boundtype == SCIP_BOUNDTYPE_LOWER )
2215 bound->newval = MAX(bound->newval, SCIPvarGetLbLocal(bound->var)); /*lint !e666*/
2216 else
2217 bound->newval = MIN(bound->newval, SCIPvarGetUbLocal(bound->var)); /*lint !e666*/
2218 }
2219 else
2220 {
2221 SCIP_Real oldlb;
2222 SCIP_Real oldub;
2223
2224 oldlb = oldlbs[bound->index];
2225 oldub = oldubs[bound->index];
2226
2227 if( bound->boundtype == SCIP_BOUNDTYPE_LOWER && SCIPisLbBetter(scip, SCIPvarGetLbLocal(bound->var), oldlb, oldub) )
2228 {
2229 SCIPdebugMsg(scip, "tighter lower bound due to propagation: %d - %e -> %e\n", i, oldlb, SCIPvarGetLbLocal(bound->var));
2230 bound->newval = SCIPvarGetLbLocal(bound->var);
2231 bound->found = TRUE;
2232 }
2233
2234 if( bound->boundtype == SCIP_BOUNDTYPE_UPPER && SCIPisUbBetter(scip, SCIPvarGetUbLocal(bound->var), oldlb, oldub) )
2235 {
2236 SCIPdebugMsg(scip, "tighter upper bound due to propagation: %d - %e -> %e\n", i, oldub, SCIPvarGetUbLocal(bound->var));
2237 bound->newval = SCIPvarGetUbLocal(bound->var);
2238 bound->found = TRUE;
2239 }
2240 }
2241 }
2242 }
2243
2244 /* reset relative bound improvement limit */
2245 SCIP_CALL( SCIPsetRealParam(scip, "numerics/boundstreps", oldboundstreps) );
2246
2247 /* reset original LP polishing setting */
2248 SCIP_CALL( SCIPsetIntParam(scip, "lp/solutionpolishing", oldpolishing) );
2249
2250 /* end probing */
2252 SCIPdebugMsg(scip, "end probing!\n");
2253
2254 /* release cutoff row if there is one */
2255 if( propdata->cutoffrow != NULL )
2256 {
2257 assert(!SCIProwIsInLP(propdata->cutoffrow));
2258 SCIP_CALL( SCIPreleaseRow(scip, &(propdata->cutoffrow)) );
2259 }
2260
2261 /* apply buffered bound changes */
2262 SCIP_CALL( applyBoundChgs(scip, propdata, result) );
2263
2264TERMINATE:
2265 SCIPfreeBufferArrayNull(scip, &oldubs);
2266 SCIPfreeBufferArrayNull(scip, &oldlbs);
2267
2268 return SCIP_OKAY;
2269}
2270
2271/** computes a valid inequality from the current LP relaxation for a bilinear term xy only involving x and y; the
2272 * inequality is found by optimizing along the line connecting the points (xs,ys) and (xt,yt) over the currently given
2273 * linear relaxation of the problem; this optimization problem is an LP
2274 *
2275 * max lambda
2276 * s.t. Ax <= b
2277 * (x,y) = (xs,ys) + lambda ((xt,yt) - (xs,ys))
2278 * lambda in [0,1]
2279 *
2280 * which is equivalent to
2281 *
2282 * max x
2283 * s.t. (1) Ax <= b
2284 * (2) (x - xs) / (xt - xs) = (y - ys) / (yt - ys)
2285 *
2286 * Let x* be the optimal primal and (mu,theta) be the optimal dual solution of this LP. The KKT conditions imply that
2287 * the aggregation of the linear constraints mu*Ax <= mu*b can be written as
2288 *
2289 * x * (1 - theta) / (xt - xs) + y * theta / (yt - ys) = mu * Ax <= mu * b
2290 *
2291 * <=> alpha * x + beta * y <= mu * b = alpha * (x*) + beta * (y*)
2292 *
2293 * which is a valid inequality in the (x,y)-space; in order to avoid numerical difficulties when (xs,ys) is too close
2294 * to (xt,yt), we scale constraint (1) by max{1,|xt-xs|,|yt-ys|} beforehand
2295 */
2296static
2298 SCIP* scip, /**< SCIP data structure */
2299 SCIP_VAR* x, /**< first variable */
2300 SCIP_VAR* y, /**< second variable */
2301 SCIP_Real xs, /**< x-coordinate of the first point */
2302 SCIP_Real ys, /**< y-coordinate of the first point */
2303 SCIP_Real xt, /**< x-coordinate of the second point */
2304 SCIP_Real yt, /**< y-coordinate of the second point */
2305 SCIP_Real* xcoef, /**< pointer to store the coefficient of x */
2306 SCIP_Real* ycoef, /**< pointer to store the coefficient of y */
2307 SCIP_Real* constant, /**< pointer to store the constant */
2308 SCIP_Longint iterlim, /**< iteration limit (-1: for no limit) */
2309 int* nnonzduals /**< buffer to store the number of non-zero dual multipliers except for
2310 * the auxiliary row (NULL if not needed) */
2311 )
2312{
2313 SCIP_ROW* row;
2314 SCIP_Real signx;
2315 SCIP_Real scale;
2316 SCIP_Real side;
2318
2319 assert(xcoef != NULL);
2320 assert(ycoef != NULL);
2321 assert(constant != NULL);
2323
2324 *xcoef = SCIP_INVALID;
2325 *ycoef = SCIP_INVALID;
2326 *constant= SCIP_INVALID;
2327 if( nnonzduals != NULL )
2328 *nnonzduals = 0;
2329
2330 SCIPdebugMsg(scip, " solve bilinear LP for (%s,%s) from (%g,%g) to (%g,%g)\n", SCIPvarGetName(x), SCIPvarGetName(y), xs,
2331 ys, xt, yt);
2332
2333 /* skip computations if (xs,ys) and (xt,yt) are too close to each other or contain too large values */
2334 if( SCIPisFeasEQ(scip, xs, xt) || SCIPisFeasEQ(scip, ys, yt)
2337 {
2338 SCIPdebugMsg(scip, " -> skip: bounds are too close/large\n");
2339 return SCIP_OKAY;
2340 }
2341
2342 /* compute scaler for the additional linear constraint */
2343 scale = MIN(MAX3(1.0, REALABS(xt-xs), REALABS(yt-ys)), 100.0); /*lint !e666*/
2344
2345 /* set objective function */
2346 signx = (xs > xt) ? 1.0 : -1.0;
2348
2349 /* create new probing node to remove the added LP row afterwards */
2351
2352 /* create row */
2353 side = scale * (xs/(xt-xs) - ys/(yt-ys));
2354 SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, "bilinrow", side, side, FALSE, FALSE, TRUE) );
2355 SCIP_CALL( SCIPaddVarToRow(scip, row, x, scale/(xt-xs)) );
2356 SCIP_CALL( SCIPaddVarToRow(scip, row, y, -scale/(yt-ys)) );
2358
2359 /* solve probing LP */
2360#ifdef NDEBUG
2361 {
2362 SCIP_RETCODE retstat;
2363 retstat = SCIPsolveProbingLP(scip, iterlim, &lperror, NULL);
2364 if( retstat != SCIP_OKAY )
2365 {
2366 SCIPwarningMessage(scip, "Error while solving LP in quadratic constraint handler; LP solve terminated with" \
2367 "code <%d>\n", retstat);
2368 }
2369 }
2370#else
2371 SCIP_CALL( SCIPsolveProbingLP(scip, (int)iterlim, &lperror, NULL) ); /*lint !e712*/
2372#endif
2373
2374 SCIPdebugMsg(scip, " solved probing LP -> lperror=%u lpstat=%d\n", lperror, SCIPgetLPSolstat(scip));
2375
2376 /* collect dual and primal solution entries */
2378 {
2379 SCIP_Real xval = SCIPvarGetLPSol(x);
2380 SCIP_Real yval = SCIPvarGetLPSol(y);
2381 SCIP_Real mu = -SCIProwGetDualsol(row);
2382
2383 SCIPdebugMsg(scip, " primal=(%g,%g) dual=%g\n", xval, yval, mu);
2384
2385 /* xcoef x + ycoef y <= constant */
2386 *xcoef = -signx - (mu * scale) / (xt - xs);
2387 *ycoef = (mu * scale) / (yt - ys);
2388 *constant = (*xcoef) * xval + (*ycoef) * yval;
2389
2390 /* xcoef x <= -ycoef y + constant */
2391 *ycoef = -(*ycoef);
2392
2393 /* inequality is only useful when both coefficients are different from zero; normalize inequality if possible */
2394 if( !SCIPisFeasZero(scip, *xcoef) && !SCIPisFeasZero(scip, *ycoef) )
2395 {
2396 SCIP_Real val = REALABS(*xcoef);
2397 int r;
2398
2399 *xcoef /= val;
2400 *ycoef /= val;
2401 *constant /= val;
2402
2403 if( SCIPisZero(scip, *constant) )
2404 *constant = 0.0;
2405
2406 if( nnonzduals != NULL )
2407 {
2408 /* count the number of non-zero dual multipliers except for the added row */
2409 for( r = 0; r < SCIPgetNLPRows(scip); ++r )
2410 {
2412 ++(*nnonzduals);
2413 }
2414 }
2415 }
2416 else
2417 {
2418 *xcoef = SCIP_INVALID;
2419 *ycoef = SCIP_INVALID;
2420 *constant = SCIP_INVALID;
2421 }
2422 }
2423
2424 /* release row and backtrack probing node */
2425 SCIP_CALL( SCIPreleaseRow(scip, &row) );
2427
2428 /* reset objective function */
2430
2431 return SCIP_OKAY;
2432}
2433
2434/* applies obbt for finding valid inequalities for bilinear terms; function works as follows:
2435 *
2436 * 1. start probing mode
2437 * 2. add objective cutoff (if possible)
2438 * 3. set objective function to zero
2439 * 4. set feasibility, optimality, and relative bound improvement tolerances of SCIP
2440 * 5. main loop
2441 * 6. restore old tolerances
2442 *
2443 */
2444static
2446 SCIP* scip, /**< SCIP data structure */
2447 SCIP_PROPDATA* propdata, /**< data of the obbt propagator */
2448 SCIP_Longint itlimit, /**< LP iteration limit (-1: no limit) */
2449 SCIP_RESULT* result /**< result pointer */
2450 )
2451{
2452 SCIP_VAR** vars;
2453 SCIP_Real oldfeastol;
2455 SCIP_Longint nolditerations;
2456 SCIP_Longint nleftiterations;
2457 SCIP_CONSHDLR* conshdlr;
2458 SCIP_NLHDLR* bilinearnlhdlr;
2459 int nvars;
2460 int i;
2461
2462 assert(scip != NULL);
2463 assert(propdata != NULL);
2464 assert(itlimit == -1 || itlimit >= 0);
2465 assert(result != NULL);
2466
2467 if( propdata->nbilinbounds <= 0 || SCIPgetDepth(scip) != 0 || propdata->lastbilinidx >= propdata->nbilinbounds )
2468 return SCIP_OKAY;
2469
2470 SCIPdebugMsg(scip, "call applyObbtBilinear starting from %d\n", propdata->lastbilinidx);
2471
2472 /* find nonlinear handler for bilinear terms */
2473 conshdlr = SCIPfindConshdlr(scip, "nonlinear");
2474 bilinearnlhdlr = conshdlr != NULL ? SCIPfindNlhdlrNonlinear(conshdlr, "bilinear") : NULL;
2475
2476 /* no nonlinear handler available -> skip */
2477 if( bilinearnlhdlr == NULL )
2478 return SCIP_OKAY;
2479
2482
2483 nolditerations = SCIPgetNLPIterations(scip);
2484 nleftiterations = getIterationsLeft(scip, nolditerations, itlimit);
2485 SCIPdebugMsg(scip, "iteration limit: %lld\n", nleftiterations);
2486
2487 /* 1. start probing */
2489
2490 /* 2. add objective cutoff */
2491 SCIP_CALL( addObjCutoff(scip, propdata) );
2492
2493 /* 3. set objective function to zero */
2494 for( i = 0; i < nvars; ++i )
2495 {
2497 }
2498
2499 /* 4. tighten LP feasibility tolerance to be at most feastol/10.0 */
2500 oldfeastol = SCIPchgRelaxfeastol(scip, SCIPfeastol(scip) / 10.0);
2501
2502 /* we need to solve the probing LP before creating new probing nodes in solveBilinearLP() */
2503 SCIP_CALL( SCIPsolveProbingLP(scip, (int)nleftiterations, &lperror, NULL) );
2504
2505 if( lperror )
2506 goto TERMINATE;
2507
2508 /* 5. main loop */
2509 for( i = propdata->lastbilinidx; i < propdata->nbilinbounds
2510 && (nleftiterations > 0 || nleftiterations == -1)
2511 && (propdata->itlimitbilin < 0 || propdata->itlimitbilin > propdata->itusedbilin )
2512 && !SCIPisStopped(scip); ++i )
2513 {
2514 CORNER corners[4] = {LEFTBOTTOM, LEFTTOP, RIGHTTOP, RIGHTBOTTOM};
2515 BILINBOUND* bilinbound;
2516 int k;
2517
2518 bilinbound = propdata->bilinbounds[i];
2519 assert(bilinbound != NULL);
2520
2521 SCIPdebugMsg(scip, "process %d: %s %s done=%u filtered=%d nunderest=%d noverest=%d\n", i,
2522 SCIPvarGetName(bilinboundGetX(bilinbound)), SCIPvarGetName(bilinboundGetY(bilinbound)), bilinbound->done,
2523 bilinbound->filtered, bilinboundGetLocksNeg(bilinbound), bilinboundGetLocksPos(bilinbound));
2524
2525 /* we already solved LPs for this bilinear term */
2526 if( bilinbound->done || bilinbound->filtered == (int)FILTERED )
2527 continue;
2528
2529 /* iterate through all corners
2530 *
2531 * 0: (xs,ys)=(ubx,lby) (xt,yt)=(lbx,uby) -> underestimate
2532 * 1: (xs,ys)=(ubx,uby) (xt,yt)=(lbx,lby) -> overestimate
2533 * 2: (xs,ys)=(lbx,uby) (xt,yt)=(ubx,lby) -> underestimate
2534 * 3: (xs,ys)=(lbx,lby) (xt,yt)=(ubx,uby) -> overestimate
2535 */
2536 for( k = 0; k < 4; ++k )
2537 {
2538 CORNER corner = corners[k];
2539 SCIP_VAR* x = bilinboundGetX(bilinbound);
2540 SCIP_VAR* y = bilinboundGetY(bilinbound);
2541 SCIP_Real xcoef;
2542 SCIP_Real ycoef;
2543 SCIP_Real constant;
2548 int nnonzduals = 0;
2549
2550 /* skip corners that lead to an under- or overestimate that is not needed */
2551 if( ((corner == LEFTTOP || corner == RIGHTBOTTOM) && bilinboundGetLocksPos(bilinbound) == 0)
2552 || ((corner == LEFTBOTTOM || corner == RIGHTTOP) && bilinboundGetLocksNeg(bilinbound) == 0) )
2553 continue;
2554
2555 /* check whether corner has been filtered already */
2556 if( (bilinbound->filtered & corner) != 0 ) /*lint !e641*/
2557 continue;
2558
2559 /* get corners (xs,ys) and (xt,yt) */
2560 getCorners(x, y, corner, &xs, &ys, &xt, &yt);
2561
2562 /* skip target corner points with too large values */
2564 continue;
2565
2566 /* compute inequality */
2567 propdata->itusedbilin -= SCIPgetNLPIterations(scip);
2568 SCIP_CALL( solveBilinearLP(scip, x, y, xs, ys, xt, yt, &xcoef, &ycoef, &constant, -1L,
2569 propdata->createlincons ? &nnonzduals : NULL) ); /*lint !e826*/
2570 propdata->itusedbilin += SCIPgetNLPIterations(scip);
2571
2572 /* update number of LP iterations */
2573 nleftiterations = getIterationsLeft(scip, nolditerations, itlimit);
2574 SCIPdebugMsg(scip, "LP iterations left: %lld\n", nleftiterations);
2575
2576 /* add inequality to quadratic constraint handler if it separates (xt,yt) */
2577 if( !SCIPisHugeValue(scip, xcoef) && !SCIPisFeasZero(scip, xcoef)
2578 && REALABS(ycoef) < 1e+3 && REALABS(ycoef) > 1e-3 /* TODO add a parameter for this */
2579 && SCIPisFeasGT(scip, (xcoef*xt - ycoef*yt - constant) / sqrt(SQR(xcoef) + SQR(ycoef) + SQR(constant)), 1e-2) )
2580 {
2581 SCIP_Bool success;
2582
2583 /* add inequality to the associated product expression */
2584 SCIP_CALL( SCIPaddIneqBilinear(scip, bilinearnlhdlr, bilinbound->expr, xcoef, ycoef,
2585 constant, &success) );
2586
2587 /* check whether the inequality has been accepted */
2588 if( success )
2589 {
2591 SCIPdebugMsg(scip, " found %g x <= %g y + %g with violation %g\n", xcoef, ycoef, constant,
2592 (xcoef*xt - ycoef*yt - constant) / sqrt(SQR(xcoef) + SQR(ycoef) + SQR(constant)));
2593
2594 /* create a linear constraint that is only used for propagation */
2595 if( propdata->createlincons && nnonzduals > 1 )
2596 {
2597 SCIP_CONS* cons;
2598 char name[SCIP_MAXSTRLEN];
2599 SCIP_VAR* linvars[2] = {x, y};
2600 SCIP_Real linvals[2] = {xcoef, -ycoef};
2601 SCIP_Real rhs = constant;
2602
2603 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "bilincons_%s_%s", SCIPvarGetName(x), SCIPvarGetName(y));
2604 SCIP_CALL( SCIPcreateConsLinear(scip, &cons, name, 2, linvars, linvals, -SCIPinfinity(scip), rhs,
2606
2607 SCIP_CALL( SCIPaddCons(scip, cons) );
2608 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
2609 }
2610 }
2611 }
2612 }
2613
2614 /* mark the bound as processed */
2615 bilinbound->done = TRUE;
2616 }
2617
2618 /* remember last unprocessed bilinear term */
2619 propdata->lastbilinidx = i;
2620
2621 TERMINATE:
2622 /* end probing */
2624
2625 /* release cutoff row if there is one */
2626 if( propdata->cutoffrow != NULL )
2627 {
2628 assert(!SCIProwIsInLP(propdata->cutoffrow));
2629 SCIP_CALL( SCIPreleaseRow(scip, &(propdata->cutoffrow)) );
2630 }
2631
2632 /* 6. restore old tolerance */
2633 (void) SCIPchgRelaxfeastol(scip, oldfeastol);
2634
2635 return SCIP_OKAY;
2636}
2637
2638/** computes the score of a bound */
2639static
2640unsigned int getScore(
2641 SCIP* scip, /**< SCIP data structure */
2642 BOUND* bound, /**< pointer of bound */
2643 int nlcount, /**< number of nonlinear constraints containing the bounds variable */
2644 int nindcount, /**< number of indicator constraints containing the bounds variable */
2645 int maxnlcount, /**< maximal number of nonlinear and indicator constraints a variable appears in */
2646 SCIP_Real smallub /**< variables with upper bound smaller than this value are counted in half iff part of indicator constraints */
2647 )
2648{
2649 SCIP_Real counter;
2650 unsigned int score; /* score to be computed */
2651
2652 assert(scip != NULL);
2653 assert(bound != NULL);
2654 assert(nlcount >= 0);
2655 assert(nindcount >= 0);
2656 assert(maxnlcount >= nlcount + nindcount);
2657
2658 counter = nlcount;
2659 if( nindcount > 0 )
2660 {
2661 /* variables with small upper bound are counted in half
2662 * since the probability is high that the corresponding indicator constraint is already reformulated as bigM constraint
2663 */
2664 if( SCIPvarGetUbLocal(bound->var) <= smallub )
2665 counter += 0.5 * nindcount;
2666 else
2667 counter += nindcount;
2668 }
2669
2670 /* score = ( nlcount * ( BASE - 1 ) / maxnlcount ) * BASE^2 + vartype * BASE + boundtype */
2671 score = (unsigned int) ( counter > 0 ? (OBBT_SCOREBASE * counter * ( OBBT_SCOREBASE - 1 )) / maxnlcount : 0 ); /*lint !e414*/
2673 score += 2;
2674 else
2675 {
2676 switch( SCIPvarGetType(bound->var) )
2677 {
2679 score += 4;
2680 break;
2682 score += 1;
2683 break;
2685 score += 3;
2686 break;
2687 default:
2688 SCIPerrorMessage("invalid variable type\n");
2689 SCIPABORT();
2690 return 0; /*lint !e527*/
2691 } /*lint !e788*/
2692 }
2693
2694 score *= OBBT_SCOREBASE;
2695 if( bound->boundtype == SCIP_BOUNDTYPE_UPPER )
2696 score += 1;
2697
2698 return score;
2699}
2700
2701/** count how often each variable is used in a nonconvex term */
2702static
2704 SCIP* scip, /**< SCIP data structure */
2705 unsigned int* nccounts /**< store the number each variable appears in a
2706 * non-convex term */
2707 )
2708{
2709 SCIP_CONSHDLR* conshdlr;
2710 SCIP_HASHMAP* var2expr;
2711 int nvars;
2712 int i;
2713
2714 assert(scip != NULL);
2715 assert(nccounts != NULL);
2716
2718
2719 /* initialize nccounts to zero */
2720 BMSclearMemoryArray(nccounts, nvars);
2721
2722 /* get nonlinear constraint handler */
2723 conshdlr = SCIPfindConshdlr(scip, "nonlinear");
2724 if( conshdlr == NULL || SCIPconshdlrGetNConss(conshdlr) == 0 )
2725 return SCIP_OKAY;
2726
2727 var2expr = SCIPgetVarExprHashmapNonlinear(conshdlr);
2728 assert(var2expr != NULL);
2729
2730 for( i = 0; i < SCIPgetNVars(scip); ++i )
2731 {
2732 SCIP_VAR* var;
2733
2734 var = SCIPgetVars(scip)[i];
2735 assert(var != NULL);
2736
2737 if( SCIPhashmapExists(var2expr, (void*) var) )
2738 {
2739 SCIP_EXPR* expr = (SCIP_EXPR*)SCIPhashmapGetImage(var2expr, (void*) var);
2740 assert(expr != NULL);
2741 assert(SCIPisExprVar(scip, expr));
2742
2744 }
2745 }
2746
2747#ifdef SCIP_DEBUG
2748 for( i = 0; i < SCIPgetNVars(scip); ++i)
2749 {
2751 assert(var != NULL);
2752 SCIPdebugMsg(scip, "nccounts[%s] = %u\n", SCIPvarGetName(var), nccounts[SCIPvarGetProbindex(var)]);
2753 }
2754#endif
2755
2756 return SCIP_OKAY;
2757}
2758
2759/** computes for each variable the number of indicator constraints in which the variable appears */
2760static
2762 SCIP* scip, /**< SCIP data structure */
2763 int* nindcount /**< array that stores in how many indicator conss each variable appears */
2764 )
2765{
2766 SCIP_CONSHDLR* conshdlr;
2767 SCIP_CONS** indconss;
2768 int nvars;
2769 int nindconss;
2770
2771 assert(scip != NULL);
2772 assert(nindcount != NULL);
2773
2775
2776 /* initialize nindcount to zero */
2777 BMSclearMemoryArray(nindcount, nvars);
2778
2779 /* get indicator constraint handler */
2780 conshdlr = SCIPfindConshdlr(scip, "indicator");
2781 if( conshdlr == NULL || SCIPconshdlrGetNConss(conshdlr) == 0 )
2782 return SCIP_OKAY;
2783
2784 nindconss = SCIPconshdlrGetNConss(conshdlr);
2785 indconss = SCIPconshdlrGetConss(conshdlr);
2786
2787 for( int i = 0; i < nindconss; ++i )
2788 {
2789 SCIP_VAR** consvars;
2790 SCIP_VAR* slackvar;
2791 SCIP_CONS* lincons;
2792 int nconsvars;
2793
2794 lincons = SCIPgetLinearConsIndicator(indconss[i]);
2795 assert(lincons!=NULL);
2796
2797 nconsvars = SCIPgetNVarsLinear(scip, lincons);
2798 consvars = SCIPgetVarsLinear(scip, lincons);
2799 assert(consvars != NULL);
2800 slackvar = SCIPgetSlackVarIndicator(indconss[i]);
2801
2802 for( int v = 0; v < nconsvars; ++v )
2803 {
2804 /* we should skip the slackvariable */
2805 if( consvars[v] == slackvar )
2806 continue;
2807
2808 /* consider only active variables */
2809 if( SCIPvarGetStatus(consvars[v]) == SCIP_VARSTATUS_COLUMN )
2810 {
2811 nindcount[SCIPvarGetProbindex(consvars[v])] += 1;
2812 }
2813 }
2814 }
2815
2816 return SCIP_OKAY;
2817}
2818
2819/** determines whether a variable is interesting */
2820static
2822 SCIP* scip, /**< SCIP data structure */
2823 SCIP_VAR* var, /**< variable to check */
2824 int nlcount, /**< number of nonlinear constraints containing the variable
2825 * or number of non-convex terms containing the variable
2826 * (depends on propdata->onlynonconvexvars) */
2827 int nindcount /**< number of indicator constraints containing the variable
2828 * or 0 (depends on propdata->indicators) */
2829 )
2830{
2831 assert(SCIPgetDepth(scip) == 0);
2832
2833 return !SCIPvarIsBinary(var) && SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN && (nlcount > 0 || nindcount > 0)
2834 && !varIsFixedLocal(scip, var);
2835}
2836
2837/** initializes interesting bounds */
2838static
2840 SCIP* scip, /**< SCIP data structure */
2841 SCIP_PROPDATA* propdata /**< data of the obbt propagator */
2842 )
2843{
2844 SCIP_CONSHDLR* conshdlr;
2845 SCIP_VAR** vars; /* array of the problems variables */
2846 int* nlcount; /* array that stores in how many nonlinearities each variable appears */
2847 int* nindcount; /* array that stores in how many indicator constraints each variable appears */
2848 unsigned int* nccount; /* array that stores in how many nonconvexities each variable appears */
2849 SCIP_Real maxcouplingvalue;
2850 SCIP_Real sepacouplingvalue;
2851 SCIP_Real smallub;
2852
2853 int bdidx; /* bound index inside propdata->bounds */
2854 int maxnlcount; /* maximal number of nonlinear and indicator constraints a variable appears in */
2855 int nvars; /* number of the problems variables */
2856 int i;
2857
2858 assert(scip != NULL);
2859 assert(propdata != NULL);
2860 assert(SCIPisNLPConstructed(scip) || propdata->indicators);
2861
2862 SCIPdebugMsg(scip, "initialize bounds\n");
2863
2864 /* get variable data */
2866
2869 SCIP_CALL( SCIPallocBufferArray(scip, &nindcount, nvars) );
2870
2871 /* count nonlinearities */
2873 {
2877 }
2878 else
2879 {
2880 /* initialize to zero */
2881 BMSclearMemoryArray(nlcount, nvars);
2882 BMSclearMemoryArray(nccount, nvars);
2883 }
2884
2885 /* count indicators */
2886 if( propdata->indicators )
2887 {
2888 SCIP_CALL( getNVarsIndicators(scip, nindcount) );
2889 }
2890 else
2891 {
2892 /* initialize to zero */
2893 BMSclearMemoryArray(nindcount, nvars);
2894 }
2895
2896 maxnlcount = 0;
2897 for( i = 0; i < nvars; i++ )
2898 {
2899 if( maxnlcount < (nlcount[i] + nindcount[i]) )
2900 maxnlcount = nlcount[i] + nindcount[i];
2901 }
2902
2903 /* allocate interesting bounds array */
2904 propdata->boundssize = 2 * nvars;
2905 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(propdata->bounds), 2 * nvars) );
2906
2907 SCIP_CALL( SCIPgetRealParam(scip, "constraints/indicator/maxcouplingvalue", &maxcouplingvalue) );
2908 SCIP_CALL( SCIPgetRealParam(scip, "constraints/indicator/sepacouplingvalue", &sepacouplingvalue) );
2909
2910 smallub = MIN(maxcouplingvalue, sepacouplingvalue);
2911
2912 /* get all interesting variables and their bounds */
2913 bdidx = 0;
2914 for( i = 0; i < nvars; i++ )
2915 {
2916 if( varIsInteresting(scip, vars[i], (propdata->onlynonconvexvars ? (int)nccount[i] : nlcount[i]), (propdata->indicators ? nindcount[i] : 0))
2917 && indicatorVarIsInteresting(scip, vars[i], (propdata->onlynonconvexvars ? (int)nccount[i] : nlcount[i]), (propdata->indicators ? nindcount[i] : 0), propdata->indicatorthreshold) )
2918 {
2919 BOUND** bdaddress;
2920
2921 /* create lower bound */
2922 bdaddress = &(propdata->bounds[bdidx]);
2923 SCIP_CALL( SCIPallocBlockMemory(scip, bdaddress) );
2924 propdata->bounds[bdidx]->boundtype = SCIP_BOUNDTYPE_LOWER;
2925 propdata->bounds[bdidx]->var = vars[i];
2926 propdata->bounds[bdidx]->found = FALSE;
2927 propdata->bounds[bdidx]->filtered = FALSE;
2928 propdata->bounds[bdidx]->newval = 0.0;
2929 propdata->bounds[bdidx]->score = getScore(scip, propdata->bounds[bdidx], nlcount[i], nindcount[i], maxnlcount, smallub);
2930 propdata->bounds[bdidx]->done = FALSE;
2931 propdata->bounds[bdidx]->nonconvex = (nccount[i] > 0);
2932 propdata->bounds[bdidx]->indicator = (nindcount[i] > 0);
2933 propdata->bounds[bdidx]->index = bdidx;
2934 bdidx++;
2935
2936 /* create upper bound */
2937 bdaddress = &(propdata->bounds[bdidx]);
2938 SCIP_CALL( SCIPallocBlockMemory(scip, bdaddress) );
2939 propdata->bounds[bdidx]->boundtype = SCIP_BOUNDTYPE_UPPER;
2940 propdata->bounds[bdidx]->var = vars[i];
2941 propdata->bounds[bdidx]->found = FALSE;
2942 propdata->bounds[bdidx]->filtered = FALSE;
2943 propdata->bounds[bdidx]->newval = 0.0;
2944 propdata->bounds[bdidx]->score = getScore(scip, propdata->bounds[bdidx], nlcount[i], nindcount[i], maxnlcount, smallub);
2945 propdata->bounds[bdidx]->done = FALSE;
2946 propdata->bounds[bdidx]->nonconvex = (nccount[i] > 0);
2947 propdata->bounds[bdidx]->indicator = (nindcount[i] > 0);
2948 propdata->bounds[bdidx]->index = bdidx;
2949 bdidx++;
2950 }
2951 }
2952
2953 /* set number of interesting bounds */
2954 propdata->nbounds = bdidx;
2955
2956 conshdlr = SCIPfindConshdlr(scip, "nonlinear");
2957
2958 /* get all product expressions from nonlinear constraint handler */
2959 if( propdata->nbounds > 0 && conshdlr != NULL && propdata->createbilinineqs )
2960 {
2961 SCIP_NLHDLR* bilinnlhdlr;
2962 SCIP_EXPR** exprs;
2963 int nexprs;
2964
2965 /* find nonlinear handler for bilinear terms */
2966 bilinnlhdlr = SCIPfindNlhdlrNonlinear(conshdlr, "bilinear");
2967 assert(bilinnlhdlr != NULL);
2968
2969 /* collect all bilinear product in all nonlinear constraints */
2970 exprs = SCIPgetExprsBilinear(bilinnlhdlr);
2971 nexprs = SCIPgetNExprsBilinear(bilinnlhdlr);
2972
2973 if( nexprs > 0 )
2974 {
2975 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->bilinbounds, nexprs) );
2976 propdata->bilinboundssize = nexprs;
2977 propdata->nbilinbounds = 0;
2978
2979 /* store candidates as bilinear bounds */
2980 for( i = 0; i < nexprs; ++i )
2981 {
2982 BILINBOUND* bilinbound;
2983 SCIP_VAR* x;
2984 SCIP_VAR* y;
2985
2986 assert(exprs[i] != NULL);
2987 assert(SCIPexprGetNChildren(exprs[i]) == 2);
2988
2991 assert(x != NULL);
2992 assert(y != NULL);
2993 assert(x != y);
2994
2995 /* skip almost fixed variables */
2996 if( !varIsInteresting(scip, x, 1, 0) || !varIsInteresting(scip, y, 1, 0) )
2997 continue;
2998
2999 /* create bilinear bound */
3000 SCIP_CALL( SCIPallocBlockMemory(scip, &propdata->bilinbounds[propdata->nbilinbounds]) ); /*lint !e866*/
3001 bilinbound = propdata->bilinbounds[propdata->nbilinbounds];
3002 BMSclearMemory(bilinbound);
3003
3004 /* store and capture expression */
3005 bilinbound->expr = exprs[i];
3006 SCIPcaptureExpr(bilinbound->expr);
3007
3008 /* compute a descent score */
3009 bilinbound->score = bilinboundGetScore(scip, propdata->randnumgen, bilinbound);
3010
3011 /* increase the number of bilinear bounds */
3012 ++(propdata->nbilinbounds);
3013
3014 SCIPdebugMsg(scip, "added bilinear bound for %s %s\n", SCIPvarGetName(x), SCIPvarGetName(y));
3015 }
3016 }
3017
3018 /* sort bounds according to decreasing score */
3019 if( propdata->nbilinbounds > 1 )
3020 {
3021 SCIPsortDownPtr((void**) propdata->bilinbounds, compBilinboundsScore, propdata->nbilinbounds);
3022 }
3023 }
3024
3025 /* free memory for buffering nonlinearities */
3026 assert(nlcount != NULL);
3027 assert(nccount != NULL);
3028 assert(nindcount != NULL);
3029 SCIPfreeBufferArray(scip, &nindcount);
3030 SCIPfreeBufferArray(scip, &nccount);
3031 SCIPfreeBufferArray(scip, &nlcount);
3032
3033 /* propdata->bounds array if empty */
3034 if( propdata->nbounds <= 0 )
3035 {
3036 assert(propdata->nbounds == 0);
3037 assert(propdata->boundssize >= 0 );
3038 SCIPfreeBlockMemoryArray(scip, &(propdata->bounds), propdata->boundssize);
3039 }
3040
3041 SCIPdebugMsg(scip, "problem has %d/%d interesting bounds\n", propdata->nbounds, 2 * nvars);
3042
3043 if( propdata->nbounds > 0 )
3044 {
3045 /* sort bounds according to decreasing score; although this initial order will be overruled by the distance
3046 * criterion later, gives a more well-defined starting situation for OBBT and might help to reduce solver
3047 * variability
3048 */
3049 SCIPsortDownPtr((void**) propdata->bounds, compBoundsScore, propdata->nbounds);
3050 }
3051
3052 return SCIP_OKAY;
3053}
3054
3055/*
3056 * Callback methods of propagator
3057 */
3058
3059/** copy method for propagator plugins (called when SCIP copies plugins)
3060 *
3061 * @note The UG framework assumes that all default plug-ins of SCIP implement a copy callback. We check
3062 * SCIPgetSubscipDepth() in PROPEXEC to prevent the propagator to run in a sub-SCIP.
3063 */
3064static
3066{ /*lint --e{715}*/
3067 assert(scip != NULL);
3068 assert(prop != NULL);
3069
3071
3072 /* call inclusion method of constraint handler */
3074
3075 return SCIP_OKAY;
3076}
3077
3078/** solving process initialization method of propagator (called when branch and bound process is about to begin) */
3079static
3081{ /*lint --e{715}*/
3082 SCIP_PROPDATA* propdata;
3083
3084 assert(scip != NULL);
3085 assert(prop != NULL);
3086
3088
3089 /* get propagator data */
3090 propdata = SCIPpropGetData(prop);
3091 assert(propdata != NULL);
3092
3093 propdata->bounds = NULL;
3094 propdata->nbounds = -1;
3095 propdata->boundssize = 0;
3096 propdata->cutoffrow = NULL;
3097 propdata->lastnode = -1;
3098
3099 /* if genvbounds propagator is not available, we cannot create genvbounds */
3100 propdata->genvboundprop = propdata->creategenvbounds ? SCIPfindProp(scip, GENVBOUND_PROP_NAME) : NULL;
3101
3102 SCIPdebugMsg(scip, "creating genvbounds: %s\n", propdata->genvboundprop != NULL ? "true" : "false");
3103
3104 /* create random number generator */
3105 SCIP_CALL( SCIPcreateRandom(scip, &propdata->randnumgen, DEFAULT_RANDSEED, TRUE) );
3106
3107 return SCIP_OKAY;
3108}
3109
3110/** execution method of propagator */
3111static
3113{ /*lint --e{715}*/
3114 SCIP_PROPDATA* propdata;
3115 SCIP_Longint itlimit;
3116
3117 assert(scip != NULL);
3118 assert(prop != NULL);
3119
3121
3123
3124 /* do not run in: presolving, repropagation, probing mode, if no objective propagation is allowed */
3126 return SCIP_OKAY;
3127
3128 /* do not run propagator in a sub-SCIP */
3129 if( SCIPgetSubscipDepth(scip) > 0 )
3130 return SCIP_OKAY;
3131
3132 /* get propagator data */
3133 propdata = SCIPpropGetData(prop);
3134 assert(propdata != NULL);
3135
3136 /* only run for nonlinear problems, i.e., if NLP is constructed
3137 * or if indicator constraints exists and should be considered
3138 */
3140 && (!propdata->indicators || SCIPfindConshdlr(scip, "indicator") == NULL || SCIPconshdlrGetNConss(SCIPfindConshdlr(scip, "indicator")) == 0) )
3141 {
3142 SCIPdebugMsg(scip, "NLP not constructed and no indicator constraints available, skipping obbt\n");
3143 return SCIP_OKAY;
3144 }
3145
3146 /* only run if LP all columns are in the LP, i.e., the LP is a relaxation; e.g., do not run if pricers are active
3147 * since pricing is not performed in probing mode
3148 */
3149 if( !SCIPallColsInLP(scip) )
3150 {
3151 SCIPdebugMsg(scip, "not all columns in LP, skipping obbt\n");
3152 return SCIP_OKAY;
3153 }
3154
3155 /* ensure that bounds are initialized */
3156 if( propdata->nbounds == -1 )
3157 {
3158 /* bounds must be initialized at root node */
3159 if( SCIPgetDepth(scip) == 0 )
3160 {
3161 SCIP_CALL( initBounds(scip, propdata) );
3162 }
3163 else
3164 {
3166 return SCIP_OKAY;
3167 }
3168 }
3169 assert(propdata->nbounds >= 0);
3170
3171 /* do not run if there are no interesting bounds */
3172 /**@todo disable */
3173 if( propdata->nbounds <= 0 )
3174 {
3175 SCIPdebugMsg(scip, "there are no interesting bounds\n");
3176 return SCIP_OKAY;
3177 }
3178
3179 /* only run once in a node != root */
3180 if( SCIPgetDepth(scip) > 0 && SCIPnodeGetNumber(SCIPgetCurrentNode(scip)) == propdata->lastnode )
3181 {
3182 return SCIP_OKAY;
3183 }
3184
3185 SCIPdebugMsg(scip, "applying obbt for problem <%s> at depth %d\n", SCIPgetProbName(scip), SCIPgetDepth(scip));
3186
3187 /* without an optimal LP solution we don't want to run; this may be because propagators with higher priority have
3188 * already found reductions or numerical troubles occurred during LP solving
3189 */
3191 {
3192 SCIPdebugMsg(scip, "aborting since no optimal LP solution is at hand\n");
3193 return SCIP_OKAY;
3194 }
3195
3196 /* compute iteration limit */
3197 if( propdata->itlimitfactor > 0.0 )
3198 itlimit = (SCIP_Longint) MAX(propdata->itlimitfactor * SCIPgetNRootLPIterations(scip),
3199 propdata->minitlimit); /*lint !e666*/
3200 else
3201 itlimit = -1;
3202
3203 /* apply obbt */
3204 SCIP_CALL( applyObbt(scip, propdata, itlimit, result) );
3206
3207 /* compute globally inequalities for bilinear terms */
3208 if( propdata->createbilinineqs )
3209 {
3210 /* set LP iteration limit */
3211 if( propdata->itlimitbilin == 0L )
3212 {
3213 /* no iteration limit if itlimit < 0 or itlimitfactorbilin < 0 */
3214 propdata->itlimitbilin = (itlimit < 0 || propdata->itlimitfactorbilin < 0)
3215 ? -1L : (SCIP_Longint)(itlimit * propdata->itlimitfactorbilin);
3216 }
3217
3218 SCIP_CALL( applyObbtBilinear(scip, propdata, itlimit, result) );
3219 }
3220
3221 /* set current node as last node */
3222 propdata->lastnode = SCIPnodeGetNumber(SCIPgetCurrentNode(scip));
3223
3224 return SCIP_OKAY;
3225}
3226
3227/** propagation conflict resolving method of propagator */
3228static
3230{ /*lint --e{715}*/
3232
3233 return SCIP_OKAY;
3234}
3235
3236/** solving process deinitialization method of propagator (called before branch and bound process data is freed) */
3237static
3239{ /*lint --e{715}*/
3240 SCIP_PROPDATA* propdata;
3241 int i;
3242
3243 assert(scip != NULL);
3244 assert(prop != NULL);
3245
3247
3248 /* get propagator data */
3249 propdata = SCIPpropGetData(prop);
3250 assert(propdata != NULL);
3251
3252 /* free random number generator */
3253 SCIPfreeRandom(scip, &propdata->randnumgen);
3254 propdata->randnumgen = NULL;
3255
3256 /* note that because we reset filtered flags to false at each call to obbt, the same bound may be filtered multiple
3257 * times
3258 */
3259 SCIPstatisticMessage("DIVE-LP: %" SCIP_LONGINT_FORMAT " NFILTERED: %d NTRIVIALFILTERED: %d NSOLVED: %d "
3260 "FILTER-LP: %" SCIP_LONGINT_FORMAT " NGENVB(dive): %d NGENVB(aggr.): %d NGENVB(triv.) %d\n",
3261 propdata->nprobingiterations, propdata->nfiltered, propdata->ntrivialfiltered, propdata->nsolvedbounds,
3262 propdata->nfilterlpiters, propdata->ngenvboundsprobing, propdata->ngenvboundsaggrfil, propdata->ngenvboundstrivfil);
3263
3264 /* free bilinear bounds */
3265 if( propdata->bilinboundssize > 0 )
3266 {
3267 for( i = propdata->nbilinbounds - 1; i >= 0; --i )
3268 {
3269 assert(propdata->bilinbounds[i] != NULL);
3270 assert(propdata->bilinbounds[i]->expr != NULL);
3271
3272 /* release expression */
3273 SCIP_CALL( SCIPreleaseExpr(scip, &propdata->bilinbounds[i]->expr) );
3274
3275 SCIPfreeBlockMemory(scip, &propdata->bilinbounds[i]); /*lint !e866*/
3276 }
3277 SCIPfreeBlockMemoryArray(scip, &propdata->bilinbounds, propdata->bilinboundssize);
3278 propdata->bilinboundssize = 0;
3279 propdata->nbilinbounds = 0;
3280 }
3281
3282 /* free memory allocated for the bounds */
3283 if( propdata->nbounds > 0 )
3284 {
3285 /* free bounds */
3286 for( i = propdata->nbounds - 1; i >= 0; i-- )
3287 {
3288 SCIPfreeBlockMemory(scip, &(propdata->bounds[i])); /*lint !e866*/
3289 }
3290 SCIPfreeBlockMemoryArray(scip, &(propdata->bounds), propdata->boundssize);
3291 }
3292
3293 propdata->nbounds = -1;
3294 propdata->itlimitbilin = 0;
3295 propdata->itusedbilin = 0;
3296
3297 return SCIP_OKAY;
3298}
3299
3300/** destructor of propagator to free user data (called when SCIP is exiting) */
3301static
3303{ /*lint --e{715}*/
3304 SCIP_PROPDATA* propdata;
3305
3307
3308 /* free propagator data */
3309 propdata = SCIPpropGetData(prop);
3310 assert(propdata != NULL);
3311
3312 SCIPfreeBlockMemory(scip, &propdata);
3313
3314 SCIPpropSetData(prop, NULL);
3315
3316 return SCIP_OKAY;
3317}
3318
3319/*
3320 * propagator specific interface methods
3321 */
3322
3323/** creates the obbt propagator and includes it in SCIP */
3325 SCIP* scip /**< SCIP data structure */
3326 )
3327{
3328 SCIP_PROPDATA* propdata;
3329 SCIP_PROP* prop;
3330
3331 /* create obbt propagator data */
3332 SCIP_CALL( SCIPallocBlockMemory(scip, &propdata) );
3333 BMSclearMemory(propdata);
3334
3335 /* initialize statistic variables */
3336 propdata->nprobingiterations = 0;
3337 propdata->nfiltered = 0;
3338 propdata->ntrivialfiltered = 0;
3339 propdata->nsolvedbounds = 0;
3340 propdata->ngenvboundsprobing = 0;
3341 propdata->ngenvboundsaggrfil = 0;
3342 propdata->ngenvboundstrivfil = 0;
3343 propdata->nfilterlpiters = 0;
3344 propdata->lastidx = -1;
3345 propdata->propagatecounter = 0;
3346 propdata->npropagatedomreds = 0;
3347
3348 /* include propagator */
3350 propExecObbt, propdata) );
3351
3352 SCIP_CALL( SCIPsetPropCopy(scip, prop, propCopyObbt) );
3353 SCIP_CALL( SCIPsetPropFree(scip, prop, propFreeObbt) );
3354 SCIP_CALL( SCIPsetPropExitsol(scip, prop, propExitsolObbt) );
3355 SCIP_CALL( SCIPsetPropInitsol(scip, prop, propInitsolObbt) );
3356 SCIP_CALL( SCIPsetPropResprop(scip, prop, propRespropObbt) );
3357
3358 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/creategenvbounds",
3359 "should obbt try to provide genvbounds if possible?",
3360 &propdata->creategenvbounds, TRUE, DEFAULT_CREATE_GENVBOUNDS, NULL, NULL) );
3361
3362 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/normalize",
3363 "should coefficients in filtering be normalized w.r.t. the domains sizes?",
3364 &propdata->normalize, TRUE, DEFAULT_FILTERING_NORM, NULL, NULL) );
3365
3366 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/applyfilterrounds",
3367 "try to filter bounds in so-called filter rounds by solving auxiliary LPs?",
3368 &propdata->applyfilterrounds, TRUE, DEFAULT_APPLY_FILTERROUNDS, NULL, NULL) );
3369
3370 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/applytrivialfilter",
3371 "try to filter bounds with the LP solution after each solve?",
3372 &propdata->applytrivialfilter, TRUE, DEFAULT_APPLY_TRIVIALFITLERING, NULL, NULL) );
3373
3374 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/genvbdsduringfilter",
3375 "should we try to generate genvbounds during trivial and aggressive filtering?",
3376 &propdata->genvbdsduringfilter, TRUE, DEFAULT_GENVBDSDURINGFILTER, NULL, NULL) );
3377
3378 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/genvbdsduringsepa",
3379 "try to create genvbounds during separation process?",
3380 &propdata->genvbdsduringsepa, TRUE, DEFAULT_GENVBDSDURINGSEPA, NULL, NULL) );
3381
3382 SCIP_CALL( SCIPaddIntParam(scip, "propagating/" PROP_NAME "/minfilter",
3383 "minimal number of filtered bounds to apply another filter round",
3384 &propdata->nminfilter, TRUE, DEFAULT_FILTERING_MIN, 1, INT_MAX, NULL, NULL) );
3385
3386 SCIP_CALL( SCIPaddRealParam(scip, "propagating/" PROP_NAME "/itlimitfactor",
3387 "multiple of root node LP iterations used as total LP iteration limit for obbt (<= 0: no limit )",
3388 &propdata->itlimitfactor, FALSE, DEFAULT_ITLIMITFACTOR, SCIP_REAL_MIN, SCIP_REAL_MAX, NULL, NULL) );
3389
3390 SCIP_CALL( SCIPaddRealParam(scip, "propagating/" PROP_NAME "/itlimitfactorbilin",
3391 "multiple of OBBT LP limit used as total LP iteration limit for solving bilinear inequality LPs (< 0 for no limit)",
3392 &propdata->itlimitfactorbilin, FALSE, DEFAULT_ITLIMITFAC_BILININEQS, SCIP_REAL_MIN, SCIP_REAL_MAX, NULL, NULL) );
3393
3394 SCIP_CALL( SCIPaddRealParam(scip, "propagating/" PROP_NAME "/minnonconvexity",
3395 "minimum absolute value of nonconvex eigenvalues for a bilinear term",
3396 &propdata->minnonconvexity, FALSE, DEFAULT_MINNONCONVEXITY, 0.0, SCIP_REAL_MAX, NULL, NULL) );
3397
3398 SCIP_CALL( SCIPaddLongintParam(scip, "propagating/" PROP_NAME "/minitlimit",
3399 "minimum LP iteration limit",
3400 &propdata->minitlimit, FALSE, DEFAULT_MINITLIMIT, 0L, SCIP_LONGINT_MAX, NULL, NULL) );
3401
3402 SCIP_CALL( SCIPaddRealParam(scip, "propagating/" PROP_NAME "/dualfeastol",
3403 "feasibility tolerance for reduced costs used in obbt; this value is used if SCIP's dual feastol is greater",
3404 &propdata->dualfeastol, FALSE, DEFAULT_DUALFEASTOL, 0.0, SCIP_REAL_MAX, NULL, NULL) );
3405
3406 SCIP_CALL( SCIPaddRealParam(scip, "propagating/" PROP_NAME "/conditionlimit",
3407 "maximum condition limit used in LP solver (-1.0: no limit)",
3408 &propdata->conditionlimit, FALSE, DEFAULT_CONDITIONLIMIT, -1.0, SCIP_REAL_MAX, NULL, NULL) );
3409
3410 SCIP_CALL( SCIPaddRealParam(scip, "propagating/" PROP_NAME "/boundstreps",
3411 "minimal relative improve for strengthening bounds",
3412 &propdata->boundstreps, FALSE, DEFAULT_BOUNDSTREPS, 0.0, 1.0, NULL, NULL) );
3413
3414 SCIP_CALL( SCIPaddRealParam(scip, "propagating/" PROP_NAME "/indicatorthreshold",
3415 "threshold whether upper bounds of vars of indicator conss are considered or tightened",
3416 &propdata->indicatorthreshold, TRUE, DEFAULT_INDICATORTHRESHOLD, 0.0, SCIP_REAL_MAX, NULL, NULL) );
3417
3418 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/onlynonconvexvars",
3419 "only apply obbt on non-convex variables",
3420 &propdata->onlynonconvexvars, TRUE, DEFAULT_ONLYNONCONVEXVARS, NULL, NULL) );
3421
3422 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/indicators",
3423 "apply obbt on variables of indicator constraints? (independent of convexity)",
3424 &propdata->indicators, TRUE, DEFAULT_INDICATORS, NULL, NULL) );
3425
3426 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/tightintboundsprobing",
3427 "should integral bounds be tightened during the probing mode?",
3428 &propdata->tightintboundsprobing, TRUE, DEFAULT_TIGHTINTBOUNDSPROBING, NULL, NULL) );
3429
3430 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/tightcontboundsprobing",
3431 "should continuous bounds be tightened during the probing mode?",
3432 &propdata->tightcontboundsprobing, TRUE, DEFAULT_TIGHTCONTBOUNDSPROBING, NULL, NULL) );
3433
3434 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/createbilinineqs",
3435 "solve auxiliary LPs in order to find valid inequalities for bilinear terms?",
3436 &propdata->createbilinineqs, TRUE, DEFAULT_CREATE_BILININEQS, NULL, NULL) );
3437
3438 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/createlincons",
3439 "create linear constraints from inequalities for bilinear terms?",
3440 &propdata->createlincons, TRUE, DEFAULT_CREATE_LINCONS, NULL, NULL) );
3441
3442 SCIP_CALL( SCIPaddIntParam(scip, "propagating/" PROP_NAME "/orderingalgo",
3443 "select the type of ordering algorithm which should be used (0: no special ordering, 1: greedy, 2: greedy reverse)",
3444 &propdata->orderingalgo, TRUE, DEFAULT_ORDERINGALGO, 0, 2, NULL, NULL) );
3445
3446 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/separatesol",
3447 "should the obbt LP solution be separated?",
3448 &propdata->separatesol, TRUE, DEFAULT_SEPARATESOL, NULL, NULL) );
3449
3450 SCIP_CALL( SCIPaddIntParam(scip, "propagating/" PROP_NAME "/sepaminiter",
3451 "minimum number of iteration spend to separate an obbt LP solution",
3452 &propdata->sepaminiter, TRUE, DEFAULT_SEPAMINITER, 0, INT_MAX, NULL, NULL) );
3453
3454 SCIP_CALL( SCIPaddIntParam(scip, "propagating/" PROP_NAME "/sepamaxiter",
3455 "maximum number of iteration spend to separate an obbt LP solution",
3456 &propdata->sepamaxiter, TRUE, DEFAULT_SEPAMAXITER, 0, INT_MAX, NULL, NULL) );
3457
3458 SCIP_CALL( SCIPaddIntParam(scip, "propagating/" PROP_NAME "/propagatefreq",
3459 "trigger a propagation round after that many bound tightenings (0: no propagation)",
3460 &propdata->propagatefreq, TRUE, DEFAULT_PROPAGATEFREQ, 0, INT_MAX, NULL, NULL) );
3461
3462 return SCIP_OKAY;
3463}
static long bound
SCIP_VAR ** y
SCIP_VAR ** x
constraint handler for indicator constraints
Constraint handler for linear constraints in their most general form, .
constraint handler for nonlinear constraints specified by algebraic expressions
#define DEFAULT_RANDSEED
#define NULL
Definition def.h:257
#define SCIP_MAXSTRLEN
Definition def.h:278
#define SCIP_Longint
Definition def.h:150
#define SCIP_REAL_MAX
Definition def.h:167
#define SCIP_INVALID
Definition def.h:187
#define SCIP_Bool
Definition def.h:100
#define MIN(x, y)
Definition def.h:233
#define MAX3(x, y, z)
Definition def.h:237
#define SCIP_STRINGEQ(name, reference, retcode)
Definition def.h:454
#define SCIP_Real
Definition def.h:165
#define SQR(x)
Definition def.h:208
#define TRUE
Definition def.h:102
#define FALSE
Definition def.h:103
#define MAX(x, y)
Definition def.h:229
#define SCIP_LONGINT_FORMAT
Definition def.h:157
#define SCIPABORT()
Definition def.h:336
#define SCIP_REAL_MIN
Definition def.h:168
#define REALABS(x)
Definition def.h:191
#define SCIP_LONGINT_MAX
Definition def.h:151
#define EPSZ(x, eps)
Definition def.h:197
#define SCIP_CALL(x)
Definition def.h:364
SCIP_VAR ** SCIPgetVarsLinear(SCIP *scip, SCIP_CONS *cons)
int SCIPgetExprNLocksPosNonlinear(SCIP_EXPR *expr)
SCIP_HASHMAP * SCIPgetVarExprHashmapNonlinear(SCIP_CONSHDLR *conshdlr)
int SCIPgetNVarsLinear(SCIP *scip, SCIP_CONS *cons)
SCIP_VAR * SCIPgetExprAuxVarNonlinear(SCIP_EXPR *expr)
unsigned int SCIPgetExprNSepaUsesActivityNonlinear(SCIP_EXPR *expr)
SCIP_VAR * SCIPgetSlackVarIndicator(SCIP_CONS *cons)
SCIP_CONS * SCIPgetLinearConsIndicator(SCIP_CONS *cons)
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)
int SCIPgetExprNLocksNegNonlinear(SCIP_EXPR *expr)
int SCIPgetSubscipDepth(SCIP *scip)
Definition scip_copy.c:2589
SCIP_Bool SCIPisStopped(SCIP *scip)
SCIP_STAGE SCIPgetStage(SCIP *scip)
const char * SCIPgetProbName(SCIP *scip)
Definition scip_prob.c:1242
SCIP_RETCODE SCIPgetVarsData(SCIP *scip, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars, int *nimplvars, int *ncontvars)
Definition scip_prob.c:2115
int SCIPgetNVars(SCIP *scip)
Definition scip_prob.c:2246
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition scip_prob.c:3274
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition scip_prob.c:2201
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3284
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3466
#define SCIPdebugMsg
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
int SCIPgetNExprsBilinear(SCIP_NLHDLR *nlhdlr)
SCIP_RETCODE SCIPaddIneqBilinear(SCIP *scip, SCIP_NLHDLR *nlhdlr, SCIP_EXPR *expr, SCIP_Real xcoef, SCIP_Real ycoef, SCIP_Real constant, SCIP_Bool *success)
SCIP_EXPR ** SCIPgetExprsBilinear(SCIP_NLHDLR *nlhdlr)
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition misc.c:11162
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 SCIPaddLongintParam(SCIP *scip, const char *name, const char *desc, SCIP_Longint *valueptr, SCIP_Bool isadvanced, SCIP_Longint defaultvalue, SCIP_Longint minvalue, SCIP_Longint maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:111
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:83
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:139
SCIP_RETCODE SCIPsetIntParam(SCIP *scip, const char *name, int value)
Definition scip_param.c:487
SCIP_RETCODE SCIPgetRealParam(SCIP *scip, const char *name, SCIP_Real *value)
Definition scip_param.c:307
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 SCIPgetIntParam(SCIP *scip, const char *name, int *value)
Definition scip_param.c:269
SCIP_RETCODE SCIPsetRealParam(SCIP *scip, const char *name, SCIP_Real value)
Definition scip_param.c:603
SCIP_RETCODE SCIPincludePropObbt(SCIP *scip)
Definition prop_obbt.c:3324
SCIP_BASESTAT SCIPcolGetBasisStatus(SCIP_COL *col)
Definition lp.c:17414
int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4782
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition scip_cons.c:940
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4739
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition scip_cons.c:1173
SCIP_RETCODE SCIPseparateSol(SCIP *scip, SCIP_SOL *sol, SCIP_Bool pretendroot, SCIP_Bool allowlocal, SCIP_Bool onlydelayed, SCIP_Bool *delayed, SCIP_Bool *cutoff)
Definition scip_cut.c:710
int SCIPgetNCuts(SCIP *scip)
Definition scip_cut.c:762
int SCIPexprGetNChildren(SCIP_EXPR *expr)
Definition expr.c:3872
SCIP_RETCODE SCIPreleaseExpr(SCIP *scip, SCIP_EXPR **expr)
Definition scip_expr.c:1443
SCIP_Bool SCIPisExprVar(SCIP *scip, SCIP_EXPR *expr)
Definition scip_expr.c:1457
SCIP_EXPR ** SCIPexprGetChildren(SCIP_EXPR *expr)
Definition expr.c:3882
void SCIPcaptureExpr(SCIP_EXPR *expr)
Definition scip_expr.c:1435
SCIP_ROW ** SCIPgetLPRows(SCIP *scip)
Definition scip_lp.c:611
int SCIPgetNLPRows(SCIP *scip)
Definition scip_lp.c:632
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition scip_lp.c:174
SCIP_Bool SCIPallColsInLP(SCIP *scip)
Definition scip_lp.c:655
SCIP_Real SCIPgetLPObjval(SCIP *scip)
Definition scip_lp.c:253
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition scip_mem.h:110
#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 SCIPfreeBlockMemory(scip, ptr)
Definition scip_mem.h:108
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition scip_mem.h:137
#define SCIPallocBlockMemory(scip, ptr)
Definition scip_mem.h:89
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition scip_nlp.c:110
int SCIPgetNNLPVars(SCIP *scip)
Definition scip_nlp.c:201
SCIP_RETCODE SCIPgetNLPVarsNonlinearity(SCIP *scip, int *nlcount)
Definition scip_nlp.c:223
SCIP_NLHDLR * SCIPfindNlhdlrNonlinear(SCIP_CONSHDLR *conshdlr, const char *name)
SCIP_Longint SCIPnodeGetNumber(SCIP_NODE *node)
Definition tree.c:8513
SCIP_RETCODE SCIPaddRowProbing(SCIP *scip, SCIP_ROW *row)
SCIP_RETCODE SCIPapplyCutsProbing(SCIP *scip, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPchgVarUbProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
SCIP_RETCODE SCIPchgVarLbProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
SCIP_RETCODE SCIPpropagateProbing(SCIP *scip, int maxproprounds, SCIP_Bool *cutoff, SCIP_Longint *ndomredsfound)
SCIP_RETCODE SCIPchgVarObjProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newobj)
SCIP_RETCODE SCIPbacktrackProbing(SCIP *scip, int probingdepth)
SCIP_Bool SCIPinProbing(SCIP *scip)
SCIP_RETCODE SCIPstartProbing(SCIP *scip)
SCIP_Real SCIPgetVarObjProbing(SCIP *scip, SCIP_VAR *var)
SCIP_RETCODE SCIPnewProbingNode(SCIP *scip)
SCIP_RETCODE SCIPsolveProbingLP(SCIP *scip, int itlim, SCIP_Bool *lperror, SCIP_Bool *cutoff)
SCIP_PROP * SCIPfindProp(SCIP *scip, const char *name)
Definition scip_prop.c:333
void SCIPpropSetData(SCIP_PROP *prop, SCIP_PROPDATA *propdata)
Definition prop.c:801
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 SCIPsetPropExitsol(SCIP *scip, SCIP_PROP *prop,)
Definition scip_prop.c:235
const char * SCIPpropGetName(SCIP_PROP *prop)
Definition prop.c:951
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 SCIPsetPropInitsol(SCIP *scip, SCIP_PROP *prop,)
Definition scip_prop.c:219
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_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1581
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1604
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition scip_lp.c:1646
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition scip_lp.c:1508
SCIP_RETCODE SCIPcreateEmptyRowUnspec(SCIP *scip, SCIP_ROW **row, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition scip_lp.c:1458
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition lp.c:17917
SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
Definition lp.c:17706
SCIP_Longint SCIPgetNRootLPIterations(SCIP *scip)
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
SCIP_Longint SCIPgetNLPIterations(SCIP *scip)
SCIP_Bool SCIPisUbBetter(SCIP *scip, SCIP_Real newub, SCIP_Real oldlb, SCIP_Real oldub)
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Real SCIPchgRelaxfeastol(SCIP *scip, SCIP_Real relaxfeastol)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLbBetter(SCIP *scip, SCIP_Real newlb, SCIP_Real oldlb, SCIP_Real oldub)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPfeastol(SCIP *scip)
SCIP_Real SCIPdualfeastol(SCIP *scip)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPceil(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_Real SCIPepsilon(SCIP *scip)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPchgDualfeastol(SCIP *scip, SCIP_Real dualfeastol)
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition scip_tree.c:146
int SCIPgetDepth(SCIP *scip)
Definition scip_tree.c:672
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition scip_tree.c:91
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:6401
SCIP_COL * SCIPvarGetCol(SCIP_VAR *var)
Definition var.c:23715
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition var.c:23510
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition var.c:23418
SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
Definition var.c:23530
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition var.c:24300
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition var.c:23932
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:6651
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition var.c:23485
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition var.c:24174
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition var.c:23694
const char * SCIPvarGetName(SCIP_VAR *var)
Definition var.c:23299
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition var.c:23522
SCIP_Real SCIPvarGetLPSol(SCIP_VAR *var)
Definition var.c:24696
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition var.c:24266
SCIP_Real SCIPgetVarRedcost(SCIP *scip, SCIP_VAR *var)
Definition scip_var.c:2608
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition var.c:24152
SCIP_Bool SCIPallowWeakDualReds(SCIP *scip)
Definition scip_var.c:10998
SCIP_Real SCIPrandomGetReal(SCIP_RANDNUMGEN *randnumgen, SCIP_Real minrandval, SCIP_Real maxrandval)
Definition misc.c:10245
void SCIPsortDownPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition misc.c:10827
return SCIP_OKAY
SCIPfreeRandom(scip, &heurdata->randnumgen)
SCIP_Bool lperror
int c
static SCIP_LPSOLSTAT lpsolstat
SCIPendProbing(scip))
SCIP_Bool cutoff
SCIPcreateRandom(scip, &heurdata->randnumgen, DEFAULT_RANDSEED, TRUE))
int r
assert(minobj< SCIPgetCutoffbound(scip))
int nvars
SCIP_VAR * var
static SCIP_VAR ** vars
#define BMSclearMemory(ptr)
Definition memory.h:129
#define BMSclearMemoryArray(ptr, num)
Definition memory.h:130
bilinear nonlinear handler
#define PROP_DESC
#define PROP_NAME
#define PROP_DELAY
#define PROP_TIMING
#define PROP_FREQ
#define PROP_PRIORITY
generalized variable bounds propagator
#define DEFAULT_ITLIMITFACTOR
Definition prop_nlobbt.c:73
static SCIP_Real getFilterCoef(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_VAR *var, SCIP_BOUNDTYPE boundtype)
Definition prop_obbt.c:480
#define GENVBOUND_PROP_NAME
Definition prop_obbt.c:115
static SCIP_VAR * bilinboundGetY(BILINBOUND *bilinbound)
Definition prop_obbt.c:855
#define DEFAULT_INDICATORS
Definition prop_obbt.c:105
#define DEFAULT_APPLY_FILTERROUNDS
Definition prop_obbt.c:91
#define DEFAULT_BOUNDSTREPS
Definition prop_obbt.c:98
#define DEFAULT_DUALFEASTOL
Definition prop_obbt.c:95
#define DEFAULT_SEPAMINITER
Definition prop_obbt.c:120
struct Bound BOUND
Definition prop_obbt.c:149
static SCIP_RETCODE filterExistingLP(SCIP *scip, SCIP_PROPDATA *propdata, int *nfiltered, BOUND *currbound)
Definition prop_obbt.c:961
#define DEFAULT_FILTERING_MIN
Definition prop_obbt.c:99
#define DEFAULT_MINNONCONVEXITY
Definition prop_obbt.c:128
#define DEFAULT_INDICATORTHRESHOLD
Definition prop_obbt.c:106
#define DEFAULT_SEPAMAXITER
Definition prop_obbt.c:121
static SCIP_Real bilinboundGetScore(SCIP *scip, SCIP_RANDNUMGEN *randnumgen, BILINBOUND *bilinbound)
Definition prop_obbt.c:889
static SCIP_RETCODE initBounds(SCIP *scip, SCIP_PROPDATA *propdata)
Definition prop_obbt.c:2839
#define DEFAULT_CONDITIONLIMIT
Definition prop_obbt.c:97
static int nextBound(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_Bool convexphase)
Definition prop_obbt.c:1669
static SCIP_RETCODE tightenBoundProbing(SCIP *scip, BOUND *bound, SCIP_Real newval, SCIP_Bool *tightened)
Definition prop_obbt.c:1531
static SCIP_Real evalBound(SCIP *scip, BOUND *bound)
Definition prop_obbt.c:1653
#define DEFAULT_TIGHTINTBOUNDSPROBING
Definition prop_obbt.c:108
static SCIP_Bool includeVarGenVBound(SCIP *scip, SCIP_VAR *var)
Definition prop_obbt.c:423
#define DEFAULT_MINITLIMIT
Definition prop_obbt.c:103
#define DEFAULT_PROPAGATEFREQ
Definition prop_obbt.c:123
static int bilinboundGetLocksNeg(BILINBOUND *bilinbound)
Definition prop_obbt.c:867
static SCIP_RETCODE filterBounds(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_Longint itlimit)
Definition prop_obbt.c:1294
static SCIP_Bool indicatorVarIsInteresting(SCIP *scip, SCIP_VAR *var, int nlcount, int nindcount, SCIP_Real threshold)
Definition prop_obbt.c:938
#define DEFAULT_ORDERINGALGO
Definition prop_obbt.c:112
#define DEFAULT_GENVBDSDURINGSEPA
Definition prop_obbt.c:122
static SCIP_RETCODE addObjCutoff(SCIP *scip, SCIP_PROPDATA *propdata)
Definition prop_obbt.c:316
#define DEFAULT_APPLY_TRIVIALFITLERING
Definition prop_obbt.c:93
#define DEFAULT_SEPARATESOL
Definition prop_obbt.c:117
#define OBBT_SCOREBASE
Definition prop_obbt.c:114
static SCIP_RETCODE solveLP(SCIP *scip, int itlimit, SCIP_Bool *error, SCIP_Bool *optimal)
Definition prop_obbt.c:244
#define DEFAULT_FILTERING_NORM
Definition prop_obbt.c:89
static void getCorners(SCIP_VAR *x, SCIP_VAR *y, CORNER corner, SCIP_Real *xs, SCIP_Real *ys, SCIP_Real *xt, SCIP_Real *yt)
Definition prop_obbt.c:801
static int getIterationsLeft(SCIP *scip, SCIP_Longint nolditerations, SCIP_Longint itlimit)
Definition prop_obbt.c:450
static SCIP_RETCODE filterRound(SCIP *scip, SCIP_PROPDATA *propdata, int itlimit, int *nfiltered, SCIP_Real *objcoefs, int *objcoefsinds, int nobjcoefs)
Definition prop_obbt.c:1134
static SCIP_RETCODE sortBounds(SCIP *scip, SCIP_PROPDATA *propdata)
Definition prop_obbt.c:1637
#define DEFAULT_CREATE_BILININEQS
Definition prop_obbt.c:125
#define DEFAULT_CREATE_LINCONS
Definition prop_obbt.c:126
#define DEFAULT_TIGHTCONTBOUNDSPROBING
Definition prop_obbt.c:110
struct BilinBound BILINBOUND
Definition prop_obbt.c:170
static SCIP_VAR * bilinboundGetX(BILINBOUND *bilinbound)
Definition prop_obbt.c:843
Corner
Definition prop_obbt.c:153
@ LEFTTOP
Definition prop_obbt.c:157
@ RIGHTBOTTOM
Definition prop_obbt.c:155
@ FILTERED
Definition prop_obbt.c:158
@ LEFTBOTTOM
Definition prop_obbt.c:154
@ RIGHTTOP
Definition prop_obbt.c:156
#define DEFAULT_CREATE_GENVBOUNDS
Definition prop_obbt.c:88
enum Corner CORNER
Definition prop_obbt.c:160
static SCIP_RETCODE setObjProbing(SCIP *scip, SCIP_PROPDATA *propdata, BOUND *bound, SCIP_Real coef)
Definition prop_obbt.c:376
static unsigned int getScore(SCIP *scip, BOUND *bound, int nlcount, int nindcount, int maxnlcount, SCIP_Real smallub)
Definition prop_obbt.c:2640
#define DEFAULT_ITLIMITFAC_BILININEQS
Definition prop_obbt.c:127
#define DEFAULT_ONLYNONCONVEXVARS
Definition prop_obbt.c:104
static SCIP_RETCODE findNewBounds(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_Longint *nleftiterations, SCIP_Bool convexphase)
Definition prop_obbt.c:1804
static SCIP_Bool varIsFixedLocal(SCIP *scip, SCIP_VAR *var)
Definition prop_obbt.c:366
static SCIP_RETCODE solveBilinearLP(SCIP *scip, SCIP_VAR *x, SCIP_VAR *y, SCIP_Real xs, SCIP_Real ys, SCIP_Real xt, SCIP_Real yt, SCIP_Real *xcoef, SCIP_Real *ycoef, SCIP_Real *constant, SCIP_Longint iterlim, int *nnonzduals)
Definition prop_obbt.c:2297
static SCIP_RETCODE applyObbt(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_Longint itlimit, SCIP_RESULT *result)
Definition prop_obbt.c:2043
static SCIP_RETCODE applyObbtBilinear(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_Longint itlimit, SCIP_RESULT *result)
Definition prop_obbt.c:2445
#define DEFAULT_GENVBDSDURINGFILTER
Definition prop_obbt.c:94
static SCIP_RETCODE getNVarsIndicators(SCIP *scip, int *nindcount)
Definition prop_obbt.c:2761
static SCIP_RETCODE createGenVBound(SCIP *scip, SCIP_PROPDATA *propdata, BOUND *bound, SCIP_Bool *found)
Definition prop_obbt.c:554
static SCIP_RETCODE applyBoundChgs(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_RESULT *result)
Definition prop_obbt.c:1456
static void getCorner(SCIP_VAR *x, SCIP_VAR *y, CORNER corner, SCIP_Real *px, SCIP_Real *py)
Definition prop_obbt.c:763
static int bilinboundGetLocksPos(BILINBOUND *bilinbound)
Definition prop_obbt.c:878
static SCIP_RETCODE getNLPVarsNonConvexity(SCIP *scip, unsigned int *nccounts)
Definition prop_obbt.c:2703
static SCIP_RETCODE applySeparation(SCIP *scip, SCIP_PROPDATA *propdata, BOUND *currbound, SCIP_Longint *nleftiterations, SCIP_Bool *success)
Definition prop_obbt.c:1722
static SCIP_Bool varIsInteresting(SCIP *scip, SCIP_VAR *var, int nlcount, int nindcount)
Definition prop_obbt.c:2821
static void exchangeBounds(SCIP_PROPDATA *propdata, int i)
Definition prop_obbt.c:740
optimization-based bound tightening propagator
public methods for managing constraints
public methods for LP management
public methods for message output
#define SCIPerrorMessage
Definition pub_message.h:64
#define SCIPstatisticMessage
#define SCIPdebug(x)
Definition pub_message.h:93
#define SCIPdebugMessage
Definition pub_message.h:96
public data structures and miscellaneous methods
methods for sorting joint arrays of various types
public methods for NLP management
public methods for propagators
public methods for branch and bound tree
public methods for problem variables
public methods for constraint handler plugins and constraints
public methods for problem copies
public methods for cuts and aggregation rows
general public methods
public methods for the LP relaxation, rows and columns
public methods for memory management
public methods for message handling
public methods for nonlinear relaxation
public methods for numerical tolerances
public methods for SCIP parameter handling
public methods for global and local (sub)problems
public methods for the probing mode
public methods for propagator plugins
public methods for random numbers
public methods for querying solving statistics
public methods for the branch-and-bound tree
public methods for SCIP variables
SCIP_Real score
Definition prop_obbt.c:168
unsigned int done
Definition prop_obbt.c:167
SCIP_EXPR * expr
Definition prop_obbt.c:165
unsigned int score
Definition prop_obbt.c:141
unsigned int done
Definition prop_obbt.c:144
unsigned int filtered
Definition prop_obbt.c:142
SCIP_BOUNDTYPE boundtype
Definition prop_obbt.c:140
int index
Definition prop_obbt.c:147
unsigned int found
Definition prop_obbt.c:143
SCIP_Real newval
Definition prop_obbt.c:139
SCIP_VAR * var
Definition prop_obbt.c:138
unsigned int nonconvex
Definition prop_obbt.c:145
unsigned int indicator
Definition prop_obbt.c:146
struct SCIP_Cons SCIP_CONS
Definition type_cons.h:63
struct SCIP_Conshdlr SCIP_CONSHDLR
Definition type_cons.h:62
struct SCIP_Expr SCIP_EXPR
Definition type_expr.h:55
struct SCIP_Row SCIP_ROW
Definition type_lp.h:105
enum SCIP_LPSolStat SCIP_LPSOLSTAT
Definition type_lp.h:52
@ 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
@ SCIP_LPSOLSTAT_ERROR
Definition type_lp.h:50
@ SCIP_LPSOLSTAT_NOTSOLVED
Definition type_lp.h:43
@ SCIP_LPSOLSTAT_OPTIMAL
Definition type_lp.h:44
@ SCIP_LPSOLSTAT_TIMELIMIT
Definition type_lp.h:49
@ SCIP_LPSOLSTAT_UNBOUNDEDRAY
Definition type_lp.h:46
@ SCIP_LPSOLSTAT_INFEASIBLE
Definition type_lp.h:45
@ SCIP_LPSOLSTAT_OBJLIMIT
Definition type_lp.h:47
@ SCIP_LPSOLSTAT_ITERLIMIT
Definition type_lp.h:48
@ SCIP_BASESTAT_BASIC
Definition type_lpi.h:92
enum SCIP_BaseStat SCIP_BASESTAT
Definition type_lpi.h:96
struct SCIP_HashMap SCIP_HASHMAP
Definition type_misc.h:106
#define SCIP_DECL_SORTPTRCOMP(x)
Definition type_misc.h:189
struct SCIP_RandNumGen SCIP_RANDNUMGEN
Definition type_misc.h:127
struct SCIP_Nlhdlr SCIP_NLHDLR
#define SCIP_DECL_PROPCOPY(x)
Definition type_prop.h:61
#define SCIP_DECL_PROPINITSOL(x)
Definition type_prop.h:129
#define SCIP_DECL_PROPFREE(x)
Definition type_prop.h:69
#define SCIP_DECL_PROPEXITSOL(x)
Definition type_prop.h:141
struct SCIP_Prop SCIP_PROP
Definition type_prop.h:51
#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
enum SCIP_Result SCIP_RESULT
Definition type_result.h:61
@ SCIP_INVALIDCALL
enum SCIP_Retcode SCIP_RETCODE
struct Scip SCIP
Definition type_scip.h:39
@ SCIP_STAGE_SOLVING
Definition type_set.h:53
struct SCIP_Var SCIP_VAR
Definition type_var.h:166
@ SCIP_VARTYPE_INTEGER
Definition type_var.h:65
@ SCIP_VARTYPE_CONTINUOUS
Definition type_var.h:71
@ SCIP_VARTYPE_BINARY
Definition type_var.h:64
@ SCIP_VARSTATUS_COLUMN
Definition type_var.h:53