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