Scippy

SCIP

Solving Constraint Integer Programs

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