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*/
2676 score += 2;
2677 else
2678 {
2679 switch( SCIPvarGetType(bound->var) )
2680 {
2682 score += 4;
2683 break;
2685 score += 1;
2686 break;
2688 score += 3;
2689 break;
2690 default:
2691 SCIPerrorMessage("invalid variable type\n");
2692 SCIPABORT();
2693 return 0; /*lint !e527*/
2694 } /*lint !e788*/
2695 }
2696
2697 score *= OBBT_SCOREBASE;
2698 if( bound->boundtype == SCIP_BOUNDTYPE_UPPER )
2699 score += 1;
2700
2701 return score;
2702}
2703
2704/** count how often each variable is used in a nonconvex term */
2705static
2707 SCIP* scip, /**< SCIP data structure */
2708 unsigned int* nccounts /**< store the number each variable appears in a
2709 * non-convex term */
2710 )
2711{
2712 SCIP_CONSHDLR* conshdlr;
2713 SCIP_HASHMAP* var2expr;
2714 int nvars;
2715 int i;
2716
2717 assert(scip != NULL);
2718 assert(nccounts != NULL);
2719
2720 nvars = SCIPgetNVars(scip);
2721
2722 /* initialize nccounts to zero */
2723 BMSclearMemoryArray(nccounts, nvars);
2724
2725 /* get nonlinear constraint handler */
2726 conshdlr = SCIPfindConshdlr(scip, "nonlinear");
2727 if( conshdlr == NULL || SCIPconshdlrGetNConss(conshdlr) == 0 )
2728 return SCIP_OKAY;
2729
2730 var2expr = SCIPgetVarExprHashmapNonlinear(conshdlr);
2731 assert(var2expr != NULL);
2732
2733 for( i = 0; i < SCIPgetNVars(scip); ++i )
2734 {
2735 SCIP_VAR* var;
2736
2737 var = SCIPgetVars(scip)[i];
2738 assert(var != NULL);
2739
2740 if( SCIPhashmapExists(var2expr, (void*) var) )
2741 {
2742 SCIP_EXPR* expr = (SCIP_EXPR*)SCIPhashmapGetImage(var2expr, (void*) var);
2743 assert(expr != NULL);
2744 assert(SCIPisExprVar(scip, expr));
2745
2747 }
2748 }
2749
2750#ifdef SCIP_DEBUG
2751 for( i = 0; i < SCIPgetNVars(scip); ++i)
2752 {
2753 SCIP_VAR* var = SCIPgetVars(scip)[i];
2754 assert(var != NULL);
2755 SCIPdebugMsg(scip, "nccounts[%s] = %u\n", SCIPvarGetName(var), nccounts[SCIPvarGetProbindex(var)]);
2756 }
2757#endif
2758
2759 return SCIP_OKAY;
2760}
2761
2762/** computes for each variable the number of indicator constraints in which the variable appears */
2763static
2765 SCIP* scip, /**< SCIP data structure */
2766 int* nindcount /**< array that stores in how many indicator conss each variable appears */
2767 )
2768{
2769 SCIP_CONSHDLR* conshdlr;
2770 SCIP_CONS** indconss;
2771 int nvars;
2772 int nindconss;
2773
2774 assert(scip != NULL);
2775 assert(nindcount != NULL);
2776
2777 nvars = SCIPgetNVars(scip);
2778
2779 /* initialize nindcount to zero */
2780 BMSclearMemoryArray(nindcount, nvars);
2781
2782 /* get indicator constraint handler */
2783 conshdlr = SCIPfindConshdlr(scip, "indicator");
2784 if( conshdlr == NULL || SCIPconshdlrGetNConss(conshdlr) == 0 )
2785 return SCIP_OKAY;
2786
2787 nindconss = SCIPconshdlrGetNConss(conshdlr);
2788 indconss = SCIPconshdlrGetConss(conshdlr);
2789
2790 for( int i = 0; i < nindconss; ++i )
2791 {
2792 SCIP_VAR** consvars;
2793 SCIP_VAR* slackvar;
2794 SCIP_CONS* lincons;
2795 int nconsvars;
2796
2797 lincons = SCIPgetLinearConsIndicator(indconss[i]);
2798 assert(lincons!=NULL);
2799
2800 nconsvars = SCIPgetNVarsLinear(scip, lincons);
2801 consvars = SCIPgetVarsLinear(scip, lincons);
2802 assert(consvars != NULL);
2803 slackvar = SCIPgetSlackVarIndicator(indconss[i]);
2804
2805 for( int v = 0; v < nconsvars; ++v )
2806 {
2807 /* we should skip the slackvariable */
2808 if( consvars[v] == slackvar )
2809 continue;
2810
2811 /* consider only active variables */
2812 if( SCIPvarGetStatus(consvars[v]) == SCIP_VARSTATUS_COLUMN )
2813 {
2814 nindcount[SCIPvarGetProbindex(consvars[v])] += 1;
2815 }
2816 }
2817 }
2818
2819 return SCIP_OKAY;
2820}
2821
2822/** determines whether a variable is interesting */
2823static
2825 SCIP* scip, /**< SCIP data structure */
2826 SCIP_VAR* var, /**< variable to check */
2827 int nlcount, /**< number of nonlinear constraints containing the variable
2828 * or number of non-convex terms containing the variable
2829 * (depends on propdata->onlynonconvexvars) */
2830 int nindcount /**< number of indicator constraints containing the variable
2831 * or 0 (depends on propdata->indicators) */
2832 )
2833{
2834 assert(SCIPgetDepth(scip) == 0);
2835
2836 return !SCIPvarIsBinary(var) && SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN && (nlcount > 0 || nindcount > 0)
2837 && !varIsFixedLocal(scip, var);
2838}
2839
2840/** initializes interesting bounds */
2841static
2843 SCIP* scip, /**< SCIP data structure */
2844 SCIP_PROPDATA* propdata /**< data of the obbt propagator */
2845 )
2846{
2847 SCIP_CONSHDLR* conshdlr;
2848 SCIP_VAR** vars; /* array of the problems variables */
2849 int* nlcount; /* array that stores in how many nonlinearities each variable appears */
2850 int* nindcount; /* array that stores in how many indicator constraints each variable appears */
2851 unsigned int* nccount; /* array that stores in how many nonconvexities each variable appears */
2852 SCIP_Real maxcouplingvalue;
2853 SCIP_Real sepacouplingvalue;
2854 SCIP_Real smallub;
2855
2856 int bdidx; /* bound index inside propdata->bounds */
2857 int maxnlcount; /* maximal number of nonlinear and indicator constraints a variable appears in */
2858 int nvars; /* number of the problems variables */
2859 int i;
2860
2861 assert(scip != NULL);
2862 assert(propdata != NULL);
2863 assert(SCIPisNLPConstructed(scip) || propdata->indicators);
2864
2865 SCIPdebugMsg(scip, "initialize bounds\n");
2866
2867 /* get variable data */
2868 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
2869
2870 SCIP_CALL( SCIPallocBufferArray(scip, &nlcount, nvars) );
2871 SCIP_CALL( SCIPallocBufferArray(scip, &nccount, nvars) );
2872 SCIP_CALL( SCIPallocBufferArray(scip, &nindcount, nvars) );
2873
2874 /* count nonlinearities */
2876 {
2877 assert(SCIPgetNNLPVars(scip) == nvars);
2880 }
2881 else
2882 {
2883 /* initialize to zero */
2884 BMSclearMemoryArray(nlcount, nvars);
2885 BMSclearMemoryArray(nccount, nvars);
2886 }
2887
2888 /* count indicators */
2889 if( propdata->indicators )
2890 {
2891 SCIP_CALL( getNVarsIndicators(scip, nindcount) );
2892 }
2893 else
2894 {
2895 /* initialize to zero */
2896 BMSclearMemoryArray(nindcount, nvars);
2897 }
2898
2899 maxnlcount = 0;
2900 for( i = 0; i < nvars; i++ )
2901 {
2902 if( maxnlcount < (nlcount[i] + nindcount[i]) )
2903 maxnlcount = nlcount[i] + nindcount[i];
2904 }
2905
2906 /* allocate interesting bounds array */
2907 propdata->boundssize = 2 * nvars;
2908 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(propdata->bounds), 2 * nvars) );
2909
2910 SCIP_CALL( SCIPgetRealParam(scip, "constraints/indicator/maxcouplingvalue", &maxcouplingvalue) );
2911 SCIP_CALL( SCIPgetRealParam(scip, "constraints/indicator/sepacouplingvalue", &sepacouplingvalue) );
2912
2913 smallub = MIN(maxcouplingvalue, sepacouplingvalue);
2914
2915 /* get all interesting variables and their bounds */
2916 bdidx = 0;
2917 for( i = 0; i < nvars; i++ )
2918 {
2919 if( varIsInteresting(scip, vars[i], (propdata->onlynonconvexvars ? (int)nccount[i] : nlcount[i]), (propdata->indicators ? nindcount[i] : 0))
2920 && indicatorVarIsInteresting(scip, vars[i], (propdata->onlynonconvexvars ? (int)nccount[i] : nlcount[i]), (propdata->indicators ? nindcount[i] : 0), propdata->indicatorthreshold) )
2921 {
2922 BOUND** bdaddress;
2923
2924 /* create lower bound */
2925 bdaddress = &(propdata->bounds[bdidx]);
2926 SCIP_CALL( SCIPallocBlockMemory(scip, bdaddress) );
2927 propdata->bounds[bdidx]->boundtype = SCIP_BOUNDTYPE_LOWER;
2928 propdata->bounds[bdidx]->var = vars[i];
2929 propdata->bounds[bdidx]->found = FALSE;
2930 propdata->bounds[bdidx]->filtered = FALSE;
2931 propdata->bounds[bdidx]->newval = 0.0;
2932 propdata->bounds[bdidx]->score = getScore(scip, propdata->bounds[bdidx], nlcount[i], nindcount[i], maxnlcount, smallub);
2933 propdata->bounds[bdidx]->done = FALSE;
2934 propdata->bounds[bdidx]->nonconvex = (nccount[i] > 0);
2935 propdata->bounds[bdidx]->indicator = (nindcount[i] > 0);
2936 propdata->bounds[bdidx]->index = bdidx;
2937 bdidx++;
2938
2939 /* create upper bound */
2940 bdaddress = &(propdata->bounds[bdidx]);
2941 SCIP_CALL( SCIPallocBlockMemory(scip, bdaddress) );
2942 propdata->bounds[bdidx]->boundtype = SCIP_BOUNDTYPE_UPPER;
2943 propdata->bounds[bdidx]->var = vars[i];
2944 propdata->bounds[bdidx]->found = FALSE;
2945 propdata->bounds[bdidx]->filtered = FALSE;
2946 propdata->bounds[bdidx]->newval = 0.0;
2947 propdata->bounds[bdidx]->score = getScore(scip, propdata->bounds[bdidx], nlcount[i], nindcount[i], maxnlcount, smallub);
2948 propdata->bounds[bdidx]->done = FALSE;
2949 propdata->bounds[bdidx]->nonconvex = (nccount[i] > 0);
2950 propdata->bounds[bdidx]->indicator = (nindcount[i] > 0);
2951 propdata->bounds[bdidx]->index = bdidx;
2952 bdidx++;
2953 }
2954 }
2955
2956 /* set number of interesting bounds */
2957 propdata->nbounds = bdidx;
2958
2959 conshdlr = SCIPfindConshdlr(scip, "nonlinear");
2960
2961 /* get all product expressions from nonlinear constraint handler */
2962 if( propdata->nbounds > 0 && conshdlr != NULL && propdata->createbilinineqs )
2963 {
2964 SCIP_NLHDLR* bilinnlhdlr;
2965 SCIP_EXPR** exprs;
2966 int nexprs;
2967
2968 /* find nonlinear handler for bilinear terms */
2969 bilinnlhdlr = SCIPfindNlhdlrNonlinear(conshdlr, "bilinear");
2970 assert(bilinnlhdlr != NULL);
2971
2972 /* collect all bilinear product in all nonlinear constraints */
2973 exprs = SCIPgetExprsBilinear(bilinnlhdlr);
2974 nexprs = SCIPgetNExprsBilinear(bilinnlhdlr);
2975
2976 if( nexprs > 0 )
2977 {
2978 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->bilinbounds, nexprs) );
2979 propdata->bilinboundssize = nexprs;
2980 propdata->nbilinbounds = 0;
2981
2982 /* store candidates as bilinear bounds */
2983 for( i = 0; i < nexprs; ++i )
2984 {
2985 BILINBOUND* bilinbound;
2986 SCIP_VAR* x;
2987 SCIP_VAR* y;
2988
2989 assert(exprs[i] != NULL);
2990 assert(SCIPexprGetNChildren(exprs[i]) == 2);
2991
2994 assert(x != NULL);
2995 assert(y != NULL);
2996 assert(x != y);
2997
2998 /* skip almost fixed variables */
2999 if( !varIsInteresting(scip, x, 1, 0) || !varIsInteresting(scip, y, 1, 0) )
3000 continue;
3001
3002 /* create bilinear bound */
3003 SCIP_CALL( SCIPallocBlockMemory(scip, &propdata->bilinbounds[propdata->nbilinbounds]) ); /*lint !e866*/
3004 bilinbound = propdata->bilinbounds[propdata->nbilinbounds];
3005 BMSclearMemory(bilinbound);
3006
3007 /* store and capture expression */
3008 bilinbound->expr = exprs[i];
3009 SCIPcaptureExpr(bilinbound->expr);
3010
3011 /* compute a descent score */
3012 bilinbound->score = bilinboundGetScore(scip, propdata->randnumgen, bilinbound);
3013
3014 /* increase the number of bilinear bounds */
3015 ++(propdata->nbilinbounds);
3016
3017 SCIPdebugMsg(scip, "added bilinear bound for %s %s\n", SCIPvarGetName(x), SCIPvarGetName(y));
3018 }
3019 }
3020
3021 /* sort bounds according to decreasing score */
3022 if( propdata->nbilinbounds > 1 )
3023 {
3024 SCIPsortDownPtr((void**) propdata->bilinbounds, compBilinboundsScore, propdata->nbilinbounds);
3025 }
3026 }
3027
3028 /* free memory for buffering nonlinearities */
3029 assert(nlcount != NULL);
3030 assert(nccount != NULL);
3031 assert(nindcount != NULL);
3032 SCIPfreeBufferArray(scip, &nindcount);
3033 SCIPfreeBufferArray(scip, &nccount);
3034 SCIPfreeBufferArray(scip, &nlcount);
3035
3036 /* propdata->bounds array if empty */
3037 if( propdata->nbounds <= 0 )
3038 {
3039 assert(propdata->nbounds == 0);
3040 assert(propdata->boundssize >= 0 );
3041 SCIPfreeBlockMemoryArray(scip, &(propdata->bounds), propdata->boundssize);
3042 }
3043
3044 SCIPdebugMsg(scip, "problem has %d/%d interesting bounds\n", propdata->nbounds, 2 * nvars);
3045
3046 if( propdata->nbounds > 0 )
3047 {
3048 /* sort bounds according to decreasing score; although this initial order will be overruled by the distance
3049 * criterion later, gives a more well-defined starting situation for OBBT and might help to reduce solver
3050 * variability
3051 */
3052 SCIPsortDownPtr((void**) propdata->bounds, compBoundsScore, propdata->nbounds);
3053 }
3054
3055 return SCIP_OKAY;
3056}
3057
3058/*
3059 * Callback methods of propagator
3060 */
3061
3062/** copy method for propagator plugins (called when SCIP copies plugins)
3063 *
3064 * @note The UG framework assumes that all default plug-ins of SCIP implement a copy callback. We check
3065 * SCIPgetSubscipDepth() in PROPEXEC to prevent the propagator to run in a sub-SCIP.
3066 */
3067static
3069{ /*lint --e{715}*/
3070 assert(scip != NULL);
3071 assert(prop != NULL);
3072 assert(strcmp(SCIPpropGetName(prop), PROP_NAME) == 0);
3073
3074 /* call inclusion method of constraint handler */
3076
3077 return SCIP_OKAY;
3078}
3079
3080/** solving process initialization method of propagator (called when branch and bound process is about to begin) */
3081static
3083{ /*lint --e{715}*/
3084 SCIP_PROPDATA* propdata;
3085
3086 assert(scip != NULL);
3087 assert(prop != NULL);
3088 assert(strcmp(SCIPpropGetName(prop), PROP_NAME) == 0);
3089
3090 /* get propagator data */
3091 propdata = SCIPpropGetData(prop);
3092 assert(propdata != NULL);
3093
3094 propdata->bounds = NULL;
3095 propdata->nbounds = -1;
3096 propdata->boundssize = 0;
3097 propdata->cutoffrow = NULL;
3098 propdata->lastnode = -1;
3099
3100 /* if genvbounds propagator is not available, we cannot create genvbounds */
3101 propdata->genvboundprop = propdata->creategenvbounds ? SCIPfindProp(scip, GENVBOUND_PROP_NAME) : NULL;
3102
3103 SCIPdebugMsg(scip, "creating genvbounds: %s\n", propdata->genvboundprop != NULL ? "true" : "false");
3104
3105 /* create random number generator */
3106 SCIP_CALL( SCIPcreateRandom(scip, &propdata->randnumgen, DEFAULT_RANDSEED, TRUE) );
3107
3108 return SCIP_OKAY;
3109}
3110
3111/** execution method of propagator */
3112static
3114{ /*lint --e{715}*/
3115 SCIP_PROPDATA* propdata;
3116 SCIP_Longint itlimit;
3117
3118 assert(scip != NULL);
3119 assert(prop != NULL);
3120 assert(strcmp(SCIPpropGetName(prop), PROP_NAME) == 0);
3121
3122 *result = SCIP_DIDNOTRUN;
3123
3124 /* do not run in: presolving, repropagation, probing mode, if no objective propagation is allowed */
3126 return SCIP_OKAY;
3127
3128 /* do not run propagator in a sub-SCIP */
3129 if( SCIPgetSubscipDepth(scip) > 0 )
3130 return SCIP_OKAY;
3131
3132 /* get propagator data */
3133 propdata = SCIPpropGetData(prop);
3134 assert(propdata != NULL);
3135
3136 /* only run for nonlinear problems, i.e., if NLP is constructed
3137 * or if indicator constraints exists and should be considered
3138 */
3140 && (!propdata->indicators || SCIPfindConshdlr(scip, "indicator") == NULL || SCIPconshdlrGetNConss(SCIPfindConshdlr(scip, "indicator")) == 0) )
3141 {
3142 SCIPdebugMsg(scip, "NLP not constructed and no indicator constraints available, skipping obbt\n");
3143 return SCIP_OKAY;
3144 }
3145
3146 /* only run if LP all columns are in the LP, i.e., the LP is a relaxation; e.g., do not run if pricers are active
3147 * since pricing is not performed in probing mode
3148 */
3149 if( !SCIPallColsInLP(scip) )
3150 {
3151 SCIPdebugMsg(scip, "not all columns in LP, skipping obbt\n");
3152 return SCIP_OKAY;
3153 }
3154
3155 /* ensure that bounds are initialized */
3156 if( propdata->nbounds == -1 )
3157 {
3158 /* bounds must be initialized at root node */
3159 if( SCIPgetDepth(scip) == 0 )
3160 {
3161 SCIP_CALL( initBounds(scip, propdata) );
3162 }
3163 else
3164 {
3165 assert(!SCIPinProbing(scip));
3166 return SCIP_OKAY;
3167 }
3168 }
3169 assert(propdata->nbounds >= 0);
3170
3171 /* do not run if there are no interesting bounds */
3172 /**@todo disable */
3173 if( propdata->nbounds <= 0 )
3174 {
3175 SCIPdebugMsg(scip, "there are no interesting bounds\n");
3176 return SCIP_OKAY;
3177 }
3178
3179 /* only run once in a node != root */
3180 if( SCIPgetDepth(scip) > 0 && SCIPnodeGetNumber(SCIPgetCurrentNode(scip)) == propdata->lastnode )
3181 {
3182 return SCIP_OKAY;
3183 }
3184
3185 SCIPdebugMsg(scip, "applying obbt for problem <%s> at depth %d\n", SCIPgetProbName(scip), SCIPgetDepth(scip));
3186
3187 /* without an optimal LP solution we don't want to run; this may be because propagators with higher priority have
3188 * already found reductions or numerical troubles occured during LP solving
3189 */
3191 {
3192 SCIPdebugMsg(scip, "aborting since no optimal LP solution is at hand\n");
3193 return SCIP_OKAY;
3194 }
3195
3196 /* compute iteration limit */
3197 if( propdata->itlimitfactor > 0.0 )
3198 itlimit = (SCIP_Longint) MAX(propdata->itlimitfactor * SCIPgetNRootLPIterations(scip),
3199 propdata->minitlimit); /*lint !e666*/
3200 else
3201 itlimit = -1;
3202
3203 /* apply obbt */
3204 SCIP_CALL( applyObbt(scip, propdata, itlimit, result) );
3205 assert(*result != SCIP_DIDNOTRUN);
3206
3207 /* compute globally inequalities for bilinear terms */
3208 if( propdata->createbilinineqs )
3209 {
3210 /* set LP iteration limit */
3211 if( propdata->itlimitbilin == 0L )
3212 {
3213 /* no iteration limit if itlimit < 0 or itlimitfactorbilin < 0 */
3214 propdata->itlimitbilin = (itlimit < 0 || propdata->itlimitfactorbilin < 0)
3215 ? -1L : (SCIP_Longint)(itlimit * propdata->itlimitfactorbilin);
3216 }
3217
3218 SCIP_CALL( applyObbtBilinear(scip, propdata, itlimit, result) );
3219 }
3220
3221 /* set current node as last node */
3222 propdata->lastnode = SCIPnodeGetNumber(SCIPgetCurrentNode(scip));
3223
3224 return SCIP_OKAY;
3225}
3226
3227/** propagation conflict resolving method of propagator */
3228static
3230{ /*lint --e{715}*/
3231 *result = SCIP_DIDNOTFIND;
3232
3233 return SCIP_OKAY;
3234}
3235
3236/** solving process deinitialization method of propagator (called before branch and bound process data is freed) */
3237static
3239{ /*lint --e{715}*/
3240 SCIP_PROPDATA* propdata;
3241 int i;
3242
3243 assert(scip != NULL);
3244 assert(prop != NULL);
3245 assert(strcmp(SCIPpropGetName(prop), PROP_NAME) == 0);
3246
3247 /* get propagator data */
3248 propdata = SCIPpropGetData(prop);
3249 assert(propdata != NULL);
3250
3251 /* free random number generator */
3252 SCIPfreeRandom(scip, &propdata->randnumgen);
3253 propdata->randnumgen = NULL;
3254
3255 /* note that because we reset filtered flags to false at each call to obbt, the same bound may be filtered multiple
3256 * times
3257 */
3258 SCIPstatisticMessage("DIVE-LP: %" SCIP_LONGINT_FORMAT " NFILTERED: %d NTRIVIALFILTERED: %d NSOLVED: %d "
3259 "FILTER-LP: %" SCIP_LONGINT_FORMAT " NGENVB(dive): %d NGENVB(aggr.): %d NGENVB(triv.) %d\n",
3260 propdata->nprobingiterations, propdata->nfiltered, propdata->ntrivialfiltered, propdata->nsolvedbounds,
3261 propdata->nfilterlpiters, propdata->ngenvboundsprobing, propdata->ngenvboundsaggrfil, propdata->ngenvboundstrivfil);
3262
3263 /* free bilinear bounds */
3264 if( propdata->bilinboundssize > 0 )
3265 {
3266 for( i = propdata->nbilinbounds - 1; i >= 0; --i )
3267 {
3268 assert(propdata->bilinbounds[i] != NULL);
3269 assert(propdata->bilinbounds[i]->expr != NULL);
3270
3271 /* release expression */
3272 SCIP_CALL( SCIPreleaseExpr(scip, &propdata->bilinbounds[i]->expr) );
3273
3274 SCIPfreeBlockMemory(scip, &propdata->bilinbounds[i]); /*lint !e866*/
3275 }
3276 SCIPfreeBlockMemoryArray(scip, &propdata->bilinbounds, propdata->bilinboundssize);
3277 propdata->bilinboundssize = 0;
3278 propdata->nbilinbounds = 0;
3279 }
3280
3281 /* free memory allocated for the bounds */
3282 if( propdata->nbounds > 0 )
3283 {
3284 /* free bounds */
3285 for( i = propdata->nbounds - 1; i >= 0; i-- )
3286 {
3287 SCIPfreeBlockMemory(scip, &(propdata->bounds[i])); /*lint !e866*/
3288 }
3289 SCIPfreeBlockMemoryArray(scip, &(propdata->bounds), propdata->boundssize);
3290 }
3291
3292 propdata->nbounds = -1;
3293 propdata->itlimitbilin = 0;
3294 propdata->itusedbilin = 0;
3295
3296 return SCIP_OKAY;
3297}
3298
3299/** destructor of propagator to free user data (called when SCIP is exiting) */
3300static
3302{ /*lint --e{715}*/
3303 SCIP_PROPDATA* propdata;
3304
3305 assert(strcmp(SCIPpropGetName(prop), PROP_NAME) == 0);
3306
3307 /* free propagator data */
3308 propdata = SCIPpropGetData(prop);
3309 assert(propdata != NULL);
3310
3311 SCIPfreeBlockMemory(scip, &propdata);
3312
3313 SCIPpropSetData(prop, NULL);
3314
3315 return SCIP_OKAY;
3316}
3317
3318/*
3319 * propagator specific interface methods
3320 */
3321
3322/** creates the obbt propagator and includes it in SCIP */
3324 SCIP* scip /**< SCIP data structure */
3325 )
3326{
3327 SCIP_PROPDATA* propdata;
3328 SCIP_PROP* prop;
3329
3330 /* create obbt propagator data */
3331 SCIP_CALL( SCIPallocBlockMemory(scip, &propdata) );
3332 BMSclearMemory(propdata);
3333
3334 /* initialize statistic variables */
3335 propdata->nprobingiterations = 0;
3336 propdata->nfiltered = 0;
3337 propdata->ntrivialfiltered = 0;
3338 propdata->nsolvedbounds = 0;
3339 propdata->ngenvboundsprobing = 0;
3340 propdata->ngenvboundsaggrfil = 0;
3341 propdata->ngenvboundstrivfil = 0;
3342 propdata->nfilterlpiters = 0;
3343 propdata->lastidx = -1;
3344 propdata->propagatecounter = 0;
3345 propdata->npropagatedomreds = 0;
3346
3347 /* include propagator */
3349 propExecObbt, propdata) );
3350
3351 SCIP_CALL( SCIPsetPropCopy(scip, prop, propCopyObbt) );
3352 SCIP_CALL( SCIPsetPropFree(scip, prop, propFreeObbt) );
3353 SCIP_CALL( SCIPsetPropExitsol(scip, prop, propExitsolObbt) );
3354 SCIP_CALL( SCIPsetPropInitsol(scip, prop, propInitsolObbt) );
3355 SCIP_CALL( SCIPsetPropResprop(scip, prop, propRespropObbt) );
3356
3357 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/creategenvbounds",
3358 "should obbt try to provide genvbounds if possible?",
3359 &propdata->creategenvbounds, TRUE, DEFAULT_CREATE_GENVBOUNDS, NULL, NULL) );
3360
3361 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/normalize",
3362 "should coefficients in filtering be normalized w.r.t. the domains sizes?",
3363 &propdata->normalize, TRUE, DEFAULT_FILTERING_NORM, NULL, NULL) );
3364
3365 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/applyfilterrounds",
3366 "try to filter bounds in so-called filter rounds by solving auxiliary LPs?",
3367 &propdata->applyfilterrounds, TRUE, DEFAULT_APPLY_FILTERROUNDS, NULL, NULL) );
3368
3369 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/applytrivialfilter",
3370 "try to filter bounds with the LP solution after each solve?",
3371 &propdata->applytrivialfilter, TRUE, DEFAULT_APPLY_TRIVIALFITLERING, NULL, NULL) );
3372
3373 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/genvbdsduringfilter",
3374 "should we try to generate genvbounds during trivial and aggressive filtering?",
3375 &propdata->genvbdsduringfilter, TRUE, DEFAULT_GENVBDSDURINGFILTER, NULL, NULL) );
3376
3377 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/genvbdsduringsepa",
3378 "try to create genvbounds during separation process?",
3379 &propdata->genvbdsduringsepa, TRUE, DEFAULT_GENVBDSDURINGSEPA, NULL, NULL) );
3380
3381 SCIP_CALL( SCIPaddIntParam(scip, "propagating/" PROP_NAME "/minfilter",
3382 "minimal number of filtered bounds to apply another filter round",
3383 &propdata->nminfilter, TRUE, DEFAULT_FILTERING_MIN, 1, INT_MAX, NULL, NULL) );
3384
3385 SCIP_CALL( SCIPaddRealParam(scip, "propagating/" PROP_NAME "/itlimitfactor",
3386 "multiple of root node LP iterations used as total LP iteration limit for obbt (<= 0: no limit )",
3387 &propdata->itlimitfactor, FALSE, DEFAULT_ITLIMITFACTOR, SCIP_REAL_MIN, SCIP_REAL_MAX, NULL, NULL) );
3388
3389 SCIP_CALL( SCIPaddRealParam(scip, "propagating/" PROP_NAME "/itlimitfactorbilin",
3390 "multiple of OBBT LP limit used as total LP iteration limit for solving bilinear inequality LPs (< 0 for no limit)",
3391 &propdata->itlimitfactorbilin, FALSE, DEFAULT_ITLIMITFAC_BILININEQS, SCIP_REAL_MIN, SCIP_REAL_MAX, NULL, NULL) );
3392
3393 SCIP_CALL( SCIPaddRealParam(scip, "propagating/" PROP_NAME "/minnonconvexity",
3394 "minimum absolute value of nonconvex eigenvalues for a bilinear term",
3395 &propdata->minnonconvexity, FALSE, DEFAULT_MINNONCONVEXITY, 0.0, SCIP_REAL_MAX, NULL, NULL) );
3396
3397 SCIP_CALL( SCIPaddLongintParam(scip, "propagating/" PROP_NAME "/minitlimit",
3398 "minimum LP iteration limit",
3399 &propdata->minitlimit, FALSE, DEFAULT_MINITLIMIT, 0L, SCIP_LONGINT_MAX, NULL, NULL) );
3400
3401 SCIP_CALL( SCIPaddRealParam(scip, "propagating/" PROP_NAME "/dualfeastol",
3402 "feasibility tolerance for reduced costs used in obbt; this value is used if SCIP's dual feastol is greater",
3403 &propdata->dualfeastol, FALSE, DEFAULT_DUALFEASTOL, 0.0, SCIP_REAL_MAX, NULL, NULL) );
3404
3405 SCIP_CALL( SCIPaddRealParam(scip, "propagating/" PROP_NAME "/conditionlimit",
3406 "maximum condition limit used in LP solver (-1.0: no limit)",
3407 &propdata->conditionlimit, FALSE, DEFAULT_CONDITIONLIMIT, -1.0, SCIP_REAL_MAX, NULL, NULL) );
3408
3409 SCIP_CALL( SCIPaddRealParam(scip, "propagating/" PROP_NAME "/boundstreps",
3410 "minimal relative improve for strengthening bounds",
3411 &propdata->boundstreps, FALSE, DEFAULT_BOUNDSTREPS, 0.0, 1.0, NULL, NULL) );
3412
3413 SCIP_CALL( SCIPaddRealParam(scip, "propagating/" PROP_NAME "/indicatorthreshold",
3414 "threshold whether upper bounds of vars of indicator conss are considered or tightened",
3415 &propdata->indicatorthreshold, TRUE, DEFAULT_INDICATORTHRESHOLD, 0.0, SCIP_REAL_MAX, NULL, NULL) );
3416
3417 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/onlynonconvexvars",
3418 "only apply obbt on non-convex variables",
3419 &propdata->onlynonconvexvars, TRUE, DEFAULT_ONLYNONCONVEXVARS, NULL, NULL) );
3420
3421 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/indicators",
3422 "apply obbt on variables of indicator constraints? (independent of convexity)",
3423 &propdata->indicators, TRUE, DEFAULT_INDICATORS, NULL, NULL) );
3424
3425 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/tightintboundsprobing",
3426 "should integral bounds be tightened during the probing mode?",
3427 &propdata->tightintboundsprobing, TRUE, DEFAULT_TIGHTINTBOUNDSPROBING, NULL, NULL) );
3428
3429 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/tightcontboundsprobing",
3430 "should continuous bounds be tightened during the probing mode?",
3431 &propdata->tightcontboundsprobing, TRUE, DEFAULT_TIGHTCONTBOUNDSPROBING, NULL, NULL) );
3432
3433 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/createbilinineqs",
3434 "solve auxiliary LPs in order to find valid inequalities for bilinear terms?",
3435 &propdata->createbilinineqs, TRUE, DEFAULT_CREATE_BILININEQS, NULL, NULL) );
3436
3437 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/createlincons",
3438 "create linear constraints from inequalities for bilinear terms?",
3439 &propdata->createlincons, TRUE, DEFAULT_CREATE_LINCONS, NULL, NULL) );
3440
3441 SCIP_CALL( SCIPaddIntParam(scip, "propagating/" PROP_NAME "/orderingalgo",
3442 "select the type of ordering algorithm which should be used (0: no special ordering, 1: greedy, 2: greedy reverse)",
3443 &propdata->orderingalgo, TRUE, DEFAULT_ORDERINGALGO, 0, 2, NULL, NULL) );
3444
3445 SCIP_CALL( SCIPaddBoolParam(scip, "propagating/" PROP_NAME "/separatesol",
3446 "should the obbt LP solution be separated?",
3447 &propdata->separatesol, TRUE, DEFAULT_SEPARATESOL, NULL, NULL) );
3448
3449 SCIP_CALL( SCIPaddIntParam(scip, "propagating/" PROP_NAME "/sepaminiter",
3450 "minimum number of iteration spend to separate an obbt LP solution",
3451 &propdata->sepaminiter, TRUE, DEFAULT_SEPAMINITER, 0, INT_MAX, NULL, NULL) );
3452
3453 SCIP_CALL( SCIPaddIntParam(scip, "propagating/" PROP_NAME "/sepamaxiter",
3454 "maximum number of iteration spend to separate an obbt LP solution",
3455 &propdata->sepamaxiter, TRUE, DEFAULT_SEPAMAXITER, 0, INT_MAX, NULL, NULL) );
3456
3457 SCIP_CALL( SCIPaddIntParam(scip, "propagating/" PROP_NAME "/propagatefreq",
3458 "trigger a propagation round after that many bound tightenings (0: no propagation)",
3459 &propdata->propagatefreq, TRUE, DEFAULT_PROPAGATEFREQ, 0, INT_MAX, NULL, NULL) );
3460
3461 return SCIP_OKAY;
3462}
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:248
#define SCIP_MAXSTRLEN
Definition: def.h:269
#define SCIP_Longint
Definition: def.h:141
#define SCIP_REAL_MAX
Definition: def.h:158
#define SCIP_INVALID
Definition: def.h:178
#define SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:224
#define MAX3(x, y, z)
Definition: def.h:228
#define SCIP_Real
Definition: def.h:156
#define SQR(x)
Definition: def.h:199
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:220
#define SCIP_LONGINT_FORMAT
Definition: def.h:148
#define SCIPABORT()
Definition: def.h:327
#define SCIP_REAL_MIN
Definition: def.h:159
#define REALABS(x)
Definition: def.h:182
#define SCIP_LONGINT_MAX
Definition: def.h:142
#define EPSZ(x, eps)
Definition: def.h:188
#define SCIP_CALL(x)
Definition: def.h:355
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:2588
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:759
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:444
const char * SCIPgetProbName(SCIP *scip)
Definition: scip_prob.c:1242
SCIP_RETCODE SCIPgetVarsData(SCIP *scip, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars, int *nimplvars, int *ncontvars)
Definition: scip_prob.c:2115
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:2246
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3274
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:2201
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3284
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3466
#define SCIPdebugMsg
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:11162
SCIP_RETCODE SCIPgenVBoundAdd(SCIP *scip, SCIP_PROP *genvboundprop, SCIP_VAR **vars, SCIP_VAR *var, SCIP_Real *coefs, int ncoefs, SCIP_Real coefcutoffbound, SCIP_Real constant, SCIP_BOUNDTYPE boundtype)
SCIP_RETCODE SCIPaddLongintParam(SCIP *scip, const char *name, const char *desc, SCIP_Longint *valueptr, SCIP_Bool isadvanced, SCIP_Longint defaultvalue, SCIP_Longint minvalue, SCIP_Longint maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:111
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:83
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:139
SCIP_RETCODE SCIPsetIntParam(SCIP *scip, const char *name, int value)
Definition: scip_param.c:487
SCIP_RETCODE SCIPgetRealParam(SCIP *scip, const char *name, SCIP_Real *value)
Definition: scip_param.c:307
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:57
SCIP_RETCODE SCIPgetIntParam(SCIP *scip, const char *name, int *value)
Definition: scip_param.c:269
SCIP_RETCODE SCIPsetRealParam(SCIP *scip, const char *name, SCIP_Real value)
Definition: scip_param.c:603
SCIP_RETCODE SCIPincludePropObbt(SCIP *scip)
Definition: prop_obbt.c:3323
SCIP_BASESTAT SCIPcolGetBasisStatus(SCIP_COL *col)
Definition: lp.c:17414
int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4778
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:940
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4735
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1173
SCIP_RETCODE SCIPseparateSol(SCIP *scip, SCIP_SOL *sol, SCIP_Bool pretendroot, SCIP_Bool allowlocal, SCIP_Bool onlydelayed, SCIP_Bool *delayed, SCIP_Bool *cutoff)
Definition: scip_cut.c:710
int SCIPgetNCuts(SCIP *scip)
Definition: scip_cut.c:762
int SCIPexprGetNChildren(SCIP_EXPR *expr)
Definition: expr.c:3872
SCIP_RETCODE SCIPreleaseExpr(SCIP *scip, SCIP_EXPR **expr)
Definition: scip_expr.c:1443
SCIP_Bool SCIPisExprVar(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1457
SCIP_EXPR ** SCIPexprGetChildren(SCIP_EXPR *expr)
Definition: expr.c:3882
void SCIPcaptureExpr(SCIP_EXPR *expr)
Definition: scip_expr.c:1435
SCIP_ROW ** SCIPgetLPRows(SCIP *scip)
Definition: scip_lp.c:611
int SCIPgetNLPRows(SCIP *scip)
Definition: scip_lp.c:632
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip_lp.c:174
SCIP_Bool SCIPallColsInLP(SCIP *scip)
Definition: scip_lp.c:655
SCIP_Real SCIPgetLPObjval(SCIP *scip)
Definition: scip_lp.c:253
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:110
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:136
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:93
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip_mem.h:137
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition: scip_nlp.c:110
int SCIPgetNNLPVars(SCIP *scip)
Definition: scip_nlp.c:201
SCIP_RETCODE SCIPgetNLPVarsNonlinearity(SCIP *scip, int *nlcount)
Definition: scip_nlp.c:223
SCIP_NLHDLR * SCIPfindNlhdlrNonlinear(SCIP_CONSHDLR *conshdlr, const char *name)
SCIP_Longint SCIPnodeGetNumber(SCIP_NODE *node)
Definition: tree.c:8483
SCIP_RETCODE SCIPaddRowProbing(SCIP *scip, SCIP_ROW *row)
Definition: scip_probing.c:913
SCIP_RETCODE SCIPapplyCutsProbing(SCIP *scip, SCIP_Bool *cutoff)
Definition: scip_probing.c:953
SCIP_RETCODE SCIPchgVarUbProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_probing.c:346
SCIP_RETCODE SCIPchgVarLbProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_probing.c:302
SCIP_RETCODE SCIPpropagateProbing(SCIP *scip, int maxproprounds, SCIP_Bool *cutoff, SCIP_Longint *ndomredsfound)
Definition: scip_probing.c:581
SCIP_RETCODE SCIPchgVarObjProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newobj)
Definition: scip_probing.c:475
SCIP_RETCODE SCIPbacktrackProbing(SCIP *scip, int probingdepth)
Definition: scip_probing.c:226
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:98
SCIP_RETCODE SCIPstartProbing(SCIP *scip)
Definition: scip_probing.c:120
SCIP_Real SCIPgetVarObjProbing(SCIP *scip, SCIP_VAR *var)
Definition: scip_probing.c:389
SCIP_RETCODE SCIPnewProbingNode(SCIP *scip)
Definition: scip_probing.c:166
SCIP_RETCODE SCIPsolveProbingLP(SCIP *scip, int itlim, SCIP_Bool *lperror, SCIP_Bool *cutoff)
Definition: scip_probing.c:825
SCIP_RETCODE SCIPendProbing(SCIP *scip)
Definition: scip_probing.c:261
SCIP_PROP * SCIPfindProp(SCIP *scip, const char *name)
Definition: scip_prop.c:333
void SCIPpropSetData(SCIP_PROP *prop, SCIP_PROPDATA *propdata)
Definition: prop.c:801
SCIP_RETCODE 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:791
const char * SCIPpropGetName(SCIP_PROP *prop)
Definition: prop.c:951
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:1581
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1604
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1646
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1508
SCIP_RETCODE SCIPcreateEmptyRowUnspec(SCIP *scip, SCIP_ROW **row, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1458
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:17917
SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
Definition: lp.c:17706
SCIP_Longint SCIPgetNRootLPIterations(SCIP *scip)
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
SCIP_Longint SCIPgetNLPIterations(SCIP *scip)
SCIP_Bool SCIPisUbBetter(SCIP *scip, SCIP_Real newub, SCIP_Real oldlb, SCIP_Real oldub)
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Real SCIPchgRelaxfeastol(SCIP *scip, SCIP_Real relaxfeastol)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLbBetter(SCIP *scip, SCIP_Real newlb, SCIP_Real oldlb, SCIP_Real oldub)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPfeastol(SCIP *scip)
SCIP_Real SCIPdualfeastol(SCIP *scip)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPepsilon(SCIP *scip)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPchgDualfeastol(SCIP *scip, SCIP_Real dualfeastol)
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition: scip_tree.c:146
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:672
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition: scip_tree.c:91
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:6401
SCIP_COL * SCIPvarGetCol(SCIP_VAR *var)
Definition: var.c:23683
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:23478
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:23386
SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
Definition: var.c:23498
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:24268
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:23900
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:6651
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:23453
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:24142
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:23662
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:23267
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:23490
SCIP_Real SCIPvarGetLPSol(SCIP_VAR *var)
Definition: var.c:24664
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:24234
SCIP_Real SCIPgetVarRedcost(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:2608
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:24120
SCIP_Bool SCIPallowWeakDualReds(SCIP *scip)
Definition: scip_var.c:10998
void SCIPfreeRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen)
SCIP_Real SCIPrandomGetReal(SCIP_RANDNUMGEN *randnumgen, SCIP_Real minrandval, SCIP_Real maxrandval)
Definition: misc.c:10245
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:10827
#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:3113
#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:3229
#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:2842
#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:3301
#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:3068
#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:3082
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:3238
#define DEFAULT_GENVBDSDURINGFILTER
Definition: prop_obbt.c:97
static SCIP_RETCODE getNVarsIndicators(SCIP *scip, int *nindcount)
Definition: prop_obbt.c:2764
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:2706
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:2824
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 SCIPerrorMessage
Definition: pub_message.h:64
#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:52
@ SCIP_BOUNDTYPE_UPPER
Definition: type_lp.h:58
@ SCIP_BOUNDTYPE_LOWER
Definition: type_lp.h:57
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:60
@ SCIP_LPSOLSTAT_ERROR
Definition: type_lp.h:50
@ SCIP_LPSOLSTAT_NOTSOLVED
Definition: type_lp.h:43
@ SCIP_LPSOLSTAT_OPTIMAL
Definition: type_lp.h:44
@ SCIP_LPSOLSTAT_TIMELIMIT
Definition: type_lp.h:49
@ SCIP_LPSOLSTAT_UNBOUNDEDRAY
Definition: type_lp.h:46
@ SCIP_LPSOLSTAT_INFEASIBLE
Definition: type_lp.h:45
@ SCIP_LPSOLSTAT_OBJLIMIT
Definition: type_lp.h:47
@ SCIP_LPSOLSTAT_ITERLIMIT
Definition: type_lp.h:48
@ SCIP_BASESTAT_BASIC
Definition: type_lpi.h:92
enum SCIP_BaseStat SCIP_BASESTAT
Definition: type_lpi.h:96
struct SCIP_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:65
@ SCIP_VARTYPE_CONTINUOUS
Definition: type_var.h:71
@ SCIP_VARTYPE_BINARY
Definition: type_var.h:64
@ SCIP_VARSTATUS_COLUMN
Definition: type_var.h:53