Scippy

SCIP

Solving Constraint Integer Programs

cons_quadratic.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 cons_quadratic.c
17  * @brief constraint handler for quadratic constraints \f$\textrm{lhs} \leq \sum_{i,j=1}^n a_{i,j} x_i x_j + \sum_{i=1}^n b_i x_i \leq \textrm{rhs}\f$
18  * @author Stefan Vigerske
19  * @author Benjamin Mueller
20  * @author Felipe Serrano
21  *
22  * @todo SCIP might fix linear variables on +/- infinity; remove them in presolve and take care later
23  * @todo round constraint sides to integers if all coefficients and variables are (impl.) integer
24  * @todo constraints in one variable should be replaced by linear or bounddisjunction constraint
25  * @todo check if some quadratic terms appear in several constraints and try to simplify (e.g., nous1)
26  * @todo skip separation in enfolp if for current LP (check LP id) was already separated
27  * @todo watch unbounded variables to enable/disable propagation
28  * @todo sort order in bilinvar1/bilinvar2 such that the var which is involved in more terms is in bilinvar1, and use this info propagate and AddLinearReform
29  * @todo underestimate for multivariate concave quadratic terms as in cons_nonlinear
30  */
31 
32 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
33 
34 #include <assert.h>
35 #include <string.h> /* for strcmp */
36 #include <ctype.h> /* for isspace */
37 #include <math.h>
38 
39 #define SCIP_PRIVATE_ROWPREP
40 
41 #include "scip/cons_nonlinear.h"
42 #include "scip/cons_quadratic.h"
43 #include "scip/cons_linear.h"
44 #include "scip/cons_and.h"
45 #include "scip/cons_varbound.h"
47 #include "scip/intervalarith.h"
48 #include "scip/heur_subnlp.h"
49 #include "scip/heur_trysol.h"
50 #include "scip/debug.h"
51 #include "nlpi/nlpi.h"
52 #include "nlpi/nlpi_ipopt.h"
53 
54 /* constraint handler properties */
55 #define CONSHDLR_NAME "quadratic"
56 #define CONSHDLR_DESC "quadratic constraints of the form lhs <= b' x + x' A x <= rhs"
57 #define CONSHDLR_SEPAPRIORITY 10 /**< priority of the constraint handler for separation */
58 #define CONSHDLR_ENFOPRIORITY -50 /**< priority of the constraint handler for constraint enforcing */
59 #define CONSHDLR_CHECKPRIORITY -4000000 /**< priority of the constraint handler for checking feasibility */
60 #define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
61 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
62 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
63  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
64 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
65 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
66 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
67 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
68 
69 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP /**< propagation timing mask of the constraint handler */
70 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS /**< presolving timing of the constraint handler (fast, medium, or exhaustive) */
71 
72 #define MAXDNOM 10000LL /**< maximal denominator for simple rational fixed values */
73 #define NONLINCONSUPGD_PRIORITY 40000 /**< priority of upgrading nonlinear constraints */
74 #define INITLPMAXVARVAL 1000.0 /**< maximal absolute value of variable for still generating a linearization cut at that point in initlp */
75 
76 /* Activating this define enables reformulation of bilinear terms x*y with implications from x to y into linear terms.
77  * However, implications are not enforced by SCIP. Thus, if, e.g., the used implication was derived from this constraint and we then reformulate the constraint,
78  * then the implication may not be enforced in a solution.
79  * This issue need to be fixed before this feature can be enabled.
80  */
81 /* #define CHECKIMPLINBILINEAR */
82 
83 /* enable new propagation for bivariate quadratic terms */
84 #define PROPBILINNEW
85 
86 /* epsilon for differentiating between a boundary and interior point */
87 #define INTERIOR_EPS 1e-1
88 
89 /* scaling factor for gauge function */
90 #define GAUGESCALE 0.99999
91 
92 #define ROWPREP_SCALEUP_VIOLNONZERO (minviol / 10.0) /**< minimal violation for considering up-scaling of rowprep (we want to avoid upscaling very small violations) */
93 #define ROWPREP_SCALEUP_MINVIOLFACTOR 2.0 /**< scale up will target a violation of ~MINVIOLFACTOR*minviol, where minviol is given by caller */
94 #define ROWPREP_SCALEUP_MAXMINCOEF (1.0 / SCIPfeastol(scip)) /**< scale up only if min. coef is below this number (before scaling) */
95 #define ROWPREP_SCALEUP_MAXMAXCOEF SCIPgetHugeValue(scip) /**< scale up only if max. coef will not exceed this number by scaling */
96 #define ROWPREP_SCALEUP_MAXSIDE SCIPgetHugeValue(scip) /**< scale up only if side will not exceed this number by scaling */
97 #define ROWPREP_SCALEDOWN_MINMAXCOEF (1.0 / SCIPfeastol(scip)) /**< scale down if max. coef is at least this number (before scaling) */
98 #define ROWPREP_SCALEDOWN_MINCOEF SCIPfeastol(scip) /**< scale down only if min. coef does not drop below this number by scaling */
99 
100 /*
101  * Data structures
102  */
103 
104 /** eventdata for variable bound change events in quadratic constraints */
105 struct SCIP_QuadVarEventData
106 {
107  SCIP_CONS* cons; /**< the constraint */
108  int varidx; /**< the index of the variable which bound change is caught, positive for linear variables, negative for quadratic variables */
109  int filterpos; /**< position of eventdata in SCIP's event filter */
110 };
111 
112 /** Data of a quadratic constraint. */
113 struct SCIP_ConsData
114 {
115  SCIP_Real lhs; /**< left hand side of constraint */
116  SCIP_Real rhs; /**< right hand side of constraint */
117 
118  int nlinvars; /**< number of linear variables */
119  int linvarssize; /**< length of linear variable arrays */
120  SCIP_VAR** linvars; /**< linear variables */
121  SCIP_Real* lincoefs; /**< coefficients of linear variables */
122  SCIP_QUADVAREVENTDATA** lineventdata; /**< eventdata for bound change of linear variable */
123 
124  int nquadvars; /**< number of variables in quadratic terms */
125  int quadvarssize; /**< length of quadratic variable terms arrays */
126  SCIP_QUADVARTERM* quadvarterms; /**< array with quadratic variable terms */
127 
128  int nbilinterms; /**< number of bilinear terms */
129  int bilintermssize; /**< length of bilinear term arrays */
130  SCIP_BILINTERM* bilinterms; /**< bilinear terms array */
131  int* bilintermsidx; /**< unique index of each bilinear term xy in the bilinestimators array of the constraint handler data */
132 
133  SCIP_NLROW* nlrow; /**< a nonlinear row representation of this constraint */
134 
135  unsigned int linvarssorted:1; /**< are the linear variables already sorted? */
136  unsigned int linvarsmerged:1; /**< are equal linear variables already merged? */
137  unsigned int quadvarssorted:1; /**< are the quadratic variables already sorted? */
138  unsigned int quadvarsmerged:1; /**< are equal quadratic variables already merged? */
139  unsigned int bilinsorted:1; /**< are the bilinear terms already sorted? */
140  unsigned int bilinmerged:1; /**< are equal bilinear terms (and bilinear terms with zero coefficient) already merged? */
141 
142  unsigned int isconvex:1; /**< is quadratic function is convex ? */
143  unsigned int isconcave:1; /**< is quadratic function is concave ? */
144  unsigned int iscurvchecked:1; /**< is quadratic function checked on convexity or concavity ? */
145  unsigned int isremovedfixings:1; /**< did we removed fixed/aggr/multiaggr variables ? */
146  unsigned int ispropagated:1; /**< was the constraint propagated with respect to the current bounds ? */
147  unsigned int ispresolved:1; /**< did we checked for possibilities of upgrading or implicit integer variables ? */
148  unsigned int initialmerge:1; /**< did we perform an initial merge and clean in presolving yet ? */
149 #ifdef CHECKIMPLINBILINEAR
150  unsigned int isimpladded:1; /**< has there been an implication added for a binary variable in a bilinear term? */
151 #endif
152  unsigned int isgaugeavailable:1; /**< is the gauge function computed? */
153  unsigned int isedavailable:1; /**< is the eigen decomposition of A available? */
154 
155  SCIP_Real minlinactivity; /**< sum of minimal activities of all linear terms with finite minimal activity */
156  SCIP_Real maxlinactivity; /**< sum of maximal activities of all linear terms with finite maximal activity */
157  int minlinactivityinf; /**< number of linear terms with infinite minimal activity */
158  int maxlinactivityinf; /**< number of linear terms with infinity maximal activity */
159  SCIP_INTERVAL quadactivitybounds; /**< bounds on the activity of the quadratic term, if up to date, otherwise empty interval */
160  SCIP_Real activity; /**< activity of quadratic function w.r.t. current solution */
161  SCIP_Real lhsviol; /**< violation of lower bound by current solution (used temporarily inside constraint handler) */
162  SCIP_Real rhsviol; /**< violation of lower bound by current solution (used temporarily inside constraint handler) */
163 
164  int linvar_maydecrease; /**< index of a variable in linvars that may be decreased without making any other constraint infeasible, or -1 if none */
165  int linvar_mayincrease; /**< index of a variable in linvars that may be increased without making any other constraint infeasible, or -1 if none */
166 
167  SCIP_VAR** sepaquadvars; /**< variables corresponding to quadvarterms to use in separation, only available in solving stage */
168  int* sepabilinvar2pos; /**< position of second variable in bilinear terms to use in separation, only available in solving stage */
169  SCIP_Real lincoefsmin; /**< minimal absolute value of coefficients in linear part, only available in solving stage */
170  SCIP_Real lincoefsmax; /**< maximal absolute value of coefficients in linear part, only available in solving stage */
171 
172  SCIP_Real* factorleft; /**< coefficients of left factor if constraint function is factorable */
173  SCIP_Real* factorright; /**< coefficients of right factor if constraint function is factorable */
174 
175  SCIP_Real* gaugecoefs; /**< coefficients of the gauge function */
176  SCIP_Real gaugeconst; /**< constant of the gauge function */
177  SCIP_Real* interiorpoint; /**< interior point of the region defined by the convex function */
178  SCIP_Real interiorpointval; /**< function value at interior point */
179 
180  SCIP_Real* eigenvalues; /**< eigenvalues of A */
181  SCIP_Real* eigenvectors; /**< orthonormal eigenvectors of A; if A = P D P^T, then eigenvectors is P^T */
182  SCIP_Real* bp; /**< stores b * P where b are the linear coefficients of the quadratic vars */
183  SCIP_Real maxnonconvexity; /**< nonconvexity measure: estimate on largest absolute value of nonconvex eigenvalues */
184 
185  SCIP_Bool isdisaggregated; /**< has the constraint already been disaggregated? if might happen that more disaggreation would be potentially
186  possible, but we reached the maximum number of sparsity components during presolveDisaggregate() */
187 };
188 
189 /** quadratic constraint update method */
191 {
192  SCIP_DECL_QUADCONSUPGD((*quadconsupgd)); /**< method to call for upgrading quadratic constraint */
193  int priority; /**< priority of upgrading method */
194  SCIP_Bool active; /**< is upgrading enabled */
195 };
196 typedef struct SCIP_QuadConsUpgrade SCIP_QUADCONSUPGRADE; /**< quadratic constraint update method */
198 /** structure to store everything needed for using linear inequalities to improve upon the McCormick relaxation */
199 struct BilinearEstimator
200 {
201  SCIP_VAR* x; /**< first variable */
202  SCIP_VAR* y; /**< second variable */
203  SCIP_Real inequnderest[6]; /**< at most two inequalities that can be used to underestimate xy; stored as (xcoef,ycoef,constant) with xcoef x <= ycoef y + constant */
204  SCIP_Real ineqoverest[6]; /**< at most two inequalities that can be used to overestimate xy; stored as (xcoef,ycoef,constant) with xcoef x <= ycoef y + constant */
205  SCIP_Real maxnonconvexity; /**< estimate on largest absolute value of nonconvex eigenvalues of all quadratic constraint containing xy */
206  int ninequnderest; /**< total number of inequalities for underestimating xy */
207  int nineqoverest; /**< total number of inequalities for overestimating xy */
208  int nunderest; /**< number of constraints that require to underestimate xy */
209  int noverest; /**< number of constraints that require to overestimate xy */
211  SCIP_Real lastimprfac; /**< last achieved improvement factor */
212 };
213 typedef struct BilinearEstimator BILINESTIMATOR;
215 /** constraint handler data */
216 struct SCIP_ConshdlrData
217 {
218  int replacebinaryprodlength; /**< length of linear term which when multiplied with a binary variable is replaced by an auxiliary variable and an equivalent linear formulation */
219  int empathy4and; /**< how much empathy we have for using the AND constraint handler: 0 avoid always; 1 use sometimes; 2 use as often as possible */
220  SCIP_Bool binreforminitial; /**< whether to make constraints added due to replacing products with binary variables initial */
221  SCIP_Bool binreformbinaryonly;/**< whether to consider only binary variables when reformulating products with binary variables */
222  SCIP_Real binreformmaxcoef; /**< factor on 1/feastol to limit coefficients and coef range in linear constraints created by binary reformulation */
223  SCIP_Real cutmaxrange; /**< maximal range (maximal coef / minimal coef) of a cut in order to be added to LP */
224  SCIP_Bool linearizeheursol; /**< whether linearizations of convex quadratic constraints should be added to cutpool when some heuristics finds a new solution */
225  SCIP_Bool checkcurvature; /**< whether functions should be checked for convexity/concavity */
226  SCIP_Bool checkfactorable; /**< whether functions should be checked to be factorable */
227  char checkquadvarlocks; /**< whether quadratic variables contained in a single constraint should be forced to be at their lower or upper bounds ('d'isable, change 't'ype, add 'b'ound disjunction) */
228  SCIP_Bool linfeasshift; /**< whether to make solutions in check feasible if possible */
229  int maxdisaggrsize; /**< maximum number of components when disaggregating a quadratic constraint (<= 1: off) */
230  char disaggrmergemethod; /**< method on merging blocks in disaggregation */
231  int maxproprounds; /**< limit on number of propagation rounds for a single constraint within one round of SCIP propagation during solve */
232  int maxproproundspresolve; /**< limit on number of propagation rounds for a single constraint within one presolving round */
233  SCIP_Real sepanlpmincont; /**< minimal required fraction of continuous variables in problem to use solution of NLP relaxation in root for separation */
234  SCIP_Bool enfocutsremovable; /**< are cuts added during enforcement removable from the LP in the same node? */
235  SCIP_Bool gaugecuts; /**< should convex quadratics generated strong cuts via gauge function? */
236  SCIP_Bool projectedcuts; /**< should convex quadratics generated strong cuts via projections? */
237  char interiorcomputation;/**< how the interior point should be computed: 'a'ny point per constraint, 'm'ost interior per constraint */
238  char branchscoring; /**< method to use to compute score of branching candidates */
239  int enfolplimit; /**< maximum number of enforcement round before declaring the LP relaxation
240  * infeasible (-1: no limit); WARNING: if this parameter is not set to -1,
241  * SCIP might declare sub-optimal solutions optimal or feasible instances
242  * infeasible; thus, the result returned by SCIP might be incorrect!
243  */
244  SCIP_HEUR* subnlpheur; /**< a pointer to the subnlp heuristic, if available */
245  SCIP_HEUR* trysolheur; /**< a pointer to the trysol heuristic, if available */
246  SCIP_EVENTHDLR* eventhdlr; /**< our handler for variable bound change events */
247  int newsoleventfilterpos; /**< filter position of new solution event handler, if caught */
248  SCIP_Bool sepanlp; /**< where linearization of the NLP relaxation solution added? */
249  SCIP_NODE* lastenfonode; /**< the node for which enforcement was called the last time (and some constraint was violated) */
250  int nenforounds; /**< counter on number of enforcement rounds for the current node */
251  SCIP_QUADCONSUPGRADE** quadconsupgrades; /**< quadratic constraint upgrade methods for specializing quadratic constraints */
252  int quadconsupgradessize; /**< size of quadconsupgrade array */
253  int nquadconsupgrades; /**< number of quadratic constraint upgrade methods */
254 
255  BILINESTIMATOR* bilinestimators; /**< array containing all required information for using stronger estimators for each bilinear term in all quadratic constraints */
256  int nbilinterms; /**< number of bilinear terms in all quadratic constraints */
257 
258  SCIP_Bool usebilinineqbranch; /**< should linear inequalities be considered when computing the branching scores for bilinear terms? */
259  SCIP_Bool storedbilinearterms; /**< did we already try to store all bilinear terms? */
260 
261  SCIP_Real minscorebilinterms; /**< minimal required score in order to use linear inequalities for tighter bilinear relaxations */
262  SCIP_Real mincurvcollectbilinterms;/**< minimal curvature of constraints to be considered when returning bilinear terms to other plugins */
263  int bilinineqmaxseparounds; /**< maximum number of separation rounds to use linear inequalities for the bilinear term relaxation in a local node */
264 };
265 
266 
267 /*
268  * local methods for managing quadratic constraint update methods
269  */
270 
271 
272 /** checks whether a quadratic constraint upgrade method has already be registered */
273 static
275  SCIP* scip, /**< SCIP data structure */
276  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
277  SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), /**< method to call for upgrading quadratic constraint */
278  const char* conshdlrname /**< name of the constraint handler */
279  )
280 {
281  int i;
282 
283  assert(scip != NULL);
284  assert(conshdlrdata != NULL);
285  assert(quadconsupgd != NULL);
286  assert(conshdlrname != NULL);
287 
288  for( i = conshdlrdata->nquadconsupgrades - 1; i >= 0; --i )
289  {
290  if( conshdlrdata->quadconsupgrades[i]->quadconsupgd == quadconsupgd )
291  {
292  SCIPwarningMessage(scip, "Try to add already known upgrade message for constraint handler <%s>.\n", conshdlrname);
293  return TRUE;
294  }
295  }
296 
297  return FALSE;
298 }
299 
300 /*
301  * Local methods
302  */
303 
304 /** translate from one value of infinity to another
305  *
306  * if val is >= infty1, then give infty2, else give val
307  */
308 #define infty2infty(infty1, infty2, val) ((val) >= (infty1) ? (infty2) : (val))
310 /** catches variable bound change events on a linear variable in a quadratic constraint */
311 static
313  SCIP* scip, /**< SCIP data structure */
314  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
315  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
316  int linvarpos /**< position of variable in linear variables array */
317  )
318 {
319  SCIP_CONSDATA* consdata;
320  SCIP_QUADVAREVENTDATA* eventdata;
321  SCIP_EVENTTYPE eventtype;
322 
323  assert(scip != NULL);
324  assert(eventhdlr != NULL);
325  assert(cons != NULL);
326 
327  consdata = SCIPconsGetData(cons);
328  assert(consdata != NULL);
329 
330  assert(linvarpos >= 0);
331  assert(linvarpos < consdata->nlinvars);
332  assert(consdata->lineventdata != NULL);
333 
334  SCIP_CALL( SCIPallocBlockMemory(scip, &eventdata) );
335 
336  eventdata->cons = cons;
337  eventdata->varidx = linvarpos;
338 
340  if( !SCIPisInfinity(scip, consdata->rhs) )
341  {
342  /* if right hand side is finite, then a tightening in the lower bound of coef*linvar is of interest
343  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
344  if( consdata->lincoefs[linvarpos] > 0.0 )
345  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
346  else
347  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
348  }
349  if( !SCIPisInfinity(scip, -consdata->lhs) )
350  {
351  /* if left hand side is finite, then a tightening in the upper bound of coef*linvar is of interest
352  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
353  if( consdata->lincoefs[linvarpos] > 0.0 )
354  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
355  else
356  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
357  }
358 
359  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->linvars[linvarpos], eventtype, eventhdlr, (SCIP_EVENTDATA*)eventdata, &eventdata->filterpos) );
360 
361  consdata->lineventdata[linvarpos] = eventdata;
362 
363  /* invalidate activity information
364  * NOTE: It could happen that a constraint gets temporary deactivated and some variable bounds change. In this case
365  * we do not recognize those bound changes with the variable events and thus we have to recompute the activities.
366  */
367  consdata->minlinactivity = SCIP_INVALID;
368  consdata->maxlinactivity = SCIP_INVALID;
369  consdata->minlinactivityinf = -1;
370  consdata->maxlinactivityinf = -1;
371 
372  return SCIP_OKAY;
373 }
374 
375 /** drops variable bound change events on a linear variable in a quadratic constraint */
376 static
378  SCIP* scip, /**< SCIP data structure */
379  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
380  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
381  int linvarpos /**< position of variable in linear variables array */
382  )
383 {
384  SCIP_CONSDATA* consdata;
385  SCIP_EVENTTYPE eventtype;
386 
387  assert(scip != NULL);
388  assert(eventhdlr != NULL);
389  assert(cons != NULL);
390 
391  consdata = SCIPconsGetData(cons);
392  assert(consdata != NULL);
393 
394  assert(linvarpos >= 0);
395  assert(linvarpos < consdata->nlinvars);
396  assert(consdata->lineventdata != NULL);
397  assert(consdata->lineventdata[linvarpos] != NULL);
398  assert(consdata->lineventdata[linvarpos]->cons == cons);
399  assert(consdata->lineventdata[linvarpos]->varidx == linvarpos);
400  assert(consdata->lineventdata[linvarpos]->filterpos >= 0);
401 
403  if( !SCIPisInfinity(scip, consdata->rhs) )
404  {
405  /* if right hand side is finite, then a tightening in the lower bound of coef*linvar is of interest
406  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
407  if( consdata->lincoefs[linvarpos] > 0.0 )
408  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
409  else
410  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
411  }
412  if( !SCIPisInfinity(scip, -consdata->lhs) )
413  {
414  /* if left hand side is finite, then a tightening in the upper bound of coef*linvar is of interest
415  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
416  if( consdata->lincoefs[linvarpos] > 0.0 )
417  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
418  else
419  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
420  }
421 
422  SCIP_CALL( SCIPdropVarEvent(scip, consdata->linvars[linvarpos], eventtype, eventhdlr, (SCIP_EVENTDATA*)consdata->lineventdata[linvarpos], consdata->lineventdata[linvarpos]->filterpos) );
423 
424  SCIPfreeBlockMemory(scip, &consdata->lineventdata[linvarpos]); /*lint !e866 */
425 
426  return SCIP_OKAY;
427 }
428 
429 /** catches variable bound change events on a quadratic variable in a quadratic constraint */
430 static
432  SCIP* scip, /**< SCIP data structure */
433  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
434  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
435  int quadvarpos /**< position of variable in quadratic variables array */
436  )
437 {
438  SCIP_CONSDATA* consdata;
439  SCIP_QUADVAREVENTDATA* eventdata;
440  SCIP_EVENTTYPE eventtype;
441 
442  assert(scip != NULL);
443  assert(eventhdlr != NULL);
444  assert(cons != NULL);
445 
446  consdata = SCIPconsGetData(cons);
447  assert(consdata != NULL);
448 
449  assert(quadvarpos >= 0);
450  assert(quadvarpos < consdata->nquadvars);
451  assert(consdata->quadvarterms[quadvarpos].eventdata == NULL);
452 
453  SCIP_CALL( SCIPallocBlockMemory(scip, &eventdata) );
454 
456 #ifdef CHECKIMPLINBILINEAR
457  eventtype |= SCIP_EVENTTYPE_IMPLADDED;
458 #endif
459  eventdata->cons = cons;
460  eventdata->varidx = -quadvarpos-1;
461  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->quadvarterms[quadvarpos].var, eventtype, eventhdlr, (SCIP_EVENTDATA*)eventdata, &eventdata->filterpos) );
462 
463  consdata->quadvarterms[quadvarpos].eventdata = eventdata;
464 
465  /* invalidate activity information
466  * NOTE: It could happen that a constraint gets temporary deactivated and some variable bounds change. In this case
467  * we do not recognize those bound changes with the variable events and thus we have to recompute the activities.
468  */
469  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
470 
471  return SCIP_OKAY;
472 }
473 
474 /** catches variable bound change events on a quadratic variable in a quadratic constraint */
475 static
477  SCIP* scip, /**< SCIP data structure */
478  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
479  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
480  int quadvarpos /**< position of variable in quadratic variables array */
481  )
482 {
483  SCIP_CONSDATA* consdata;
484  SCIP_EVENTTYPE eventtype;
485 
486  assert(scip != NULL);
487  assert(eventhdlr != NULL);
488  assert(cons != NULL);
489 
490  consdata = SCIPconsGetData(cons);
491  assert(consdata != NULL);
492 
493  assert(quadvarpos >= 0);
494  assert(quadvarpos < consdata->nquadvars);
495  assert(consdata->quadvarterms[quadvarpos].eventdata != NULL);
496  assert(consdata->quadvarterms[quadvarpos].eventdata->cons == cons);
497  assert(consdata->quadvarterms[quadvarpos].eventdata->varidx == -quadvarpos-1);
498  assert(consdata->quadvarterms[quadvarpos].eventdata->filterpos >= 0);
499 
501 #ifdef CHECKIMPLINBILINEAR
502  eventtype |= SCIP_EVENTTYPE_IMPLADDED;
503 #endif
504 
505  SCIP_CALL( SCIPdropVarEvent(scip, consdata->quadvarterms[quadvarpos].var, eventtype, eventhdlr, (SCIP_EVENTDATA*)consdata->quadvarterms[quadvarpos].eventdata, consdata->quadvarterms[quadvarpos].eventdata->filterpos) );
506 
507  SCIPfreeBlockMemory(scip, &consdata->quadvarterms[quadvarpos].eventdata);
508 
509  return SCIP_OKAY;
510 }
511 
512 /** catch variable events */
513 static
515  SCIP* scip, /**< SCIP data structure */
516  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
517  SCIP_CONS* cons /**< constraint for which to catch bound change events */
518  )
519 {
520  SCIP_CONSDATA* consdata;
521  SCIP_VAR* var;
522  int i;
523 
524  assert(scip != NULL);
525  assert(cons != NULL);
526  assert(eventhdlr != NULL);
527 
528  consdata = SCIPconsGetData(cons);
529  assert(consdata != NULL);
530  assert(consdata->lineventdata == NULL);
531 
532  /* we will update isremovedfixings, so reset it to TRUE first */
533  consdata->isremovedfixings = TRUE;
534 
535  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize) );
536  for( i = 0; i < consdata->nlinvars; ++i )
537  {
538  SCIP_CALL( catchLinearVarEvents(scip, eventhdlr, cons, i) );
539 
540  var = consdata->linvars[i];
541  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var)
542  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
543  }
544 
545  for( i = 0; i < consdata->nquadvars; ++i )
546  {
547  assert(consdata->quadvarterms[i].eventdata == NULL);
548 
549  SCIP_CALL( catchQuadVarEvents(scip, eventhdlr, cons, i) );
550 
551  var = consdata->quadvarterms[i].var;
552  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var)
553  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
554  }
555 
556  consdata->ispropagated = FALSE;
557 
558  return SCIP_OKAY;
559 }
560 
561 /** drop variable events */
562 static
564  SCIP* scip, /**< SCIP data structure */
565  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
566  SCIP_CONS* cons /**< constraint for which to drop bound change events */
567  )
568 {
569  SCIP_CONSDATA* consdata;
570  int i;
571 
572  assert(scip != NULL);
573  assert(eventhdlr != NULL);
574  assert(cons != NULL);
575 
576  consdata = SCIPconsGetData(cons);
577  assert(consdata != NULL);
578 
579  if( consdata->lineventdata != NULL )
580  {
581  for( i = 0; i < consdata->nlinvars; ++i )
582  {
583  if( consdata->lineventdata[i] != NULL )
584  {
585  SCIP_CALL( dropLinearVarEvents(scip, eventhdlr, cons, i) );
586  }
587  }
588  SCIPfreeBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize);
589  }
590 
591  for( i = 0; i < consdata->nquadvars; ++i )
592  {
593  if( consdata->quadvarterms[i].eventdata != NULL )
594  {
595  SCIP_CALL( dropQuadVarEvents(scip, eventhdlr, cons, i) );
596  }
597  }
598 
599  return SCIP_OKAY;
600 }
601 
602 /** locks a linear variable in a constraint */
603 static
605  SCIP* scip, /**< SCIP data structure */
606  SCIP_CONS* cons, /**< constraint where to lock a variable */
607  SCIP_VAR* var, /**< variable to lock */
608  SCIP_Real coef /**< coefficient of variable in constraint */
609  )
610 {
611  SCIP_CONSDATA* consdata;
612 
613  assert(scip != NULL);
614  assert(cons != NULL);
615  assert(var != NULL);
616  assert(coef != 0.0);
617 
618  consdata = SCIPconsGetData(cons);
619  assert(consdata != NULL);
620 
621  if( coef > 0.0 )
622  {
623  SCIP_CALL( SCIPlockVarCons(scip, var, cons, !SCIPisInfinity(scip, -consdata->lhs), !SCIPisInfinity(scip, consdata->rhs)) );
624  }
625  else
626  {
627  SCIP_CALL( SCIPlockVarCons(scip, var, cons, !SCIPisInfinity(scip, consdata->rhs), !SCIPisInfinity(scip, -consdata->lhs)) );
628  }
629 
630  return SCIP_OKAY;
631 }
632 
633 /** unlocks a linear variable in a constraint */
634 static
636  SCIP* scip, /**< SCIP data structure */
637  SCIP_CONS* cons, /**< constraint where to unlock a variable */
638  SCIP_VAR* var, /**< variable to unlock */
639  SCIP_Real coef /**< coefficient of variable in constraint */
640  )
641 {
642  SCIP_CONSDATA* consdata;
643 
644  assert(scip != NULL);
645  assert(cons != NULL);
646  assert(var != NULL);
647  assert(coef != 0.0);
648 
649  consdata = SCIPconsGetData(cons);
650  assert(consdata != NULL);
651 
652  if( coef > 0.0 )
653  {
654  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, !SCIPisInfinity(scip, -consdata->lhs), !SCIPisInfinity(scip, consdata->rhs)) );
655  }
656  else
657  {
658  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, !SCIPisInfinity(scip, consdata->rhs), !SCIPisInfinity(scip, -consdata->lhs)) );
659  }
660 
661  return SCIP_OKAY;
662 }
663 
664 /** locks a quadratic variable in a constraint */
665 static
667  SCIP* scip, /**< SCIP data structure */
668  SCIP_CONS* cons, /**< constraint where to lock a variable */
669  SCIP_VAR* var /**< variable to lock */
670  )
671 {
672  SCIP_CALL( SCIPlockVarCons(scip, var, cons, TRUE, TRUE) );
673 
674  return SCIP_OKAY;
675 }
676 
677 /** unlocks a quadratic variable in a constraint */
678 static
680  SCIP* scip, /**< SCIP data structure */
681  SCIP_CONS* cons, /**< constraint where to unlock a variable */
682  SCIP_VAR* var /**< variable to unlock */
683  )
684 {
685  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, TRUE) );
686 
687  return SCIP_OKAY;
688 }
689 
690 /** computes the minimal and maximal activity for the linear part in a constraint data
691  *
692  * Only sums up terms that contribute finite values.
693  * Gives the number of terms that contribute infinite values.
694  * Only computes those activities where the corresponding side of the constraint is finite.
695  */
696 static
698  SCIP* scip, /**< SCIP data structure */
699  SCIP_CONSDATA* consdata, /**< constraint data */
700  SCIP_Real intervalinfty /**< infinity value used in interval operations */
701  )
702 { /*lint --e{666}*/
703  SCIP_ROUNDMODE prevroundmode;
704  int i;
705  SCIP_Real bnd;
706 
707  assert(scip != NULL);
708  assert(consdata != NULL);
709 
710  /* if variable bounds are not strictly consistent, then the activity update methods may yield inconsistent activities
711  * in this case, we also recompute the activities
712  */
713  if( consdata->minlinactivity != SCIP_INVALID && consdata->maxlinactivity != SCIP_INVALID && /*lint !e777 */
714  (consdata->minlinactivityinf > 0 || consdata->maxlinactivityinf > 0 || consdata->minlinactivity <= consdata->maxlinactivity) )
715  {
716  /* activities should be up-to-date */
717  assert(consdata->minlinactivityinf >= 0);
718  assert(consdata->maxlinactivityinf >= 0);
719  return;
720  }
721 
722  consdata->minlinactivityinf = 0;
723  consdata->maxlinactivityinf = 0;
724 
725  /* if lhs is -infinite, then we do not compute a maximal activity, so we set it to infinity
726  * if rhs is infinite, then we do not compute a minimal activity, so we set it to -infinity
727  */
728  consdata->minlinactivity = SCIPisInfinity(scip, consdata->rhs) ? -intervalinfty : 0.0;
729  consdata->maxlinactivity = SCIPisInfinity(scip, -consdata->lhs) ? intervalinfty : 0.0;
730 
731  if( consdata->nlinvars == 0 )
732  return;
733 
734  /* if the activities computed here should be still up-to-date after bound changes,
735  * variable events need to be caught */
736  assert(consdata->lineventdata != NULL);
737 
738  prevroundmode = SCIPintervalGetRoundingMode();
739 
740  if( !SCIPisInfinity(scip, consdata->rhs) )
741  {
742  /* compute minimal activity only if there is a finite right hand side */
744 
745  for( i = 0; i < consdata->nlinvars; ++i )
746  {
747  assert(consdata->lineventdata[i] != NULL);
748  if( consdata->lincoefs[i] >= 0.0 )
749  {
750  bnd = MIN(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
751  if( SCIPisInfinity(scip, -bnd) )
752  {
753  ++consdata->minlinactivityinf;
754  continue;
755  }
756  assert(!SCIPisInfinity(scip, bnd)); /* do not like variables that are fixed at +infinity */
757  }
758  else
759  {
760  bnd = MAX(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
761  if( SCIPisInfinity(scip, bnd) )
762  {
763  ++consdata->minlinactivityinf;
764  continue;
765  }
766  assert(!SCIPisInfinity(scip, -bnd)); /* do not like variables that are fixed at -infinity */
767  }
768  consdata->minlinactivity += consdata->lincoefs[i] * bnd;
769  }
770  }
771 
772  if( !SCIPisInfinity(scip, -consdata->lhs) )
773  {
774  /* compute maximal activity only if there is a finite left hand side */
776 
777  for( i = 0; i < consdata->nlinvars; ++i )
778  {
779  assert(consdata->lineventdata[i] != NULL);
780  if( consdata->lincoefs[i] >= 0.0 )
781  {
782  bnd = MAX(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
783  if( SCIPisInfinity(scip, bnd) )
784  {
785  ++consdata->maxlinactivityinf;
786  continue;
787  }
788  assert(!SCIPisInfinity(scip, -bnd)); /* do not like variables that are fixed at -infinity */
789  }
790  else
791  {
792  bnd = MIN(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
793  if( SCIPisInfinity(scip, -bnd) )
794  {
795  ++consdata->maxlinactivityinf;
796  continue;
797  }
798  assert(!SCIPisInfinity(scip, bnd)); /* do not like variables that are fixed at +infinity */
799  }
800  consdata->maxlinactivity += consdata->lincoefs[i] * bnd;
801  }
802  }
803 
804  SCIPintervalSetRoundingMode(prevroundmode);
805 
806  assert(consdata->minlinactivityinf > 0 || consdata->maxlinactivityinf > 0 || consdata->minlinactivity <= consdata->maxlinactivity);
807 }
808 
809 /** update the linear activities after a change in the lower bound of a variable */
810 static
812  SCIP* scip, /**< SCIP data structure */
813  SCIP_CONSDATA* consdata, /**< constraint data */
814  SCIP_Real coef, /**< coefficient of variable in constraint */
815  SCIP_Real oldbnd, /**< previous lower bound of variable */
816  SCIP_Real newbnd /**< new lower bound of variable */
817  )
818 {
819  SCIP_ROUNDMODE prevroundmode;
820 
821  assert(scip != NULL);
822  assert(consdata != NULL);
823  /* we can't deal with lower bounds at infinity */
824  assert(!SCIPisInfinity(scip, oldbnd));
825  assert(!SCIPisInfinity(scip, newbnd));
826 
827  /* @todo since we check the linear activity for consistency later anyway, we may skip changing the rounding mode here */
828 
829  /* assume lhs <= a*x + y <= rhs, then the following bound changes can be deduced:
830  * a > 0: y <= rhs - a*lb(x), y >= lhs - a*ub(x)
831  * a < 0: y <= rhs - a*ub(x), y >= lhs - a*lb(x)
832  */
833 
834  if( coef > 0.0 )
835  {
836  /* we should only be called if rhs is finite */
837  assert(!SCIPisInfinity(scip, consdata->rhs));
838 
839  /* we have no min activities computed so far, so cannot update */
840  if( consdata->minlinactivity == SCIP_INVALID ) /*lint !e777 */
841  return;
842 
843  prevroundmode = SCIPintervalGetRoundingMode();
845 
846  /* update min activity */
847  if( SCIPisInfinity(scip, -oldbnd) )
848  {
849  --consdata->minlinactivityinf;
850  assert(consdata->minlinactivityinf >= 0);
851  }
852  else
853  {
854  SCIP_Real minuscoef;
855  minuscoef = -coef;
856  consdata->minlinactivity += minuscoef * oldbnd;
857  }
858 
859  if( SCIPisInfinity(scip, -newbnd) )
860  {
861  ++consdata->minlinactivityinf;
862  }
863  else
864  {
865  consdata->minlinactivity += coef * newbnd;
866  }
867 
868  SCIPintervalSetRoundingMode(prevroundmode);
869  }
870  else
871  {
872  /* we should only be called if lhs is finite */
873  assert(!SCIPisInfinity(scip, -consdata->lhs));
874 
875  /* we have no max activities computed so far, so cannot update */
876  if( consdata->maxlinactivity == SCIP_INVALID ) /*lint !e777 */
877  return;
878 
879  prevroundmode = SCIPintervalGetRoundingMode();
881 
882  /* update max activity */
883  if( SCIPisInfinity(scip, -oldbnd) )
884  {
885  --consdata->maxlinactivityinf;
886  assert(consdata->maxlinactivityinf >= 0);
887  }
888  else
889  {
890  SCIP_Real minuscoef;
891  minuscoef = -coef;
892  consdata->maxlinactivity += minuscoef * oldbnd;
893  }
894 
895  if( SCIPisInfinity(scip, -newbnd) )
896  {
897  ++consdata->maxlinactivityinf;
898  }
899  else
900  {
901  consdata->maxlinactivity += coef * newbnd;
902  }
903 
904  SCIPintervalSetRoundingMode(prevroundmode);
905  }
906 }
907 
908 /** update the linear activities after a change in the upper bound of a variable */
909 static
911  SCIP* scip, /**< SCIP data structure */
912  SCIP_CONSDATA* consdata, /**< constraint data */
913  SCIP_Real coef, /**< coefficient of variable in constraint */
914  SCIP_Real oldbnd, /**< previous lower bound of variable */
915  SCIP_Real newbnd /**< new lower bound of variable */
916  )
917 {
918  SCIP_ROUNDMODE prevroundmode;
919 
920  assert(scip != NULL);
921  assert(consdata != NULL);
922  /* we can't deal with upper bounds at -infinity */
923  assert(!SCIPisInfinity(scip, -oldbnd));
924  assert(!SCIPisInfinity(scip, -newbnd));
925 
926  /* @todo since we check the linear activity for consistency later anyway, we may skip changing the rounding mode here */
927 
928  /* assume lhs <= a*x + y <= rhs, then the following bound changes can be deduced:
929  * a > 0: y <= rhs - a*lb(x), y >= lhs - a*ub(x)
930  * a < 0: y <= rhs - a*ub(x), y >= lhs - a*lb(x)
931  */
932 
933  if( coef > 0.0 )
934  {
935  /* we should only be called if lhs is finite */
936  assert(!SCIPisInfinity(scip, -consdata->lhs));
937 
938  /* we have no max activities computed so far, so cannot update */
939  if( consdata->maxlinactivity == SCIP_INVALID ) /*lint !e777 */
940  return;
941 
942  prevroundmode = SCIPintervalGetRoundingMode();
944 
945  /* update max activity */
946  if( SCIPisInfinity(scip, oldbnd) )
947  {
948  --consdata->maxlinactivityinf;
949  assert(consdata->maxlinactivityinf >= 0);
950  }
951  else
952  {
953  SCIP_Real minuscoef;
954  minuscoef = -coef;
955  consdata->maxlinactivity += minuscoef * oldbnd;
956  }
957 
958  if( SCIPisInfinity(scip, newbnd) )
959  {
960  ++consdata->maxlinactivityinf;
961  }
962  else
963  {
964  consdata->maxlinactivity += coef * newbnd;
965  }
966 
967  SCIPintervalSetRoundingMode(prevroundmode);
968  }
969  else
970  {
971  /* we should only be called if rhs is finite */
972  assert(!SCIPisInfinity(scip, consdata->rhs));
973 
974  /* we have no min activities computed so far, so cannot update */
975  if( consdata->minlinactivity == SCIP_INVALID ) /*lint !e777 */
976  return;
977 
978  prevroundmode = SCIPintervalGetRoundingMode();
980 
981  /* update min activity */
982  if( SCIPisInfinity(scip, oldbnd) )
983  {
984  --consdata->minlinactivityinf;
985  assert(consdata->minlinactivityinf >= 0);
986  }
987  else
988  {
989  SCIP_Real minuscoef;
990  minuscoef = -coef;
991  consdata->minlinactivity += minuscoef * oldbnd;
992  }
993 
994  if( SCIPisInfinity(scip, newbnd) )
995  {
996  ++consdata->minlinactivityinf;
997  }
998  else
999  {
1000  consdata->minlinactivity += coef * newbnd;
1001  }
1002 
1003  SCIPintervalSetRoundingMode(prevroundmode);
1004  }
1005 }
1006 
1007 /** returns whether a quadratic variable domain can be reduced to its lower or upper bound; this is the case if the
1008  * quadratic variable is in just one single quadratic constraint and (sqrcoef > 0 and LHS = -infinity), or
1009  * (sqrcoef < 0 and RHS = +infinity) hold
1010  */
1011 static
1013  SCIP* scip, /**< SCIP data structure */
1014  SCIP_CONSDATA* consdata, /**< constraint data */
1015  int idx /**< index of quadratic variable */
1016  )
1017 {
1018  SCIP_VAR* var;
1019  SCIP_Real quadcoef;
1020  SCIP_Bool haslhs;
1021  SCIP_Bool hasrhs;
1022 
1023  assert(scip != NULL);
1024  assert(consdata != NULL);
1025  assert(idx >= 0 && idx < consdata->nquadvars);
1026 
1027  var = consdata->quadvarterms[idx].var;
1028  assert(var != NULL);
1029 
1030  quadcoef = consdata->quadvarterms[idx].sqrcoef;
1031  haslhs = !SCIPisInfinity(scip, -consdata->lhs);
1032  hasrhs = !SCIPisInfinity(scip, consdata->rhs);
1033 
1034  return SCIPvarGetNLocksDown(var) == 1 && SCIPvarGetNLocksUp(var) == 1 && SCIPisZero(scip, SCIPvarGetObj(var))
1035  && SCIPvarGetType(var) != SCIP_VARTYPE_BINARY && ((quadcoef < 0.0 && !haslhs) || (quadcoef > 0.0 && !hasrhs));
1036 }
1037 
1038 /** processes variable fixing or bound change event */
1039 static
1040 SCIP_DECL_EVENTEXEC(processVarEvent)
1042  SCIP_CONS* cons;
1043  SCIP_CONSDATA* consdata;
1044  SCIP_EVENTTYPE eventtype;
1045  int varidx;
1046 
1047  assert(scip != NULL);
1048  assert(event != NULL);
1049  assert(eventdata != NULL);
1050  assert(eventhdlr != NULL);
1051 
1052  cons = ((SCIP_QUADVAREVENTDATA*)eventdata)->cons;
1053  assert(cons != NULL);
1054  consdata = SCIPconsGetData(cons);
1055  assert(consdata != NULL);
1056 
1057  varidx = ((SCIP_QUADVAREVENTDATA*)eventdata)->varidx;
1058  assert(varidx < 0 || varidx < consdata->nlinvars);
1059  assert(varidx >= 0 || -varidx-1 < consdata->nquadvars);
1060 
1061  eventtype = SCIPeventGetType(event);
1062 
1063  /* process local bound changes */
1064  if( eventtype & SCIP_EVENTTYPE_BOUNDCHANGED )
1065  {
1066  if( varidx < 0 )
1067  {
1068  /* mark activity bounds for quad term as not up to date anymore */
1069  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
1070  }
1071  else
1072  {
1073  /* update activity bounds for linear terms */
1074  if( eventtype & SCIP_EVENTTYPE_LBCHANGED )
1075  consdataUpdateLinearActivityLbChange(scip, consdata, consdata->lincoefs[varidx], SCIPeventGetOldbound(event), SCIPeventGetNewbound(event));
1076  else
1077  consdataUpdateLinearActivityUbChange(scip, consdata, consdata->lincoefs[varidx], SCIPeventGetOldbound(event), SCIPeventGetNewbound(event));
1078  }
1079 
1080  if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
1081  {
1082  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
1083  consdata->ispropagated = FALSE;
1084  }
1085  }
1086 
1087  /* process global bound changes */
1088  if( eventtype & SCIP_EVENTTYPE_GBDCHANGED )
1089  {
1090  SCIP_VAR* var;
1091 
1092  var = varidx < 0 ? consdata->quadvarterms[-varidx-1].var : consdata->linvars[varidx];
1093  assert(var != NULL);
1094 
1095  if( varidx < 0 )
1096  {
1097  SCIP_QUADVARTERM* quadvarterm;
1098 
1099  quadvarterm = &consdata->quadvarterms[-varidx-1];
1100 
1101  /* if an integer variable x with a x^2 is tightened to [0,1], then we can replace the x^2 by x, which is done in mergeAndCleanQuadVarTerms()
1102  * we currently do this only if the binary variable does not show up in any bilinear terms
1103  */
1105  quadvarterm->sqrcoef != 0.0 && quadvarterm->nadjbilin == 0 )
1106  {
1107  consdata->quadvarsmerged = FALSE;
1108  consdata->initialmerge = FALSE;
1109  }
1110  }
1111 
1112  if( SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
1113  consdata->isremovedfixings = FALSE;
1114  }
1115 
1116  /* process variable fixing event */
1117  if( eventtype & SCIP_EVENTTYPE_VARFIXED )
1118  {
1119  consdata->isremovedfixings = FALSE;
1120  }
1121 
1122 #ifdef CHECKIMPLINBILINEAR
1123  if( eventtype & SCIP_EVENTTYPE_IMPLADDED )
1124  {
1125  assert(varidx < 0); /* we catch impladded events only for quadratic variables */
1126  /* if variable is binary (quite likely if an implication has been added) and occurs in a bilinear term, then mark that we should check implications */
1127  if( SCIPvarIsBinary(SCIPeventGetVar(event)) && consdata->quadvarterms[-varidx-1].nadjbilin > 0 )
1128  consdata->isimpladded = TRUE;
1129  }
1130 #endif
1131 
1132  return SCIP_OKAY;
1133 }
1134 
1135 /** ensures, that linear vars and coefs arrays can store at least num entries */
1136 static
1138  SCIP* scip, /**< SCIP data structure */
1139  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1140  int num /**< minimum number of entries to store */
1141  )
1142 {
1143  assert(scip != NULL);
1144  assert(consdata != NULL);
1145  assert(consdata->nlinvars <= consdata->linvarssize);
1146 
1147  if( num > consdata->linvarssize )
1148  {
1149  int newsize;
1150 
1151  newsize = SCIPcalcMemGrowSize(scip, num);
1152  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->linvars, consdata->linvarssize, newsize) );
1153  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->lincoefs, consdata->linvarssize, newsize) );
1154  if( consdata->lineventdata != NULL )
1155  {
1156  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize, newsize) );
1157  }
1158  consdata->linvarssize = newsize;
1159  }
1160  assert(num <= consdata->linvarssize);
1161 
1162  return SCIP_OKAY;
1163 }
1164 
1165 /** ensures, that quadratic variable terms array can store at least num entries */
1166 static
1168  SCIP* scip, /**< SCIP data structure */
1169  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1170  int num /**< minimum number of entries to store */
1171  )
1172 {
1173  assert(scip != NULL);
1174  assert(consdata != NULL);
1175  assert(consdata->nquadvars <= consdata->quadvarssize);
1176 
1177  if( num > consdata->quadvarssize )
1178  {
1179  int newsize;
1180 
1181  newsize = SCIPcalcMemGrowSize(scip, num);
1182  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->quadvarterms, consdata->quadvarssize, newsize) );
1183  consdata->quadvarssize = newsize;
1184  }
1185  assert(num <= consdata->quadvarssize);
1186 
1187  return SCIP_OKAY;
1188 }
1189 
1190 /** ensures, that adjacency array can store at least num entries */
1191 static
1193  SCIP* scip, /**< SCIP data structure */
1194  SCIP_QUADVARTERM* quadvarterm, /**< quadratic variable term */
1195  int num /**< minimum number of entries to store */
1196  )
1197 {
1198  assert(scip != NULL);
1199  assert(quadvarterm != NULL);
1200  assert(quadvarterm->nadjbilin <= quadvarterm->adjbilinsize);
1201 
1202  if( num > quadvarterm->adjbilinsize )
1203  {
1204  int newsize;
1205 
1206  newsize = SCIPcalcMemGrowSize(scip, num);
1207  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &quadvarterm->adjbilin, quadvarterm->adjbilinsize, newsize) );
1208  quadvarterm->adjbilinsize = newsize;
1209  }
1210  assert(num <= quadvarterm->adjbilinsize);
1211 
1212  return SCIP_OKAY;
1213 }
1214 
1215 /** ensures, that bilinear term arrays can store at least num entries */
1216 static
1218  SCIP* scip, /**< SCIP data structure */
1219  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1220  int num /**< minimum number of entries to store */
1221  )
1222 {
1223  assert(scip != NULL);
1224  assert(consdata != NULL);
1225  assert(consdata->nbilinterms <= consdata->bilintermssize);
1226 
1227  if( num > consdata->bilintermssize )
1228  {
1229  int newsize;
1230 
1231  newsize = SCIPcalcMemGrowSize(scip, num);
1232  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->bilinterms, consdata->bilintermssize, newsize) );
1233  consdata->bilintermssize = newsize;
1234  }
1235  assert(num <= consdata->bilintermssize);
1236 
1237  return SCIP_OKAY;
1238 }
1239 
1240 /** creates empty constraint data structure */
1241 static
1243  SCIP* scip, /**< SCIP data structure */
1244  SCIP_CONSDATA** consdata /**< a buffer to store pointer to new constraint data */
1245  )
1246 {
1247  assert(scip != NULL);
1248  assert(consdata != NULL);
1249 
1250  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1251  BMSclearMemory(*consdata);
1252 
1253  (*consdata)->lhs = -SCIPinfinity(scip);
1254  (*consdata)->rhs = SCIPinfinity(scip);
1255 
1256  (*consdata)->linvarssorted = TRUE;
1257  (*consdata)->linvarsmerged = TRUE;
1258  (*consdata)->quadvarssorted = TRUE;
1259  (*consdata)->quadvarsmerged = TRUE;
1260  (*consdata)->bilinsorted = TRUE;
1261  (*consdata)->bilinmerged = TRUE;
1262 
1263  (*consdata)->isremovedfixings = TRUE;
1264  (*consdata)->ispropagated = TRUE;
1265  (*consdata)->initialmerge = FALSE;
1266 
1267  (*consdata)->linvar_maydecrease = -1;
1268  (*consdata)->linvar_mayincrease = -1;
1269 
1270  (*consdata)->minlinactivity = SCIP_INVALID;
1271  (*consdata)->maxlinactivity = SCIP_INVALID;
1272  (*consdata)->minlinactivityinf = -1;
1273  (*consdata)->maxlinactivityinf = -1;
1274 
1275  (*consdata)->isgaugeavailable = FALSE;
1276  (*consdata)->isedavailable = FALSE;
1277 
1278  return SCIP_OKAY;
1279 }
1280 
1281 /** creates constraint data structure */
1282 static
1284  SCIP* scip, /**< SCIP data structure */
1285  SCIP_CONSDATA** consdata, /**< a buffer to store pointer to new constraint data */
1286  SCIP_Real lhs, /**< left hand side of constraint */
1287  SCIP_Real rhs, /**< right hand side of constraint */
1288  int nlinvars, /**< number of linear variables */
1289  SCIP_VAR** linvars, /**< array of linear variables */
1290  SCIP_Real* lincoefs, /**< array of coefficients of linear variables */
1291  int nquadvars, /**< number of quadratic variables */
1292  SCIP_QUADVARTERM* quadvarterms, /**< array of quadratic variable terms */
1293  int nbilinterms, /**< number of bilinear terms */
1294  SCIP_BILINTERM* bilinterms, /**< array of bilinear terms */
1295  SCIP_Bool capturevars /**< whether we should capture variables */
1296  )
1297 {
1298  int i;
1299 
1300  assert(scip != NULL);
1301  assert(consdata != NULL);
1302 
1303  assert(nlinvars == 0 || linvars != NULL);
1304  assert(nlinvars == 0 || lincoefs != NULL);
1305  assert(nquadvars == 0 || quadvarterms != NULL);
1306  assert(nbilinterms == 0 || bilinterms != NULL);
1307 
1308  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1309  BMSclearMemory(*consdata);
1310 
1311  (*consdata)->minlinactivity = SCIP_INVALID;
1312  (*consdata)->maxlinactivity = SCIP_INVALID;
1313  (*consdata)->minlinactivityinf = -1;
1314  (*consdata)->maxlinactivityinf = -1;
1315 
1316  (*consdata)->lhs = lhs;
1317  (*consdata)->rhs = rhs;
1318 
1319  if( nlinvars > 0 )
1320  {
1321  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->linvars, linvars, nlinvars) );
1322  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->lincoefs, lincoefs, nlinvars) );
1323  (*consdata)->nlinvars = nlinvars;
1324  (*consdata)->linvarssize = nlinvars;
1325 
1326  if( capturevars )
1327  for( i = 0; i < nlinvars; ++i )
1328  {
1329  SCIP_CALL( SCIPcaptureVar(scip, linvars[i]) );
1330  }
1331  }
1332  else
1333  {
1334  (*consdata)->linvarssorted = TRUE;
1335  (*consdata)->linvarsmerged = TRUE;
1336  (*consdata)->minlinactivity = 0.0;
1337  (*consdata)->maxlinactivity = 0.0;
1338  (*consdata)->minlinactivityinf = 0;
1339  (*consdata)->maxlinactivityinf = 0;
1340  }
1341 
1342  if( nquadvars > 0 )
1343  {
1344  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->quadvarterms, quadvarterms, nquadvars) );
1345 
1346  for( i = 0; i < nquadvars; ++i )
1347  {
1348  (*consdata)->quadvarterms[i].eventdata = NULL;
1349  if( quadvarterms[i].nadjbilin )
1350  {
1351  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->quadvarterms[i].adjbilin, quadvarterms[i].adjbilin, quadvarterms[i].nadjbilin) );
1352  (*consdata)->quadvarterms[i].adjbilinsize = quadvarterms[i].nadjbilin;
1353  }
1354  else
1355  {
1356  assert((*consdata)->quadvarterms[i].nadjbilin == 0);
1357  (*consdata)->quadvarterms[i].adjbilin = NULL;
1358  (*consdata)->quadvarterms[i].adjbilinsize = 0;
1359  }
1360  if( capturevars )
1361  {
1362  SCIP_CALL( SCIPcaptureVar(scip, quadvarterms[i].var) );
1363  }
1364  }
1365 
1366  (*consdata)->nquadvars = nquadvars;
1367  (*consdata)->quadvarssize = nquadvars;
1368  SCIPintervalSetEmpty(&(*consdata)->quadactivitybounds);
1369  }
1370  else
1371  {
1372  (*consdata)->quadvarssorted = TRUE;
1373  (*consdata)->quadvarsmerged = TRUE;
1374  SCIPintervalSet(&(*consdata)->quadactivitybounds, 0.0);
1375  }
1376 
1377  if( nbilinterms > 0 )
1378  {
1379  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->bilinterms, bilinterms, nbilinterms) );
1380  (*consdata)->nbilinterms = nbilinterms;
1381  (*consdata)->bilintermssize = nbilinterms;
1382  }
1383  else
1384  {
1385  (*consdata)->bilinsorted = TRUE;
1386  (*consdata)->bilinmerged = TRUE;
1387  }
1388 
1389  (*consdata)->linvar_maydecrease = -1;
1390  (*consdata)->linvar_mayincrease = -1;
1391 
1392  (*consdata)->activity = SCIP_INVALID;
1393  (*consdata)->lhsviol = SCIPisInfinity(scip, -lhs) ? 0.0 : SCIP_INVALID;
1394  (*consdata)->rhsviol = SCIPisInfinity(scip, rhs) ? 0.0 : SCIP_INVALID;
1395 
1396  (*consdata)->isgaugeavailable = FALSE;
1397 
1398  return SCIP_OKAY;
1399 }
1400 
1401 /** frees constraint data structure */
1402 static
1404  SCIP* scip, /**< SCIP data structure */
1405  SCIP_CONSDATA** consdata /**< pointer to constraint data to free */
1406  )
1407 {
1408  int i;
1409 
1410  assert(scip != NULL);
1411  assert(consdata != NULL);
1412  assert(*consdata != NULL);
1413 
1414  /* free sepa arrays, may exists if constraint is deleted in solving stage */
1415  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->sepaquadvars, (*consdata)->nquadvars);
1416  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->sepabilinvar2pos, (*consdata)->nbilinterms);
1417 
1418  /* release linear variables and free linear part */
1419  if( (*consdata)->linvarssize > 0 )
1420  {
1421  for( i = 0; i < (*consdata)->nlinvars; ++i )
1422  {
1423  assert((*consdata)->lineventdata == NULL || (*consdata)->lineventdata[i] == NULL); /* variable events should have been dropped earlier */
1424  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->linvars[i]) );
1425  }
1426  SCIPfreeBlockMemoryArray(scip, &(*consdata)->linvars, (*consdata)->linvarssize);
1427  SCIPfreeBlockMemoryArray(scip, &(*consdata)->lincoefs, (*consdata)->linvarssize);
1428  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->lineventdata, (*consdata)->linvarssize);
1429  }
1430  assert((*consdata)->linvars == NULL);
1431  assert((*consdata)->lincoefs == NULL);
1432  assert((*consdata)->lineventdata == NULL);
1433 
1434  /* release quadratic variables and free quadratic variable term part */
1435  for( i = 0; i < (*consdata)->nquadvars; ++i )
1436  {
1437  assert((*consdata)->quadvarterms[i].eventdata == NULL); /* variable events should have been dropped earlier */
1438  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->quadvarterms[i].adjbilin, (*consdata)->quadvarterms[i].adjbilinsize);
1439  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->quadvarterms[i].var) );
1440  }
1441  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->quadvarterms, (*consdata)->quadvarssize);
1442 
1443  /* free bilinear terms */
1444  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bilinterms, (*consdata)->bilintermssize);
1445 
1446  /* free nonlinear row representation */
1447  if( (*consdata)->nlrow != NULL )
1448  {
1449  SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
1450  }
1451 
1452  /* free interior point information, may exists if constraint is deleted in solving stage */
1453  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->interiorpoint, (*consdata)->nquadvars);
1454  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->gaugecoefs, (*consdata)->nquadvars);
1455 
1456  /* free eigen decomposition information */
1457  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->eigenvalues, (*consdata)->nquadvars);
1458  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->eigenvectors, (int)((*consdata)->nquadvars*(*consdata)->nquadvars));
1459  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bp, (*consdata)->nquadvars);
1460 
1461  /* free unique indices of bilinear terms array */
1462  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bilintermsidx, (*consdata)->nbilinterms);
1463 
1464  SCIPfreeBlockMemory(scip, consdata);
1465  *consdata = NULL;
1466 
1467  return SCIP_OKAY;
1468 }
1469 
1470 /** sorts linear part of constraint data */
1471 static
1473  SCIP_CONSDATA* consdata /**< quadratic constraint data */
1474  )
1475 {
1476  assert(consdata != NULL);
1477 
1478  if( consdata->linvarssorted )
1479  return;
1480 
1481  if( consdata->nlinvars <= 1 )
1482  {
1483  consdata->linvarssorted = TRUE;
1484  return;
1485  }
1486 
1487  if( consdata->lineventdata == NULL )
1488  {
1489  SCIPsortPtrReal((void**)consdata->linvars, consdata->lincoefs, SCIPvarComp, consdata->nlinvars);
1490  }
1491  else
1492  {
1493  int i;
1494 
1495  SCIPsortPtrPtrReal((void**)consdata->linvars, (void**)consdata->lineventdata, consdata->lincoefs, SCIPvarComp, consdata->nlinvars);
1496 
1497  /* update variable indices in event data */
1498  for( i = 0; i < consdata->nlinvars; ++i )
1499  if( consdata->lineventdata[i] != NULL )
1500  consdata->lineventdata[i]->varidx = i;
1501  }
1502 
1503  consdata->linvarssorted = TRUE;
1504 }
1505 
1506 #ifdef SCIP_DISABLED_CODE /* no-one needs this routine currently */
1507 /** returns the position of variable in the linear coefficients array of a constraint, or -1 if not found */
1508 static
1509 int consdataFindLinearVar(
1510  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1511  SCIP_VAR* var /**< variable to search for */
1512  )
1513 {
1514  int pos;
1515 
1516  assert(consdata != NULL);
1517  assert(var != NULL);
1518 
1519  if( consdata->nlinvars == 0 )
1520  return -1;
1521 
1522  consdataSortLinearVars(consdata);
1523 
1524  if( !SCIPsortedvecFindPtr((void**)consdata->linvars, SCIPvarComp, (void*)var, consdata->nlinvars, &pos) )
1525  pos = -1;
1526 
1527  return pos;
1528 }
1529 #endif
1530 
1531 /** index comparison method for quadratic variable terms: compares two indices of the quadratic variable set in the quadratic constraint */
1532 static
1533 SCIP_DECL_SORTINDCOMP(quadVarTermComp)
1534 { /*lint --e{715}*/
1535  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
1536 
1537  assert(consdata != NULL);
1538  assert(0 <= ind1 && ind1 < consdata->nquadvars);
1539  assert(0 <= ind2 && ind2 < consdata->nquadvars);
1540 
1541  return SCIPvarCompare(consdata->quadvarterms[ind1].var, consdata->quadvarterms[ind2].var);
1542 }
1543 
1544 /** sorting of quadratic variable terms */
1545 static
1547  SCIP* scip, /**< SCIP data structure */
1548  SCIP_CONSDATA* consdata /**< quadratic constraint data */
1549  )
1550 {
1551  int* perm;
1552  int i;
1553  int nexti;
1554  int v;
1555  SCIP_QUADVARTERM quadterm;
1556 
1557  assert(scip != NULL);
1558  assert(consdata != NULL);
1559 
1560  if( consdata->quadvarssorted )
1561  return SCIP_OKAY;
1562 
1563  if( consdata->nquadvars == 0 )
1564  {
1565  consdata->quadvarssorted = TRUE;
1566  return SCIP_OKAY;
1567  }
1568 
1569  /* get temporary memory to store the sorted permutation */
1570  SCIP_CALL( SCIPallocBufferArray(scip, &perm, consdata->nquadvars) );
1571 
1572  /* call bubble sort */
1573  SCIPsort(perm, quadVarTermComp, (void*)consdata, consdata->nquadvars);
1574 
1575  /* permute the quadratic variable terms according to the resulting permutation */
1576  for( v = 0; v < consdata->nquadvars; ++v )
1577  {
1578  if( perm[v] != v )
1579  {
1580  quadterm = consdata->quadvarterms[v];
1581 
1582  i = v;
1583  do
1584  {
1585  assert(0 <= perm[i] && perm[i] < consdata->nquadvars);
1586  assert(perm[i] != i);
1587  consdata->quadvarterms[i] = consdata->quadvarterms[perm[i]];
1588  if( consdata->quadvarterms[i].eventdata != NULL )
1589  {
1590  consdata->quadvarterms[i].eventdata->varidx = -i-1;
1591  }
1592  nexti = perm[i];
1593  perm[i] = i;
1594  i = nexti;
1595  }
1596  while( perm[i] != v );
1597  consdata->quadvarterms[i] = quadterm;
1598  if( consdata->quadvarterms[i].eventdata != NULL )
1599  {
1600  consdata->quadvarterms[i].eventdata->varidx = -i-1;
1601  }
1602  perm[i] = i;
1603  }
1604  }
1605  consdata->quadvarssorted = TRUE;
1606 
1607  /* free temporary memory */
1608  SCIPfreeBufferArray(scip, &perm);
1609 
1610  return SCIP_OKAY;
1611 }
1612 
1613 /** returns the position of variable in the quadratic variable terms array of a constraint, or -1 if not found */
1614 static
1616  SCIP* scip, /**< SCIP data structure */
1617  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1618  SCIP_VAR* var, /**< variable to search for */
1619  int* pos /**< buffer where to store position of var in quadvarterms array, or -1 if not found */
1620  )
1621 {
1622  int left;
1623  int right;
1624  int cmpres;
1625 
1626  assert(consdata != NULL);
1627  assert(var != NULL);
1628  assert(pos != NULL);
1629 
1630  if( consdata->nquadvars == 0 )
1631  {
1632  *pos = -1;
1633  return SCIP_OKAY;
1634  }
1635 
1636  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
1637 
1638  left = 0;
1639  right = consdata->nquadvars - 1;
1640  while( left <= right )
1641  {
1642  int middle;
1643 
1644  middle = (left+right)/2;
1645  assert(0 <= middle && middle < consdata->nquadvars);
1646 
1647  cmpres = SCIPvarCompare(var, consdata->quadvarterms[middle].var);
1648 
1649  if( cmpres < 0 )
1650  right = middle - 1;
1651  else if( cmpres > 0 )
1652  left = middle + 1;
1653  else
1654  {
1655  *pos = middle;
1656  return SCIP_OKAY;
1657  }
1658  }
1659  assert(left == right+1);
1660 
1661  *pos = -1;
1662 
1663  return SCIP_OKAY;
1664 }
1665 
1666 /** index comparison method for bilinear terms: compares two index pairs of the bilinear term set in the quadratic constraint */
1667 static
1668 SCIP_DECL_SORTINDCOMP(bilinTermComp)
1669 { /*lint --e{715}*/
1670  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
1671  int var1cmp;
1672 
1673  assert(consdata != NULL);
1674  assert(0 <= ind1 && ind1 < consdata->nbilinterms);
1675  assert(0 <= ind2 && ind2 < consdata->nbilinterms);
1676 
1677  var1cmp = SCIPvarCompare(consdata->bilinterms[ind1].var1, consdata->bilinterms[ind2].var1);
1678  if( var1cmp != 0 )
1679  return var1cmp;
1680 
1681  return SCIPvarCompare(consdata->bilinterms[ind1].var2, consdata->bilinterms[ind2].var2);
1682 }
1683 
1684 #ifndef NDEBUG
1685 /** checks if all bilinear terms are sorted correctly */
1686 static
1688  SCIP_CONSDATA* consdata
1689  )
1690 {
1691  int i;
1692 
1693  assert(consdata != NULL);
1694 
1695  /* nothing to check if the bilinear terms have not been sorted yet */
1696  if( !consdata->bilinsorted )
1697  return TRUE;
1698 
1699  for( i = 0; i < consdata->nbilinterms - 1; ++i )
1700  {
1701  if( bilinTermComp(consdata, i, i+1) > 0 )
1702  return FALSE;
1703  }
1704  return TRUE;
1705 }
1706 #endif
1707 
1708 /** sorting of bilinear terms */
1709 static
1711  SCIP* scip, /**< SCIP data structure */
1712  SCIP_CONSDATA* consdata /**< quadratic constraint data */
1713  )
1714 {
1715  int* perm;
1716  int* invperm;
1717  int i;
1718  int nexti;
1719  int v;
1720  SCIP_BILINTERM bilinterm;
1721 
1722  assert(scip != NULL);
1723  assert(consdata != NULL);
1724 
1725  if( consdata->bilinsorted )
1726  return SCIP_OKAY;
1727 
1728  if( consdata->nbilinterms == 0 )
1729  {
1730  consdata->bilinsorted = TRUE;
1731  return SCIP_OKAY;
1732  }
1733 
1734  /* get temporary memory to store the sorted permutation and the inverse permutation */
1735  SCIP_CALL( SCIPallocBufferArray(scip, &perm, consdata->nbilinterms) );
1736  SCIP_CALL( SCIPallocBufferArray(scip, &invperm, consdata->nbilinterms) );
1737 
1738  /* call bubble sort */
1739  SCIPsort(perm, bilinTermComp, (void*)consdata, consdata->nbilinterms);
1740 
1741  /* compute inverted permutation */
1742  for( v = 0; v < consdata->nbilinterms; ++v )
1743  {
1744  assert(0 <= perm[v] && perm[v] < consdata->nbilinterms);
1745  invperm[perm[v]] = v;
1746  }
1747 
1748  /* permute the bilinear terms according to the resulting permutation */
1749  for( v = 0; v < consdata->nbilinterms; ++v )
1750  {
1751  if( perm[v] != v )
1752  {
1753  bilinterm = consdata->bilinterms[v];
1754 
1755  i = v;
1756  do
1757  {
1758  assert(0 <= perm[i] && perm[i] < consdata->nbilinterms);
1759  assert(perm[i] != i);
1760  consdata->bilinterms[i] = consdata->bilinterms[perm[i]];
1761  nexti = perm[i];
1762  perm[i] = i;
1763  i = nexti;
1764  }
1765  while( perm[i] != v );
1766  consdata->bilinterms[i] = bilinterm;
1767  perm[i] = i;
1768  }
1769  }
1770 
1771  /* update the adjacency information in the quadratic variable terms */
1772  for( v = 0; v < consdata->nquadvars; ++v )
1773  for( i = 0; i < consdata->quadvarterms[v].nadjbilin; ++i )
1774  consdata->quadvarterms[v].adjbilin[i] = invperm[consdata->quadvarterms[v].adjbilin[i]];
1775 
1776  consdata->bilinsorted = TRUE;
1777  assert(consdataCheckBilinTermsSort(consdata));
1778 
1779  /* free temporary memory */
1780  SCIPfreeBufferArray(scip, &invperm);
1781  SCIPfreeBufferArray(scip, &perm);
1782 
1783  return SCIP_OKAY;
1784 }
1785 
1786 /** moves a linear variable from one position to another */
1787 static
1789  SCIP_CONSDATA* consdata, /**< constraint data */
1790  int oldpos, /**< position of variable that shall be moved */
1791  int newpos /**< new position of variable */
1792  )
1793 {
1794  assert(consdata != NULL);
1795  assert(oldpos >= 0);
1796  assert(oldpos < consdata->nlinvars);
1797  assert(newpos >= 0);
1798  assert(newpos < consdata->linvarssize);
1799 
1800  if( newpos == oldpos )
1801  return;
1802 
1803  consdata->linvars [newpos] = consdata->linvars [oldpos];
1804  consdata->lincoefs[newpos] = consdata->lincoefs[oldpos];
1805 
1806  if( consdata->lineventdata != NULL )
1807  {
1808  assert(newpos >= consdata->nlinvars || consdata->lineventdata[newpos] == NULL);
1809 
1810  consdata->lineventdata[newpos] = consdata->lineventdata[oldpos];
1811  consdata->lineventdata[newpos]->varidx = newpos;
1812 
1813  consdata->lineventdata[oldpos] = NULL;
1814  }
1815 
1816  consdata->linvarssorted = FALSE;
1817 }
1818 
1819 /** moves a quadratic variable from one position to another */
1820 static
1822  SCIP_CONSDATA* consdata, /**< constraint data */
1823  int oldpos, /**< position of variable that shall be moved */
1824  int newpos /**< new position of variable */
1825  )
1826 {
1827  assert(consdata != NULL);
1828  assert(oldpos >= 0);
1829  assert(oldpos < consdata->nquadvars);
1830  assert(newpos >= 0);
1831  assert(newpos < consdata->quadvarssize);
1832 
1833  if( newpos == oldpos )
1834  return;
1835 
1836  assert(newpos >= consdata->nquadvars || consdata->quadvarterms[newpos].eventdata == NULL);
1837 
1838  consdata->quadvarterms[newpos] = consdata->quadvarterms[oldpos];
1839 
1840  if( consdata->quadvarterms[newpos].eventdata != NULL )
1841  {
1842  consdata->quadvarterms[newpos].eventdata->varidx = -newpos-1;
1843  consdata->quadvarterms[oldpos].eventdata = NULL;
1844  }
1845 
1846  consdata->quadvarssorted = FALSE;
1847 }
1848 
1849 /** adds linear coefficient in quadratic constraint */
1850 static
1852  SCIP* scip, /**< SCIP data structure */
1853  SCIP_CONS* cons, /**< quadratic constraint */
1854  SCIP_VAR* var, /**< variable of constraint entry */
1855  SCIP_Real coef /**< coefficient of constraint entry */
1856  )
1857 {
1858  SCIP_CONSDATA* consdata;
1859  SCIP_Bool transformed;
1860 
1861  assert(scip != NULL);
1862  assert(cons != NULL);
1863  assert(var != NULL);
1864 
1865  /* ignore coefficient if it is nearly zero */
1866  if( SCIPisZero(scip, coef) )
1867  return SCIP_OKAY;
1868 
1869  consdata = SCIPconsGetData(cons);
1870  assert(consdata != NULL);
1871 
1872  /* are we in the transformed problem? */
1873  transformed = SCIPconsIsTransformed(cons);
1874 
1875  /* always use transformed variables in transformed constraints */
1876  if( transformed )
1877  {
1878  SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
1879  }
1880  assert(var != NULL);
1881  assert(transformed == SCIPvarIsTransformed(var));
1882 
1883  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars+1) );
1884  consdata->linvars [consdata->nlinvars] = var;
1885  consdata->lincoefs[consdata->nlinvars] = coef;
1886 
1887  ++consdata->nlinvars;
1888 
1889  /* catch variable events */
1890  if( SCIPconsIsEnabled(cons) )
1891  {
1892  SCIP_CONSHDLR* conshdlr;
1893  SCIP_CONSHDLRDATA* conshdlrdata;
1894 
1895  /* get event handler */
1896  conshdlr = SCIPconsGetHdlr(cons);
1897  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1898  assert(conshdlrdata != NULL);
1899  assert(conshdlrdata->eventhdlr != NULL);
1900 
1901  assert(consdata->lineventdata != NULL);
1902  consdata->lineventdata[consdata->nlinvars-1] = NULL;
1903 
1904  /* catch bound change events of variable */
1905  SCIP_CALL( catchLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, consdata->nlinvars-1) );
1906  }
1907 
1908  /* invalidate activity information */
1909  consdata->activity = SCIP_INVALID;
1910  consdata->minlinactivity = SCIP_INVALID;
1911  consdata->maxlinactivity = SCIP_INVALID;
1912  consdata->minlinactivityinf = -1;
1913  consdata->maxlinactivityinf = -1;
1914 
1915  /* invalidate nonlinear row */
1916  if( consdata->nlrow != NULL )
1917  {
1918  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1919  }
1920 
1921  /* install rounding locks for new variable */
1922  SCIP_CALL( lockLinearVariable(scip, cons, var, coef) );
1923 
1924  /* capture new variable */
1925  SCIP_CALL( SCIPcaptureVar(scip, var) );
1926 
1927  consdata->ispropagated = FALSE;
1928  consdata->ispresolved = FALSE;
1929  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var)
1930  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
1931  if( consdata->nlinvars == 1 )
1932  consdata->linvarssorted = TRUE;
1933  else
1934  consdata->linvarssorted = consdata->linvarssorted && (SCIPvarCompare(consdata->linvars[consdata->nlinvars-2], consdata->linvars[consdata->nlinvars-1]) == -1);
1935  /* always set too FALSE since the new linear variable should be checked if already existing as quad var term */
1936  consdata->linvarsmerged = FALSE;
1937 
1938  return SCIP_OKAY;
1939 }
1940 
1941 /** deletes linear coefficient at given position from quadratic constraint data */
1942 static
1944  SCIP* scip, /**< SCIP data structure */
1945  SCIP_CONS* cons, /**< quadratic constraint */
1946  int pos /**< position of coefficient to delete */
1947  )
1948 {
1949  SCIP_CONSDATA* consdata;
1950  SCIP_VAR* var;
1951  SCIP_Real coef;
1952 
1953  assert(scip != NULL);
1954  assert(cons != NULL);
1955 
1956  consdata = SCIPconsGetData(cons);
1957  assert(consdata != NULL);
1958  assert(0 <= pos && pos < consdata->nlinvars);
1959 
1960  var = consdata->linvars[pos];
1961  coef = consdata->lincoefs[pos];
1962  assert(var != NULL);
1963 
1964  /* remove rounding locks for deleted variable */
1965  SCIP_CALL( unlockLinearVariable(scip, cons, var, coef) );
1966 
1967  /* if we catch variable events, drop the events on the variable */
1968  if( consdata->lineventdata != NULL )
1969  {
1970  SCIP_CONSHDLR* conshdlr;
1971  SCIP_CONSHDLRDATA* conshdlrdata;
1972 
1973  /* get event handler */
1974  conshdlr = SCIPconsGetHdlr(cons);
1975  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1976  assert(conshdlrdata != NULL);
1977  assert(conshdlrdata->eventhdlr != NULL);
1978 
1979  /* drop bound change events of variable */
1980  SCIP_CALL( dropLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
1981  }
1982 
1983  /* release variable */
1984  SCIP_CALL( SCIPreleaseVar(scip, &consdata->linvars[pos]) );
1985 
1986  /* move the last variable to the free slot */
1987  consdataMoveLinearVar(consdata, consdata->nlinvars-1, pos);
1988 
1989  --consdata->nlinvars;
1990 
1991  /* invalidate activity */
1992  consdata->activity = SCIP_INVALID;
1993  consdata->minlinactivity = SCIP_INVALID;
1994  consdata->maxlinactivity = SCIP_INVALID;
1995  consdata->minlinactivityinf = -1;
1996  consdata->maxlinactivityinf = -1;
1997 
1998  /* invalidate nonlinear row */
1999  if( consdata->nlrow != NULL )
2000  {
2001  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2002  }
2003 
2004  consdata->ispropagated = FALSE;
2005  consdata->ispresolved = FALSE;
2006 
2007  return SCIP_OKAY;
2008 }
2009 
2010 /** changes linear coefficient value at given position of quadratic constraint */
2011 static
2013  SCIP* scip, /**< SCIP data structure */
2014  SCIP_CONS* cons, /**< quadratic constraint */
2015  int pos, /**< position of linear coefficient to change */
2016  SCIP_Real newcoef /**< new value of linear coefficient */
2017  )
2018 {
2019  SCIP_CONSHDLR* conshdlr;
2020  SCIP_CONSHDLRDATA* conshdlrdata;
2021  SCIP_CONSDATA* consdata;
2022  SCIP_VAR* var;
2023  SCIP_Real coef;
2024 
2025  assert(scip != NULL);
2026  assert(cons != NULL);
2027  assert(!SCIPisZero(scip, newcoef));
2028 
2029  conshdlrdata = NULL;
2030 
2031  consdata = SCIPconsGetData(cons);
2032  assert(consdata != NULL);
2033  assert(0 <= pos);
2034  assert(pos < consdata->nlinvars);
2035  assert(!SCIPisZero(scip, newcoef));
2036 
2037  var = consdata->linvars[pos];
2038  coef = consdata->lincoefs[pos];
2039  assert(var != NULL);
2040  assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
2041 
2042  /* invalidate activity */
2043  consdata->activity = SCIP_INVALID;
2044  consdata->minlinactivity = SCIP_INVALID;
2045  consdata->maxlinactivity = SCIP_INVALID;
2046  consdata->minlinactivityinf = -1;
2047  consdata->maxlinactivityinf = -1;
2048 
2049  /* invalidate nonlinear row */
2050  if( consdata->nlrow != NULL )
2051  {
2052  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2053  }
2054 
2055  /* if necessary, remove the rounding locks and event catching of the variable */
2056  if( newcoef * coef < 0.0 )
2057  {
2058  if( SCIPconsIsLocked(cons) )
2059  {
2060  assert(SCIPconsIsTransformed(cons));
2061 
2062  /* remove rounding locks for variable with old coefficient */
2063  SCIP_CALL( unlockLinearVariable(scip, cons, var, coef) );
2064  }
2065 
2066  if( consdata->lineventdata[pos] != NULL )
2067  {
2068  /* get event handler */
2069  conshdlr = SCIPconsGetHdlr(cons);
2070  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2071  assert(conshdlrdata != NULL);
2072  assert(conshdlrdata->eventhdlr != NULL);
2073 
2074  /* drop bound change events of variable */
2075  SCIP_CALL( dropLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
2076  }
2077  }
2078 
2079  /* change the coefficient */
2080  consdata->lincoefs[pos] = newcoef;
2081 
2082  /* if necessary, install the rounding locks and event catching of the variable again */
2083  if( newcoef * coef < 0.0 )
2084  {
2085  if( SCIPconsIsLocked(cons) )
2086  {
2087  /* install rounding locks for variable with new coefficient */
2088  SCIP_CALL( lockLinearVariable(scip, cons, var, newcoef) );
2089  }
2090 
2091  if( conshdlrdata != NULL )
2092  {
2093  assert(SCIPconsIsEnabled(cons));
2094 
2095  /* catch bound change events of variable */
2096  SCIP_CALL( catchLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
2097  }
2098  }
2099 
2100  consdata->ispropagated = FALSE;
2101  consdata->ispresolved = FALSE;
2102 
2103  return SCIP_OKAY;
2104 }
2105 
2106 /** adds quadratic variable term to quadratic constraint */
2107 static
2109  SCIP* scip, /**< SCIP data structure */
2110  SCIP_CONS* cons, /**< quadratic constraint */
2111  SCIP_VAR* var, /**< variable to add */
2112  SCIP_Real lincoef, /**< linear coefficient of variable */
2113  SCIP_Real sqrcoef /**< square coefficient of variable */
2114  )
2115 {
2116  SCIP_CONSDATA* consdata;
2117  SCIP_Bool transformed;
2118  SCIP_QUADVARTERM* quadvarterm;
2119 
2120  assert(scip != NULL);
2121  assert(cons != NULL);
2122  assert(var != NULL);
2123 
2124  consdata = SCIPconsGetData(cons);
2125  assert(consdata != NULL);
2126 
2127  /* are we in the transformed problem? */
2128  transformed = SCIPconsIsTransformed(cons);
2129 
2130  /* always use transformed variables in transformed constraints */
2131  if( transformed )
2132  {
2133  SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
2134  }
2135  assert(var != NULL);
2136  assert(transformed == SCIPvarIsTransformed(var));
2137 
2138  SCIP_CALL( consdataEnsureQuadVarTermsSize(scip, consdata, consdata->nquadvars+1) );
2139 
2140  quadvarterm = &consdata->quadvarterms[consdata->nquadvars];
2141  quadvarterm->var = var;
2142  quadvarterm->lincoef = lincoef;
2143  quadvarterm->sqrcoef = sqrcoef;
2144  quadvarterm->adjbilinsize = 0;
2145  quadvarterm->nadjbilin = 0;
2146  quadvarterm->adjbilin = NULL;
2147  quadvarterm->eventdata = NULL;
2148 
2149  ++consdata->nquadvars;
2150 
2151  /* capture variable */
2152  SCIP_CALL( SCIPcaptureVar(scip, var) );
2153 
2154  /* catch variable events, if we do so */
2155  if( SCIPconsIsEnabled(cons) )
2156  {
2157  SCIP_CONSHDLR* conshdlr;
2158  SCIP_CONSHDLRDATA* conshdlrdata;
2159 
2160  /* get event handler */
2161  conshdlr = SCIPconsGetHdlr(cons);
2162  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2163  assert(conshdlrdata != NULL);
2164  assert(conshdlrdata->eventhdlr != NULL);
2165 
2166  /* catch bound change events of variable */
2167  SCIP_CALL( catchQuadVarEvents(scip, conshdlrdata->eventhdlr, cons, consdata->nquadvars-1) );
2168  }
2169 
2170  /* invalidate activity information */
2171  consdata->activity = SCIP_INVALID;
2172  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2173 
2174  /* invalidate nonlinear row */
2175  if( consdata->nlrow != NULL )
2176  {
2177  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2178  }
2179 
2180  /* install rounding locks for new variable */
2181  SCIP_CALL( lockQuadraticVariable(scip, cons, var) );
2182 
2183  consdata->ispropagated = FALSE;
2184  consdata->ispresolved = FALSE;
2185  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var)
2186  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
2187  if( consdata->nquadvars == 1 )
2188  consdata->quadvarssorted = TRUE;
2189  else
2190  consdata->quadvarssorted = consdata->quadvarssorted &&
2191  (SCIPvarCompare(consdata->quadvarterms[consdata->nquadvars-2].var, consdata->quadvarterms[consdata->nquadvars-1].var) == -1);
2192  /* also set to FALSE if nquadvars == 1, since the new variable should be checked for linearity and other stuff in mergeAndClean ... */
2193  consdata->quadvarsmerged = FALSE;
2194 
2195  consdata->iscurvchecked = FALSE;
2196 
2197  return SCIP_OKAY;
2198 }
2199 
2200 /** deletes quadratic variable term at given position from quadratic constraint data */
2201 static
2203  SCIP* scip, /**< SCIP data structure */
2204  SCIP_CONS* cons, /**< quadratic constraint */
2205  int pos /**< position of term to delete */
2206  )
2207 {
2208  SCIP_CONSDATA* consdata;
2209  SCIP_VAR* var;
2210 
2211  assert(scip != NULL);
2212  assert(cons != NULL);
2213 
2214  consdata = SCIPconsGetData(cons);
2215  assert(consdata != NULL);
2216  assert(0 <= pos && pos < consdata->nquadvars);
2217 
2218  var = consdata->quadvarterms[pos].var;
2219  assert(var != NULL);
2220  assert(consdata->quadvarterms[pos].nadjbilin == 0);
2221 
2222  /* remove rounding locks for deleted variable */
2223  SCIP_CALL( unlockQuadraticVariable(scip, cons, var) );
2224 
2225  /* if we catch variable events, drop the events on the variable */
2226  if( consdata->quadvarterms[pos].eventdata != NULL )
2227  {
2228  SCIP_CONSHDLR* conshdlr;
2229  SCIP_CONSHDLRDATA* conshdlrdata;
2230 
2231  /* get event handler */
2232  conshdlr = SCIPconsGetHdlr(cons);
2233  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2234  assert(conshdlrdata != NULL);
2235  assert(conshdlrdata->eventhdlr != NULL);
2236 
2237  /* drop bound change events of variable */
2238  SCIP_CALL( dropQuadVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
2239  }
2240 
2241  /* release variable */
2242  SCIP_CALL( SCIPreleaseVar(scip, &consdata->quadvarterms[pos].var) );
2243 
2244  /* free adjacency array */
2245  SCIPfreeBlockMemoryArrayNull(scip, &consdata->quadvarterms[pos].adjbilin, consdata->quadvarterms[pos].adjbilinsize);
2246 
2247  /* move the last variable term to the free slot */
2248  consdataMoveQuadVarTerm(consdata, consdata->nquadvars-1, pos);
2249 
2250  --consdata->nquadvars;
2251 
2252  /* invalidate activity */
2253  consdata->activity = SCIP_INVALID;
2254  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2255 
2256  /* invalidate nonlinear row */
2257  if( consdata->nlrow != NULL )
2258  {
2259  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2260  }
2261 
2262  consdata->ispropagated = FALSE;
2263  consdata->ispresolved = FALSE;
2264  consdata->iscurvchecked = FALSE;
2265 
2266  return SCIP_OKAY;
2267 }
2268 
2269 /** replace variable in quadratic variable term at given position of quadratic constraint data
2270  *
2271  * Allows to replace x by coef*y+offset, thereby maintaining linear and square coefficients and bilinear terms.
2272  */
2273 static
2275  SCIP* scip, /**< SCIP data structure */
2276  SCIP_CONS* cons, /**< quadratic constraint */
2277  int pos, /**< position of term to replace */
2278  SCIP_VAR* var, /**< new variable */
2279  SCIP_Real coef, /**< linear coefficient of new variable */
2280  SCIP_Real offset /**< offset of new variable */
2281  )
2282 {
2283  SCIP_CONSDATA* consdata;
2284  SCIP_QUADVARTERM* quadvarterm;
2285  SCIP_EVENTHDLR* eventhdlr;
2286  SCIP_BILINTERM* bilinterm;
2287  SCIP_Real constant;
2288 
2289  int i;
2290  SCIP_VAR* var2;
2291 
2292  consdata = SCIPconsGetData(cons);
2293  assert(consdata != NULL);
2294  assert(pos >= 0);
2295  assert(pos < consdata->nquadvars);
2296 
2297  quadvarterm = &consdata->quadvarterms[pos];
2298 
2299  /* remove rounding locks for old variable */
2300  SCIP_CALL( unlockQuadraticVariable(scip, cons, quadvarterm->var) );
2301 
2302  /* if we catch variable events, drop the events on the old variable */
2303  if( quadvarterm->eventdata != NULL )
2304  {
2305  SCIP_CONSHDLR* conshdlr;
2306  SCIP_CONSHDLRDATA* conshdlrdata;
2307 
2308  /* get event handler */
2309  conshdlr = SCIPconsGetHdlr(cons);
2310  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2311  assert(conshdlrdata != NULL);
2312  assert(conshdlrdata->eventhdlr != NULL);
2313 
2314  eventhdlr = conshdlrdata->eventhdlr;
2315 
2316  /* drop bound change events of variable */
2317  SCIP_CALL( dropQuadVarEvents(scip, eventhdlr, cons, pos) );
2318  }
2319  else
2320  {
2321  eventhdlr = NULL;
2322  }
2323 
2324  /* compute constant and put into lhs/rhs */
2325  constant = quadvarterm->lincoef * offset + quadvarterm->sqrcoef * offset * offset;
2326  if( constant != 0.0 )
2327  {
2328  /* maintain constant part */
2329  if( !SCIPisInfinity(scip, -consdata->lhs) )
2330  consdata->lhs -= constant;
2331  if( !SCIPisInfinity(scip, consdata->rhs) )
2332  consdata->rhs -= constant;
2333  }
2334 
2335  /* update linear and square coefficient */
2336  quadvarterm->lincoef *= coef;
2337  quadvarterm->lincoef += 2.0 * quadvarterm->sqrcoef * coef * offset;
2338  quadvarterm->sqrcoef *= coef * coef;
2339 
2340  /* update bilinear terms */
2341  for( i = 0; i < quadvarterm->nadjbilin; ++i )
2342  {
2343  bilinterm = &consdata->bilinterms[quadvarterm->adjbilin[i]];
2344 
2345  if( bilinterm->var1 == quadvarterm->var )
2346  {
2347  bilinterm->var1 = var;
2348  var2 = bilinterm->var2;
2349  }
2350  else
2351  {
2352  assert(bilinterm->var2 == quadvarterm->var);
2353  bilinterm->var2 = var;
2354  var2 = bilinterm->var1;
2355  }
2356 
2357  if( var == var2 )
2358  {
2359  /* looks like we actually have a square term here */
2360  quadvarterm->lincoef += bilinterm->coef * offset;
2361  quadvarterm->sqrcoef += bilinterm->coef * coef;
2362  /* deleting bilinear terms is expensive, since it requires updating adjacency information
2363  * thus, for now we just set the coefficient to 0.0 and clear in later when the bilinear terms are merged */
2364  bilinterm->coef = 0.0;
2365  continue;
2366  }
2367 
2368  /* swap var1 and var2 if they are in wrong order */
2369  if( SCIPvarCompare(bilinterm->var1, bilinterm->var2) > 0 )
2370  {
2371  SCIP_VAR* tmp;
2372  tmp = bilinterm->var1;
2373  bilinterm->var1 = bilinterm->var2;
2374  bilinterm->var2 = tmp;
2375  }
2376  assert(SCIPvarCompare(bilinterm->var1, bilinterm->var2) == -1);
2377 
2378  if( offset != 0.0 )
2379  {
2380  /* need to find var2 and add offset*bilinterm->coef to linear coefficient */
2381  int var2pos;
2382 
2383  var2pos = 0;
2384  while( consdata->quadvarterms[var2pos].var != var2 )
2385  {
2386  ++var2pos;
2387  assert(var2pos < consdata->nquadvars);
2388  }
2389 
2390  consdata->quadvarterms[var2pos].lincoef += bilinterm->coef * offset;
2391  }
2392 
2393  bilinterm->coef *= coef;
2394  }
2395 
2396  /* release old variable */
2397  SCIP_CALL( SCIPreleaseVar(scip, &quadvarterm->var) );
2398 
2399  /* set new variable */
2400  quadvarterm->var = var;
2401 
2402  /* capture new variable */
2403  SCIP_CALL( SCIPcaptureVar(scip, quadvarterm->var) );
2404 
2405  /* catch variable events, if we do so */
2406  if( eventhdlr != NULL )
2407  {
2408  assert(SCIPconsIsEnabled(cons));
2409 
2410  /* catch bound change events of variable */
2411  SCIP_CALL( catchQuadVarEvents(scip, eventhdlr, cons, pos) );
2412  }
2413 
2414  /* invalidate activity information */
2415  consdata->activity = SCIP_INVALID;
2416  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2417 
2418  /* invalidate nonlinear row */
2419  if( consdata->nlrow != NULL )
2420  {
2421  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2422  }
2423 
2424  /* install rounding locks for new variable */
2425  SCIP_CALL( lockQuadraticVariable(scip, cons, var) );
2426 
2427  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var)
2428  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
2429  consdata->quadvarssorted = (consdata->nquadvars == 1);
2430  consdata->quadvarsmerged = FALSE;
2431  consdata->bilinsorted &= (quadvarterm->nadjbilin == 0); /*lint !e514*/
2432  consdata->bilinmerged &= (quadvarterm->nadjbilin == 0); /*lint !e514*/
2433 
2434  consdata->ispropagated = FALSE;
2435  consdata->ispresolved = FALSE;
2436  consdata->iscurvchecked = FALSE;
2437 
2438  return SCIP_OKAY;
2439 }
2440 
2441 /** adds a bilinear term to quadratic constraint */
2442 static
2444  SCIP* scip, /**< SCIP data structure */
2445  SCIP_CONS* cons, /**< quadratic constraint */
2446  int var1pos, /**< position of first variable in quadratic variables array */
2447  int var2pos, /**< position of second variable in quadratic variables array */
2448  SCIP_Real coef /**< coefficient of bilinear term */
2449  )
2450 {
2451  SCIP_CONSDATA* consdata;
2452  SCIP_BILINTERM* bilinterm;
2453 
2454  assert(scip != NULL);
2455  assert(cons != NULL);
2456 
2457  if( var1pos == var2pos )
2458  {
2459  SCIPerrorMessage("tried to add bilinear term where both variables are the same\n");
2460  return SCIP_INVALIDDATA;
2461  }
2462 
2463  consdata = SCIPconsGetData(cons);
2464  assert(consdata != NULL);
2465 
2466  /* check if the bilinear terms are sorted */
2467  assert(consdataCheckBilinTermsSort(consdata));
2468 
2469  assert(var1pos >= 0);
2470  assert(var1pos < consdata->nquadvars);
2471  assert(var2pos >= 0);
2472  assert(var2pos < consdata->nquadvars);
2473 
2474  SCIP_CALL( consdataEnsureBilinSize(scip, consdata, consdata->nbilinterms + 1) );
2475 
2476  bilinterm = &consdata->bilinterms[consdata->nbilinterms];
2477  if( SCIPvarCompare(consdata->quadvarterms[var1pos].var, consdata->quadvarterms[var2pos].var) < 0 )
2478  {
2479  bilinterm->var1 = consdata->quadvarterms[var1pos].var;
2480  bilinterm->var2 = consdata->quadvarterms[var2pos].var;
2481  }
2482  else
2483  {
2484  bilinterm->var1 = consdata->quadvarterms[var2pos].var;
2485  bilinterm->var2 = consdata->quadvarterms[var1pos].var;
2486  }
2487  bilinterm->coef = coef;
2488 
2489  if( bilinterm->var1 == bilinterm->var2 )
2490  {
2491  SCIPerrorMessage("tried to add bilinear term where both variables are the same, but appear at different positions in quadvarterms array\n");
2492  return SCIP_INVALIDDATA;
2493  }
2494  assert(SCIPvarCompare(bilinterm->var1, bilinterm->var2) == -1);
2495 
2496  SCIP_CALL( consdataEnsureAdjBilinSize(scip, &consdata->quadvarterms[var1pos], consdata->quadvarterms[var1pos].nadjbilin + 1) );
2497  SCIP_CALL( consdataEnsureAdjBilinSize(scip, &consdata->quadvarterms[var2pos], consdata->quadvarterms[var2pos].nadjbilin + 1) );
2498 
2499  consdata->quadvarterms[var1pos].adjbilin[consdata->quadvarterms[var1pos].nadjbilin] = consdata->nbilinterms;
2500  consdata->quadvarterms[var2pos].adjbilin[consdata->quadvarterms[var2pos].nadjbilin] = consdata->nbilinterms;
2501  ++consdata->quadvarterms[var1pos].nadjbilin;
2502  ++consdata->quadvarterms[var2pos].nadjbilin;
2503 
2504  ++consdata->nbilinterms;
2505 
2506  /* invalidate activity information */
2507  consdata->activity = SCIP_INVALID;
2508  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2509 
2510  /* invalidate nonlinear row */
2511  if( consdata->nlrow != NULL )
2512  {
2513  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2514  }
2515 
2516  consdata->ispropagated = FALSE;
2517  consdata->ispresolved = FALSE;
2518  if( consdata->nbilinterms == 1 )
2519  {
2520  consdata->bilinsorted = TRUE;
2521 
2522  /* we have to take care of the bilinear term in mergeAndCleanBilinearTerms() if the coefficient is zero */
2523  consdata->bilinmerged = !SCIPisZero(scip, consdata->bilinterms[0].coef);
2524  }
2525  else
2526  {
2527  consdata->bilinsorted = consdata->bilinsorted
2528  && (bilinTermComp(consdata, consdata->nbilinterms-2, consdata->nbilinterms-1) <= 0);
2529  consdata->bilinmerged = FALSE;
2530  }
2531 
2532  consdata->iscurvchecked = FALSE;
2533 
2534  /* check if the bilinear terms are sorted */
2535  assert(consdataCheckBilinTermsSort(consdata));
2536 
2537  return SCIP_OKAY;
2538 }
2539 
2540 /** removes a set of bilinear terms and updates adjacency information in quad var terms
2541  *
2542  * Note: this function sorts the given array termposs.
2543  */
2544 static
2546  SCIP* scip, /**< SCIP data structure */
2547  SCIP_CONS* cons, /**< quadratic constraint */
2548  int nterms, /**< number of terms to delete */
2549  int* termposs /**< indices of terms to delete */
2550  )
2551 {
2552  SCIP_CONSDATA* consdata;
2553  int* newpos;
2554  int i;
2555  int j;
2556  int offset;
2557 
2558  assert(scip != NULL);
2559  assert(cons != NULL);
2560  assert(nterms == 0 || termposs != NULL);
2561 
2562  if( nterms == 0 )
2563  return SCIP_OKAY;
2564 
2565  consdata = SCIPconsGetData(cons);
2566  assert(consdata != NULL);
2567 
2568  SCIPsortInt(termposs, nterms);
2569 
2570  SCIP_CALL( SCIPallocBufferArray(scip, &newpos, consdata->nbilinterms) );
2571 
2572  i = 0;
2573  offset = 0;
2574  for( j = 0; j < consdata->nbilinterms; ++j )
2575  {
2576  /* if j'th term is deleted, increase offset and continue */
2577  if( i < nterms && j == termposs[i] )
2578  {
2579  ++offset;
2580  ++i;
2581  newpos[j] = -1;
2582  continue;
2583  }
2584 
2585  /* otherwise, move it forward and remember new position */
2586  if( offset > 0 )
2587  consdata->bilinterms[j-offset] = consdata->bilinterms[j];
2588  newpos[j] = j - offset;
2589  }
2590  assert(offset == nterms);
2591 
2592  /* update adjacency and activity information in quad var terms */
2593  for( i = 0; i < consdata->nquadvars; ++i )
2594  {
2595  offset = 0;
2596  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
2597  {
2598  assert(consdata->quadvarterms[i].adjbilin[j] < consdata->nbilinterms);
2599  if( newpos[consdata->quadvarterms[i].adjbilin[j]] == -1 )
2600  {
2601  /* corresponding bilinear term was deleted, thus increase offset */
2602  ++offset;
2603  }
2604  else
2605  {
2606  /* update index of j'th bilinear term and store at position j-offset */
2607  consdata->quadvarterms[i].adjbilin[j-offset] = newpos[consdata->quadvarterms[i].adjbilin[j]];
2608  }
2609  }
2610  consdata->quadvarterms[i].nadjbilin -= offset;
2611  /* some bilinear term was removed, so invalidate activity bounds */
2612  }
2613 
2614  consdata->nbilinterms -= nterms;
2615 
2616  SCIPfreeBufferArray(scip, &newpos);
2617 
2618  /* some quad vars may be linear now */
2619  consdata->quadvarsmerged = FALSE;
2620 
2621  consdata->ispropagated = FALSE;
2622  consdata->ispresolved = FALSE;
2623  consdata->iscurvchecked = FALSE;
2624 
2625  /* invalidate activity */
2626  consdata->activity = SCIP_INVALID;
2627  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2628 
2629  /* invalidate nonlinear row */
2630  if( consdata->nlrow != NULL )
2631  {
2632  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2633  }
2634 
2635  return SCIP_OKAY;
2636 }
2637 
2638 /** merges quad var terms that correspond to the same variable and does additional cleanup
2639  *
2640  * If a quadratic variable terms is actually linear, makes a linear term out of it
2641  * also replaces squares of binary variables by the binary variables, i.e., adds sqrcoef to lincoef.
2642  */
2643 static
2645  SCIP* scip, /**< SCIP data structure */
2646  SCIP_CONS* cons /**< quadratic constraint */
2647  )
2648 {
2649  SCIP_QUADVARTERM* quadvarterm;
2650  SCIP_CONSDATA* consdata;
2651  int i;
2652  int j;
2653 
2654  assert(scip != NULL);
2655  assert(cons != NULL);
2656 
2657  consdata = SCIPconsGetData(cons);
2658 
2659  if( consdata->quadvarsmerged )
2660  return SCIP_OKAY;
2661 
2662  if( consdata->nquadvars == 0 )
2663  {
2664  consdata->quadvarsmerged = TRUE;
2665  return SCIP_OKAY;
2666  }
2667 
2668  i = 0;
2669  while( i < consdata->nquadvars )
2670  {
2671  /* make sure quad var terms are sorted (do this in every round, since we may move variables around) */
2672  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
2673 
2674  quadvarterm = &consdata->quadvarterms[i];
2675 
2676  for( j = i+1; j < consdata->nquadvars && consdata->quadvarterms[j].var == quadvarterm->var; ++j )
2677  {
2678  /* add quad var term j to current term i */
2679  quadvarterm->lincoef += consdata->quadvarterms[j].lincoef;
2680  quadvarterm->sqrcoef += consdata->quadvarterms[j].sqrcoef;
2681  if( consdata->quadvarterms[j].nadjbilin > 0 )
2682  {
2683  /* move adjacency information from j to i */
2684  SCIP_CALL( consdataEnsureAdjBilinSize(scip, quadvarterm, quadvarterm->nadjbilin + consdata->quadvarterms[j].nadjbilin) );
2685  BMScopyMemoryArray(&quadvarterm->adjbilin[quadvarterm->nadjbilin], consdata->quadvarterms[j].adjbilin, consdata->quadvarterms[j].nadjbilin); /*lint !e866*/
2686  quadvarterm->nadjbilin += consdata->quadvarterms[j].nadjbilin;
2687  consdata->quadvarterms[j].nadjbilin = 0;
2688  }
2689  consdata->quadvarterms[j].lincoef = 0.0;
2690  consdata->quadvarterms[j].sqrcoef = 0.0;
2691  /* mark that activity information in quadvarterm is not up to date anymore */
2692  }
2693 
2694  /* remove quad var terms i+1..j-1 backwards */
2695  for( j = j-1; j > i; --j )
2696  {
2697  SCIP_CALL( delQuadVarTermPos(scip, cons, j) );
2698  }
2699 
2700  /* for binary variables, x^2 = x
2701  * however, we may destroy convexity of a quadratic term that involves also bilinear terms
2702  * thus, we do this step only if the variable does not appear in any bilinear term */
2703  if( quadvarterm->sqrcoef != 0.0 && SCIPvarIsBinary(quadvarterm->var) && quadvarterm->nadjbilin == 0 )
2704  {
2705  SCIPdebugMsg(scip, "replace square of binary variable by itself: <%s>^2 --> <%s>\n", SCIPvarGetName(quadvarterm->var), SCIPvarGetName(quadvarterm->var));
2706  quadvarterm->lincoef += quadvarterm->sqrcoef;
2707  quadvarterm->sqrcoef = 0.0;
2708 
2709  /* invalidate nonlinear row */
2710  if( consdata->nlrow != NULL )
2711  {
2712  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2713  }
2714  }
2715 
2716  /* if its 0.0 or linear, get rid of it */
2717  if( SCIPisZero(scip, quadvarterm->sqrcoef) && quadvarterm->nadjbilin == 0 )
2718  {
2719  if( !SCIPisZero(scip, quadvarterm->lincoef) )
2720  {
2721  /* seem to be a linear term now, thus add as linear term */
2722  SCIP_CALL( addLinearCoef(scip, cons, quadvarterm->var, quadvarterm->lincoef) );
2723  }
2724  /* remove term at pos i */
2725  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
2726  }
2727  else
2728  {
2729  ++i;
2730  }
2731  }
2732 
2733  consdata->quadvarsmerged = TRUE;
2734  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2735 
2736  return SCIP_OKAY;
2737 }
2738 
2739 /** merges entries with same linear variable into one entry and cleans up entries with coefficient 0.0 */
2740 static
2742  SCIP* scip, /**< SCIP data structure */
2743  SCIP_CONS* cons /**< quadratic constraint */
2744  )
2745 {
2746  SCIP_CONSDATA* consdata;
2747  SCIP_Real newcoef;
2748  int i;
2749  int j;
2750  int qvarpos;
2751 
2752  assert(scip != NULL);
2753  assert(cons != NULL);
2754 
2755  consdata = SCIPconsGetData(cons);
2756 
2757  if( consdata->linvarsmerged )
2758  return SCIP_OKAY;
2759 
2760  if( consdata->nlinvars == 0 )
2761  {
2762  consdata->linvarsmerged = TRUE;
2763  return SCIP_OKAY;
2764  }
2765 
2766  i = 0;
2767  while( i < consdata->nlinvars )
2768  {
2769  /* make sure linear variables are sorted (do this in every round, since we may move variables around) */
2770  consdataSortLinearVars(consdata);
2771 
2772  /* sum up coefficients that correspond to variable i */
2773  newcoef = consdata->lincoefs[i];
2774  for( j = i+1; j < consdata->nlinvars && consdata->linvars[i] == consdata->linvars[j]; ++j )
2775  newcoef += consdata->lincoefs[j];
2776  /* delete the additional variables in backward order */
2777  for( j = j-1; j > i; --j )
2778  {
2779  SCIP_CALL( delLinearCoefPos(scip, cons, j) );
2780  }
2781 
2782  /* check if there is already a quadratic variable term with this variable */
2783  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->linvars[i], &qvarpos) );
2784  if( qvarpos >= 0)
2785  {
2786  /* add newcoef to linear coefficient of quadratic variable and mark linear variable as to delete */
2787  assert(qvarpos < consdata->nquadvars);
2788  assert(consdata->quadvarterms[qvarpos].var == consdata->linvars[i]);
2789  consdata->quadvarterms[qvarpos].lincoef += newcoef;
2790  newcoef = 0.0;
2791  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2792  }
2793 
2794  /* delete also entry at position i, if it became zero (or was zero before) */
2795  if( SCIPisZero(scip, newcoef) )
2796  {
2797  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
2798  }
2799  else
2800  {
2801  SCIP_CALL( chgLinearCoefPos(scip, cons, i, newcoef) );
2802  ++i;
2803  }
2804  }
2805 
2806  consdata->linvarsmerged = TRUE;
2807 
2808  return SCIP_OKAY;
2809 }
2810 
2811 /** merges bilinear terms with same variables into a single term, removes bilinear terms with coefficient 0.0 */
2812 static
2814  SCIP* scip, /**< SCIP data structure */
2815  SCIP_CONS* cons /**< quadratic constraint */
2816  )
2817 {
2818  SCIP_CONSDATA* consdata;
2819  SCIP_BILINTERM* bilinterm;
2820  int i;
2821  int j;
2822  int* todelete;
2823  int ntodelete;
2824 
2825  assert(scip != NULL);
2826  assert(cons != NULL);
2827 
2828  consdata = SCIPconsGetData(cons);
2829 
2830  /* check if the bilinear terms are sorted */
2831  assert(consdataCheckBilinTermsSort(consdata));
2832 
2833  if( consdata->bilinmerged )
2834  return SCIP_OKAY;
2835 
2836  if( consdata->nbilinterms == 0 )
2837  {
2838  consdata->bilinmerged = TRUE;
2839  return SCIP_OKAY;
2840  }
2841 
2842  /* alloc memory for array of terms that need to be deleted finally */
2843  ntodelete = 0;
2844  SCIP_CALL( SCIPallocBufferArray(scip, &todelete, consdata->nbilinterms) );
2845 
2846  /* make sure bilinear terms are sorted */
2847  SCIP_CALL( consdataSortBilinTerms(scip, consdata) );
2848 
2849  i = 0;
2850  while( i < consdata->nbilinterms )
2851  {
2852  bilinterm = &consdata->bilinterms[i];
2853 
2854  /* sum up coefficients that correspond to same variables as term i */
2855  for( j = i+1; j < consdata->nbilinterms && bilinterm->var1 == consdata->bilinterms[j].var1 && bilinterm->var2 == consdata->bilinterms[j].var2; ++j )
2856  {
2857  bilinterm->coef += consdata->bilinterms[j].coef;
2858  todelete[ntodelete++] = j;
2859  }
2860 
2861  /* delete also entry at position i, if it became zero (or was zero before) */
2862  if( SCIPisZero(scip, bilinterm->coef) )
2863  {
2864  todelete[ntodelete++] = i;
2865  }
2866 
2867  /* continue with term after the current series */
2868  i = j;
2869  }
2870 
2871  /* delete bilinear terms */
2872  SCIP_CALL( removeBilinearTermsPos(scip, cons, ntodelete, todelete) );
2873 
2874  SCIPfreeBufferArray(scip, &todelete);
2875 
2876  consdata->bilinmerged = TRUE;
2877 
2878  /* check if the bilinear terms are sorted */
2879  assert(consdataCheckBilinTermsSort(consdata));
2880 
2881  return SCIP_OKAY;
2882 }
2883 
2884 /** removes fixes (or aggregated) variables from a quadratic constraint */
2885 static
2887  SCIP* scip, /**< SCIP data structure */
2888  SCIP_CONS* cons /**< quadratic constraint */
2889  )
2890 {
2891  SCIP_CONSDATA* consdata;
2892  SCIP_BILINTERM* bilinterm;
2893  SCIP_Real bilincoef;
2894  SCIP_Real coef;
2895  SCIP_Real offset;
2896  SCIP_VAR* var;
2897  SCIP_VAR* var2;
2898  int var2pos;
2899  int i;
2900  int j;
2901  int k;
2902 
2903  SCIP_Bool have_change;
2904 
2905  assert(scip != NULL);
2906  assert(cons != NULL);
2907 
2908  consdata = SCIPconsGetData(cons);
2909 
2910  have_change = FALSE;
2911  i = 0;
2912  while( i < consdata->nlinvars )
2913  {
2914  var = consdata->linvars[i];
2915 
2916  if( SCIPvarIsActive(var) && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
2917  {
2918  ++i;
2919  continue;
2920  }
2921 
2922  have_change = TRUE;
2923 
2924  coef = consdata->lincoefs[i];
2925  offset = 0.0;
2926 
2927  if( SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
2928  {
2929  offset = coef * (SCIPvarGetLbGlobal(var) + SCIPvarGetUbGlobal(var)) / 2.0;
2930  coef = 0.0;
2931  }
2932  else
2933  {
2934  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &coef, &offset) );
2935  }
2936 
2937  SCIPdebugMsg(scip, " linear term %g*<%s> is replaced by %g * <%s> + %g\n", consdata->lincoefs[i], SCIPvarGetName(consdata->linvars[i]),
2938  coef, SCIPvarGetName(var), offset);
2939 
2940  /* delete previous variable (this will move another variable to position i) */
2941  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
2942 
2943  /* put constant part into bounds */
2944  if( offset != 0.0 )
2945  {
2946  if( !SCIPisInfinity(scip, -consdata->lhs) )
2947  consdata->lhs -= offset;
2948  if( !SCIPisInfinity(scip, consdata->rhs) )
2949  consdata->rhs -= offset;
2950  }
2951 
2952  /* nothing left to do if variable had been fixed */
2953  if( coef == 0.0 )
2954  continue;
2955 
2956  /* if GetProbvar gave a linear variable, just add it
2957  * if it's a multilinear variable, add it's disaggregated variables */
2958  if( SCIPvarIsActive(var) )
2959  {
2960  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
2961  }
2962  else
2963  {
2964  int naggrs;
2965  SCIP_VAR** aggrvars;
2966  SCIP_Real* aggrscalars;
2967  SCIP_Real aggrconstant;
2968 
2969  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
2970 
2971  naggrs = SCIPvarGetMultaggrNVars(var);
2972  aggrvars = SCIPvarGetMultaggrVars(var);
2973  aggrscalars = SCIPvarGetMultaggrScalars(var);
2974  aggrconstant = SCIPvarGetMultaggrConstant(var);
2975 
2976  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars + naggrs) );
2977 
2978  for( j = 0; j < naggrs; ++j )
2979  {
2980  SCIP_CALL( addLinearCoef(scip, cons, aggrvars[j], coef * aggrscalars[j]) );
2981  }
2982 
2983  if( aggrconstant != 0.0 )
2984  {
2985  if( !SCIPisInfinity(scip, -consdata->lhs) )
2986  consdata->lhs -= coef * aggrconstant;
2987  if( !SCIPisInfinity(scip, consdata->rhs) )
2988  consdata->rhs -= coef * aggrconstant;
2989  }
2990  }
2991  }
2992 
2993  i = 0;
2994  while( i < consdata->nquadvars )
2995  {
2996  var = consdata->quadvarterms[i].var;
2997 
2998  if( SCIPvarIsActive(var) && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
2999  {
3000  ++i;
3001  continue;
3002  }
3003 
3004  have_change = TRUE;
3005 
3006  coef = 1.0;
3007  offset = 0.0;
3008 
3009  if( !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
3010  {
3011  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &coef, &offset) );
3012  }
3013  else
3014  {
3015  coef = 0.0;
3016  offset = (SCIPvarGetLbGlobal(var) + SCIPvarGetUbGlobal(var)) / 2.0;
3017  }
3018 
3019  SCIPdebugMsg(scip, " quadratic variable <%s> with status %d is replaced by %g * <%s> + %g\n", SCIPvarGetName(consdata->quadvarterms[i].var),
3020  SCIPvarGetStatus(consdata->quadvarterms[i].var), coef, SCIPvarGetName(var), offset);
3021 
3022  /* handle fixed variable */
3023  if( coef == 0.0 )
3024  {
3025  /* if not fixed to 0.0, add to linear coefs of vars in bilinear terms, and deal with linear and square term as constant */
3026  if( offset != 0.0 )
3027  {
3028  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
3029  {
3030  bilinterm = &consdata->bilinterms[consdata->quadvarterms[i].adjbilin[j]];
3031 
3032  var2 = bilinterm->var1 == consdata->quadvarterms[i].var ? bilinterm->var2 : bilinterm->var1;
3033  assert(var2 != consdata->quadvarterms[i].var);
3034 
3035  var2pos = 0;
3036  while( consdata->quadvarterms[var2pos].var != var2 )
3037  {
3038  ++var2pos;
3039  assert(var2pos < consdata->nquadvars);
3040  }
3041  consdata->quadvarterms[var2pos].lincoef += bilinterm->coef * offset;
3042  }
3043 
3044  offset = consdata->quadvarterms[i].lincoef * offset + consdata->quadvarterms[i].sqrcoef * offset * offset;
3045  if( !SCIPisInfinity(scip, -consdata->lhs) )
3046  consdata->lhs -= offset;
3047  if( !SCIPisInfinity(scip, consdata->rhs) )
3048  consdata->rhs -= offset;
3049  }
3050 
3051  /* remove bilinear terms */
3052  SCIP_CALL( removeBilinearTermsPos(scip, cons, consdata->quadvarterms[i].nadjbilin, consdata->quadvarterms[i].adjbilin) );
3053 
3054  /* delete quad. var term i */
3055  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
3056 
3057  continue;
3058  }
3059 
3060  assert(var != NULL);
3061 
3062  /* if GetProbvar gave an active variable, replace the quad var term so that it uses the new variable */
3063  if( SCIPvarIsActive(var) )
3064  {
3065  /* replace x by coef*y+offset */
3066  SCIP_CALL( replaceQuadVarTermPos(scip, cons, i, var, coef, offset) );
3067 
3068  continue;
3069  }
3070  else
3071  {
3072  /* if GetProbVar gave a multi-aggregated variable, add new quad var terms and new bilinear terms
3073  * x is replaced by coef * (sum_i a_ix_i + b) + offset
3074  * lcoef * x + scoef * x^2 + bcoef * x * y ->
3075  * (b*coef + offset) * (lcoef + (b*coef + offset) * scoef)
3076  * + sum_i a_i*coef * (lcoef + 2 (b*coef + offset) * scoef) x_i
3077  * + sum_i (a_i*coef)^2 * scoef * x_i^2
3078  * + 2 sum_{i,j, i<j} (a_i a_j coef^2 scoef) x_i x_j
3079  * + bcoef * (b*coef + offset + coef * sum_i a_ix_i) y
3080  */
3081  int naggrs;
3082  SCIP_VAR** aggrvars; /* x_i */
3083  SCIP_Real* aggrscalars; /* a_i */
3084  SCIP_Real aggrconstant; /* b */
3085  int nquadtermsold;
3086 
3087  SCIP_Real lcoef;
3088  SCIP_Real scoef;
3089 
3090  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
3091 
3092  naggrs = SCIPvarGetMultaggrNVars(var);
3093  aggrvars = SCIPvarGetMultaggrVars(var);
3094  aggrscalars = SCIPvarGetMultaggrScalars(var);
3095  aggrconstant = SCIPvarGetMultaggrConstant(var);
3096 
3097  lcoef = consdata->quadvarterms[i].lincoef;
3098  scoef = consdata->quadvarterms[i].sqrcoef;
3099 
3100  nquadtermsold = consdata->nquadvars;
3101 
3102  SCIP_CALL( consdataEnsureQuadVarTermsSize(scip, consdata, consdata->nquadvars + naggrs) );
3103 
3104  /* take care of constant part */
3105  if( aggrconstant != 0.0 || offset != 0.0 )
3106  {
3107  SCIP_Real constant;
3108  constant = (aggrconstant * coef + offset) * (lcoef + (aggrconstant * coef + offset) * scoef);
3109  if( !SCIPisInfinity(scip, -consdata->lhs) )
3110  consdata->lhs -= constant;
3111  if( !SCIPisInfinity(scip, consdata->rhs) )
3112  consdata->rhs -= constant;
3113  }
3114 
3115  /* add x_i's with linear and square coefficients */
3116  for( j = 0; j < naggrs; ++j )
3117  {
3118  SCIP_CALL( addQuadVarTerm(scip, cons, aggrvars[j],
3119  coef * aggrscalars[j] * (lcoef + 2.0 * scoef * (coef * aggrconstant + offset)),
3120  coef * coef * aggrscalars[j] * aggrscalars[j] * scoef) );
3121  }
3122 
3123  /* ensure space for bilinear terms */
3124  SCIP_CALL( consdataEnsureBilinSize(scip, consdata, consdata->nquadvars + (scoef != 0.0 ? (naggrs * (naggrs-1))/2 : 0) + consdata->quadvarterms[j].nadjbilin * naggrs) );
3125 
3126  /* add x_j*x_k's */
3127  if( scoef != 0.0 )
3128  {
3129  for( j = 0; j < naggrs; ++j )
3130  for( k = 0; k < j; ++k )
3131  {
3132  assert(aggrvars[j] != aggrvars[k]);
3133  SCIP_CALL( addBilinearTerm(scip, cons, nquadtermsold + j, nquadtermsold + k,
3134  2.0 * aggrscalars[j] * aggrscalars[k] * coef * coef * scoef) );
3135  }
3136  }
3137 
3138  /* add x_i*y's */
3139  for( k = 0; k < consdata->quadvarterms[i].nadjbilin; ++k )
3140  {
3141  bilinterm = &consdata->bilinterms[consdata->quadvarterms[i].adjbilin[k]];
3142  bilincoef = bilinterm->coef; /* copy coef, as bilinterm pointer may become invalid by realloc in addBilinearTerm() below */
3143  var2 = (bilinterm->var1 == consdata->quadvarterms[i].var) ? bilinterm->var2 : bilinterm->var1;
3144  assert(var2 != consdata->quadvarterms[i].var);
3145 
3146  /* this is not efficient, but we cannot sort the quadratic terms here, since we currently iterate over them */
3147  var2pos = 0;
3148  while( consdata->quadvarterms[var2pos].var != var2 )
3149  {
3150  ++var2pos;
3151  assert(var2pos < consdata->nquadvars);
3152  }
3153 
3154  for( j = 0; j < naggrs; ++j )
3155  {
3156  if( aggrvars[j] == var2 )
3157  { /* x_i == y, so we have a square term here */
3158  consdata->quadvarterms[var2pos].sqrcoef += bilincoef * coef * aggrscalars[j];
3159  }
3160  else
3161  { /* x_i != y, so we need to add a bilinear term here */
3162  SCIP_CALL( addBilinearTerm(scip, cons, nquadtermsold + j, var2pos, bilincoef * coef * aggrscalars[j]) );
3163  }
3164  }
3165 
3166  consdata->quadvarterms[var2pos].lincoef += bilincoef * (aggrconstant * coef + offset);
3167  }
3168 
3169  /* remove bilinear terms */
3170  SCIP_CALL( removeBilinearTermsPos(scip, cons, consdata->quadvarterms[i].nadjbilin, consdata->quadvarterms[i].adjbilin) );
3171 
3172  /* delete quad. var term i */
3173  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
3174  }
3175  }
3176 
3177  consdata->isremovedfixings = TRUE;
3178 
3179  SCIPdebugMsg(scip, "removed fixations from <%s>\n -> ", SCIPconsGetName(cons));
3180  SCIPdebugPrintCons(scip, cons, NULL);
3181 
3182 #ifndef NDEBUG
3183  for( i = 0; i < consdata->nlinvars; ++i )
3184  assert(SCIPvarIsActive(consdata->linvars[i]));
3185 
3186  for( i = 0; i < consdata->nquadvars; ++i )
3187  assert(SCIPvarIsActive(consdata->quadvarterms[i].var));
3188 #endif
3189 
3190  if( !have_change )
3191  return SCIP_OKAY;
3192 
3193  /* some quadratic variable may have been replaced by an already existing linear variable
3194  * in this case, we want the linear variable to be removed, which happens in mergeAndCleanLinearVars
3195  */
3196  consdata->linvarsmerged = FALSE;
3197 
3198  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
3199  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, cons) );
3200  SCIP_CALL( mergeAndCleanLinearVars(scip, cons) );
3201 
3202 #ifndef NDEBUG
3203  for( i = 0; i < consdata->nbilinterms; ++i )
3204  {
3205  assert(consdata->bilinterms[i].var1 != consdata->bilinterms[i].var2);
3206  assert(consdata->bilinterms[i].coef != 0.0);
3207  assert(SCIPvarCompare(consdata->bilinterms[i].var1, consdata->bilinterms[i].var2) < 0);
3208  }
3209 #endif
3210 
3211  return SCIP_OKAY;
3212 }
3213 
3214 /** create a nonlinear row representation of the constraint and stores them in consdata */
3215 static
3217  SCIP* scip, /**< SCIP data structure */
3218  SCIP_CONS* cons /**< quadratic constraint */
3219  )
3220 {
3221  SCIP_CONSDATA* consdata;
3222  int nquadvars; /* number of variables in quadratic terms */
3223  SCIP_VAR** quadvars; /* variables in quadratic terms */
3224  int nquadelems; /* number of quadratic elements (square and bilinear terms) */
3225  SCIP_QUADELEM* quadelems; /* quadratic elements (square and bilinear terms) */
3226  int nquadlinterms; /* number of linear terms using variables that are in quadratic terms */
3227  SCIP_VAR** quadlinvars; /* variables of linear terms using variables that are in quadratic terms */
3228  SCIP_Real* quadlincoefs; /* coefficients of linear terms using variables that are in quadratic terms */
3229  int i;
3230  int idx1;
3231  int idx2;
3232  int lincnt;
3233  int elcnt;
3234  SCIP_VAR* lastvar;
3235  int lastvaridx;
3236  SCIP_EXPRCURV curvature;
3237 
3238  assert(scip != NULL);
3239  assert(cons != NULL);
3240 
3241  consdata = SCIPconsGetData(cons);
3242  assert(consdata != NULL);
3243 
3244  if( consdata->nlrow != NULL )
3245  {
3246  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3247  }
3248 
3249  nquadvars = consdata->nquadvars;
3250  nquadelems = consdata->nbilinterms;
3251  nquadlinterms = 0;
3252  for( i = 0; i < nquadvars; ++i )
3253  {
3254  if( consdata->quadvarterms[i].sqrcoef != 0.0 )
3255  ++nquadelems;
3256  if( !SCIPisZero(scip, consdata->quadvarterms[i].lincoef) )
3257  ++nquadlinterms;
3258  }
3259 
3260  SCIP_CALL( SCIPallocBufferArray(scip, &quadvars, nquadvars) );
3261  SCIP_CALL( SCIPallocBufferArray(scip, &quadelems, nquadelems) );
3262  SCIP_CALL( SCIPallocBufferArray(scip, &quadlinvars, nquadlinterms) );
3263  SCIP_CALL( SCIPallocBufferArray(scip, &quadlincoefs, nquadlinterms) );
3264 
3265  lincnt = 0;
3266  elcnt = 0;
3267  for( i = 0; i < nquadvars; ++i )
3268  {
3269  quadvars[i] = consdata->quadvarterms[i].var;
3270 
3271  if( consdata->quadvarterms[i].sqrcoef != 0.0 )
3272  {
3273  assert(elcnt < nquadelems);
3274  quadelems[elcnt].idx1 = i;
3275  quadelems[elcnt].idx2 = i;
3276  quadelems[elcnt].coef = consdata->quadvarterms[i].sqrcoef;
3277  ++elcnt;
3278  }
3279 
3280  if( !SCIPisZero(scip, consdata->quadvarterms[i].lincoef) )
3281  {
3282  assert(lincnt < nquadlinterms);
3283  quadlinvars [lincnt] = consdata->quadvarterms[i].var;
3284  quadlincoefs[lincnt] = consdata->quadvarterms[i].lincoef;
3285  ++lincnt;
3286  }
3287  }
3288  assert(lincnt == nquadlinterms);
3289 
3290  /* bilinear terms are sorted first by first variable, then by second variable
3291  * thus, it makes sense to remember the index of the previous first variable for the case a series of bilinear terms with the same first var appears */
3292  lastvar = NULL;
3293  lastvaridx = -1;
3294  for( i = 0; i < consdata->nbilinterms; ++i )
3295  {
3296  if( lastvar == consdata->bilinterms[i].var1 )
3297  {
3298  assert(lastvaridx >= 0);
3299  assert(consdata->quadvarterms[lastvaridx].var == consdata->bilinterms[i].var1);
3300  }
3301  else
3302  {
3303  lastvar = consdata->bilinterms[i].var1;
3304  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, lastvar, &lastvaridx) );
3305  }
3306  idx1 = lastvaridx;
3307 
3308  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->bilinterms[i].var2, &idx2) );
3309 
3310  assert(elcnt < nquadelems);
3311  quadelems[elcnt].idx1 = MIN(idx1, idx2);
3312  quadelems[elcnt].idx2 = MAX(idx1, idx2);
3313  quadelems[elcnt].coef = consdata->bilinterms[i].coef;
3314  ++elcnt;
3315  }
3316  assert(elcnt == nquadelems);
3317 
3318  /* set curvature for the nonlinear row */
3319  if( consdata->isconcave && consdata->isconvex )
3320  {
3321  assert(consdata->nbilinterms == 0 && consdata->nquadvars == 0);
3322  curvature = SCIP_EXPRCURV_LINEAR;
3323  }
3324  else if( consdata->isconcave )
3325  curvature = SCIP_EXPRCURV_CONCAVE;
3326  else if( consdata->isconvex )
3327  curvature = SCIP_EXPRCURV_CONVEX;
3328  else
3329  curvature = SCIP_EXPRCURV_UNKNOWN;
3330 
3331  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
3332  consdata->nlinvars, consdata->linvars, consdata->lincoefs,
3333  nquadvars, quadvars, nquadelems, quadelems,
3334  NULL, consdata->lhs, consdata->rhs,
3335  curvature) );
3336 
3337  SCIP_CALL( SCIPaddLinearCoefsToNlRow(scip, consdata->nlrow, nquadlinterms, quadlinvars, quadlincoefs) );
3338 
3339  SCIPfreeBufferArray(scip, &quadlincoefs);
3340  SCIPfreeBufferArray(scip, &quadlinvars);
3341  SCIPfreeBufferArray(scip, &quadelems);
3342  SCIPfreeBufferArray(scip, &quadvars);
3343 
3344  return SCIP_OKAY;
3345 }
3346 
3347 /** solve constraint as presolving */
3348 static
3350  SCIP* scip, /**< SCIP data structure */
3351  SCIP_CONS* cons, /**< constraint */
3352  SCIP_RESULT* result, /**< to store result of solve: cutoff, success, or do-not-find */
3353  SCIP_Bool* redundant, /**< to store whether constraint is redundant now (should be deleted) */
3354  int* naggrvars /**< counter on number of variable aggregations */
3355  )
3356 {
3357  SCIP_CONSDATA* consdata;
3358 
3359  assert(scip != NULL);
3360  assert(cons != NULL);
3361  assert(result != NULL);
3362  assert(redundant != NULL);
3363 
3364  *result = SCIP_DIDNOTFIND;
3365  *redundant = FALSE;
3366 
3367  consdata = SCIPconsGetData(cons);
3368  assert(consdata != NULL);
3369 
3370  /* if constraint is an equality with two variables, at least one of them binary,
3371  * and linear after fixing the binary, then we can aggregate the variables */
3372  if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) && consdata->nlinvars == 0 && consdata->nquadvars == 2 &&
3373  ((SCIPvarIsBinary(consdata->quadvarterms[0].var) && consdata->quadvarterms[1].sqrcoef == 0.0) ||
3374  (SCIPvarIsBinary(consdata->quadvarterms[1].var) && consdata->quadvarterms[0].sqrcoef == 0.0)) )
3375  {
3376  SCIP_Bool infeasible;
3377  SCIP_Bool aggregated;
3378  SCIP_Real a;
3379  SCIP_Real b;
3380  SCIP_Real c;
3381  SCIP_VAR* x;
3382  SCIP_VAR* y;
3383  int binvaridx;
3384 
3385  /* constraint is a*(x+x^2) + b*y + c*x*y = rhs, with x binary variable
3386  * x = 0 -> b*y == rhs
3387  * x = 1 -> (b+c)*y == rhs - a
3388  *
3389  * if b != 0 and b+c != 0, then y = (rhs-a)/(b+c) * x + rhs/b * (1-x) = ((rhs-a)/(b+c) - rhs/b) * x + rhs/b
3390  */
3391 
3392  binvaridx = (SCIPvarIsBinary(consdata->quadvarterms[0].var) && consdata->quadvarterms[1].sqrcoef == 0.0) ? 0 : 1;
3393 
3394  x = consdata->quadvarterms[binvaridx].var;
3395  a = consdata->quadvarterms[binvaridx].sqrcoef + consdata->quadvarterms[binvaridx].lincoef;
3396 
3397  y = consdata->quadvarterms[1-binvaridx].var;
3398  b = consdata->quadvarterms[1-binvaridx].lincoef;
3399 
3400  assert(consdata->nbilinterms <= 1); /* should actually be 1, since constraint is otherwise linear */
3401  c = (consdata->nbilinterms == 1) ? consdata->bilinterms[0].coef : 0.0;
3402 
3403  if( !SCIPisZero(scip, b) && !SCIPisZero(scip, b+c) )
3404  {
3405  SCIPdebugMsg(scip, "<%s> = 0 -> %g*<%s> = %g and <%s> = 1 -> %g*<%s> = %g\n", SCIPvarGetName(x), b, SCIPvarGetName(y), consdata->rhs,
3406  SCIPvarGetName(x), b+c, SCIPvarGetName(y), consdata->rhs - a);
3407  SCIPdebugMsg(scip, "=> attempt aggregation <%s> = %g*<%s> + %g\n", SCIPvarGetName(y), (consdata->rhs-a)/(b+c) - consdata->rhs/b,
3408  SCIPvarGetName(x), consdata->rhs/b);
3409 
3410  SCIP_CALL( SCIPaggregateVars(scip, x, y, (consdata->rhs-a)/(b+c) - consdata->rhs/b, -1.0, -consdata->rhs/b, &infeasible, redundant, &aggregated) );
3411  if( infeasible )
3412  *result = SCIP_CUTOFF;
3413  else if( *redundant || aggregated )
3414  {
3415  /* aggregated (or were already aggregated), so constraint is now redundant */
3416  *result = SCIP_SUCCESS;
3417  *redundant = TRUE;
3418 
3419  if( aggregated )
3420  ++*naggrvars;
3421  }
3422  }
3423 
3424  /* @todo if b is 0 or b+c is 0, or lhs != rhs, then could replace by varbound constraint */
3425  }
3426 
3427  return SCIP_OKAY;
3428 }
3429 
3430 
3431 /** reformulates products of binary variables as AND constraint
3432  *
3433  * For a product x*y, with x and y binary variables, the product is replaced by a new auxiliary variable z and the constraint z = {x and y} is added.
3434  */
3435 static
3437  SCIP* scip, /**< SCIP data structure */
3438  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3439  SCIP_CONS* cons, /**< constraint */
3440  int* naddconss /**< buffer where to add the number of AND constraints added */
3441  )
3442 {
3443  SCIP_CONSHDLRDATA* conshdlrdata;
3444  SCIP_CONSDATA* consdata;
3445  char name[SCIP_MAXSTRLEN];
3446  SCIP_VAR* vars[2];
3447  SCIP_VAR* auxvar;
3448  SCIP_CONS* andcons;
3449  int i;
3450  int ntodelete;
3451  int* todelete;
3452 
3453  assert(scip != NULL);
3454  assert(conshdlr != NULL);
3455  assert(cons != NULL);
3456  assert(naddconss != NULL);
3457 
3458  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3459  assert(conshdlrdata != NULL);
3460 
3461  /* if no binary variables, then we will find nothing to reformulate here
3462  * (note that this does not count in integer variables with {0,1} bounds...)
3463  */
3464  if( SCIPgetNBinVars(scip) == 0 )
3465  return SCIP_OKAY;
3466 
3467  /* if user does not like AND very much, then return */
3468  if( conshdlrdata->empathy4and < 2 )
3469  return SCIP_OKAY;
3470 
3471  consdata = SCIPconsGetData(cons);
3472  assert(consdata != NULL);
3473 
3474  if( consdata->nbilinterms == 0 )
3475  return SCIP_OKAY;
3476 
3477  /* get array to store indices of bilinear terms that shall be deleted */
3478  SCIP_CALL( SCIPallocBufferArray(scip, &todelete, consdata->nbilinterms) );
3479  ntodelete = 0;
3480 
3481  for( i = 0; i < consdata->nbilinterms; ++i )
3482  {
3483  vars[0] = consdata->bilinterms[i].var1;
3484  if( !SCIPvarIsBinary(vars[0]) )
3485  continue;
3486 
3487  vars[1] = consdata->bilinterms[i].var2;
3488  if( !SCIPvarIsBinary(vars[1]) )
3489  continue;
3490 
3491  /* create auxiliary variable */
3492  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_%s", SCIPvarGetName(vars[0]), SCIPvarGetName(vars[1]), SCIPconsGetName(cons));
3493  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY,
3494  SCIPvarIsInitial(vars[0]) || SCIPvarIsInitial(vars[1]), SCIPvarIsRemovable(vars[0]) && SCIPvarIsRemovable(vars[1]), NULL, NULL, NULL, NULL, NULL) );
3495  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3496 #ifdef WITH_DEBUG_SOLUTION
3497  if( SCIPdebugIsMainscip(scip) )
3498  {
3499  SCIP_Real var0val;
3500  SCIP_Real var1val;
3501  SCIP_CALL( SCIPdebugGetSolVal(scip, vars[0], &var0val) );
3502  SCIP_CALL( SCIPdebugGetSolVal(scip, vars[1], &var1val) );
3503  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, var0val * var1val) );
3504  }
3505 #endif
3506 
3507  /* create AND-constraint auxvar = x and y, need to be enforced as not redundant */
3508  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%sAND%s", SCIPvarGetName(vars[0]), SCIPvarGetName(vars[1]));
3509  SCIP_CALL( SCIPcreateConsAnd(scip, &andcons, name, auxvar, 2, vars,
3510  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3511  SCIPconsIsSeparated(cons), TRUE, TRUE,
3514  SCIP_CALL( SCIPaddCons(scip, andcons) );
3515  SCIPdebugMsg(scip, "added AND constraint: ");
3516  SCIPdebugPrintCons(scip, andcons, NULL);
3517  SCIP_CALL( SCIPreleaseCons(scip, &andcons) );
3518  ++*naddconss;
3519 
3520  /* add bilincoef * auxvar to linear terms */
3521  SCIP_CALL( addLinearCoef(scip, cons, auxvar, consdata->bilinterms[i].coef) );
3522  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
3523 
3524  /* remember that we have to delete this bilinear term */
3525  assert(ntodelete < consdata->nbilinterms);
3526  todelete[ntodelete++] = i;
3527  }
3528 
3529  /* remove bilinear terms that have been replaced */
3530  SCIP_CALL( removeBilinearTermsPos(scip, cons, ntodelete, todelete) );
3531  SCIPfreeBufferArray(scip, &todelete);
3532 
3533  return SCIP_OKAY;
3534 }
3535 
3536 /** gets bounds of variable y if x takes a certain value; checks whether x = xval has implications on y */
3537 static
3539  SCIP* scip, /**< SCIP data structure */
3540  SCIP_VAR* x, /**< variable which implications to check */
3541  SCIP_Bool xval, /**< value of x to check for (TRUE for 1, FALSE for 0) */
3542  SCIP_VAR* y, /**< variable to check if bounds can be reduced */
3543  SCIP_INTERVAL* resultant /**< buffer to store bounds on y */
3544  )
3545 {
3546  SCIP_VAR** implvars;
3547  SCIP_BOUNDTYPE* impltypes;
3548  SCIP_Real* implbounds;
3549  int nimpls;
3550  int pos;
3551 
3552  assert(scip != NULL);
3553  assert(x != NULL);
3554  assert(y != NULL);
3555  assert(resultant != NULL);
3556 
3558 
3559  if( !SCIPvarIsBinary(x) || !SCIPvarIsActive(x) )
3560  return SCIP_OKAY;
3561 
3562  /* check in cliques for binary to binary implications */
3563  if( SCIPvarIsBinary(y) )
3564  {
3565  resultant->inf = MAX(resultant->inf, MIN(resultant->sup, 0.0));
3566  resultant->sup = MIN(resultant->sup, MAX(resultant->inf, 1.0));
3567 
3568  if( SCIPhaveVarsCommonClique(scip, x, xval, y, TRUE, FALSE) )
3569  {
3570  resultant->sup = MIN(resultant->sup, MAX(resultant->inf, 0.0));
3571  }
3572  else if( SCIPhaveVarsCommonClique(scip, x, xval, y, FALSE, FALSE) )
3573  {
3574  resultant->inf = MAX(resultant->inf, MIN(resultant->sup, 1.0));
3575  }
3576 
3577  return SCIP_OKAY;
3578  }
3579 
3580  /* analyze implications for x = xval */
3581  nimpls = SCIPvarGetNImpls(x, xval);
3582  if( nimpls == 0 )
3583  return SCIP_OKAY;
3584 
3585  implvars = SCIPvarGetImplVars (x, xval);
3586  impltypes = SCIPvarGetImplTypes (x, xval);
3587  implbounds = SCIPvarGetImplBounds(x, xval);
3588 
3589  assert(implvars != NULL);
3590  assert(impltypes != NULL);
3591  assert(implbounds != NULL);
3592 
3593  /* find implications */
3594  if( !SCIPsortedvecFindPtr((void**)implvars, SCIPvarComp, (void*)y, nimpls, &pos) )
3595  return SCIP_OKAY;
3596 
3597  /* if there are several implications on y, go to the first one */
3598  while( pos > 0 && implvars[pos-1] == y )
3599  --pos;
3600 
3601  /* update implied lower and upper bounds on y
3602  * but make sure that resultant will not be empty, due to tolerances
3603  */
3604  while( pos < nimpls && implvars[pos] == y )
3605  {
3606  if( impltypes[pos] == SCIP_BOUNDTYPE_LOWER )
3607  resultant->inf = MAX(resultant->inf, MIN(resultant->sup, implbounds[pos]));
3608  else
3609  resultant->sup = MIN(resultant->sup, MAX(resultant->inf, implbounds[pos]));
3610  ++pos;
3611  }
3612 
3613  assert(resultant->sup >= resultant->inf);
3614 
3615  return SCIP_OKAY;
3616 }
3617 
3618 /** Reformulates products of binary times bounded continuous variables as system of linear inequalities (plus auxiliary variable).
3619  *
3620  * For a product x*y, with y a binary variable and x a continous variable with finite bounds,
3621  * an auxiliary variable z and the inequalities \f$ x^L y \leq z \leq x^U y \f$ and \f$ x - (1-y) x^U \leq z \leq x - (1-y) x^L \f$ are added.
3622  *
3623  * If x is a linear term consisting of more than one variable, it is split up in groups of linear terms of length at most maxnrvar.
3624  * For each product of linear term of length at most maxnrvar with y, an auxiliary z and linear inequalities are added.
3625  *
3626  * If y is a binary variable, the AND constraint \f$ z = x \wedge y \f$ may be added instead of linear constraints.
3627  */
3628 static
3630  SCIP* scip, /**< SCIP data structure */
3631  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3632  SCIP_CONS* cons, /**< constraint */
3633  int* naddconss /**< buffer where to add the number of auxiliary constraints added */
3634  )
3635 { /*lint --e{666} */
3636  SCIP_CONSHDLRDATA* conshdlrdata;
3637  SCIP_CONSDATA* consdata;
3638  SCIP_VAR** xvars;
3639  SCIP_Real* xcoef;
3640  SCIP_INTERVAL xbndszero;
3641  SCIP_INTERVAL xbndsone;
3642  SCIP_INTERVAL act0;
3643  SCIP_INTERVAL act1;
3644  int nxvars;
3645  SCIP_VAR* y;
3646  SCIP_VAR* bvar;
3647  char name[SCIP_MAXSTRLEN];
3648  int nbilinterms;
3649  SCIP_VAR* auxvar;
3650  SCIP_CONS* auxcons;
3651  int i;
3652  int j;
3653  int k;
3654  int bilinidx;
3655  SCIP_Real bilincoef;
3656  SCIP_Real mincoef;
3657  SCIP_Real maxcoef;
3658  int* todelete;
3659  int ntodelete;
3660  int maxnrvar;
3661  SCIP_Bool integral;
3662  SCIP_Longint gcd;
3663  SCIP_Bool auxvarinitial;
3664  SCIP_Bool auxvarremovable;
3665 
3666  assert(scip != NULL);
3667  assert(conshdlr != NULL);
3668  assert(cons != NULL);
3669  assert(naddconss != NULL);
3670 
3671  /* if no binary variables, then we will find nothing to reformulate here
3672  * (note that this does not count in integer variables with {0,1} bounds...)
3673  */
3674  if( SCIPgetNBinVars(scip) == 0 )
3675  return SCIP_OKAY;
3676 
3677  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3678  assert(conshdlrdata != NULL);
3679 
3680  maxnrvar = conshdlrdata->replacebinaryprodlength;
3681  if( maxnrvar == 0 )
3682  return SCIP_OKAY;
3683 
3684  consdata = SCIPconsGetData(cons);
3685  assert(consdata != NULL);
3686 
3687  xvars = NULL;
3688  xcoef = NULL;
3689  todelete = NULL;
3690  gcd = 0;
3691 
3692  for( i = 0; i < consdata->nquadvars; ++i )
3693  {
3694  y = consdata->quadvarterms[i].var;
3695  if( !SCIPvarIsBinary(y) )
3696  continue;
3697 
3698  nbilinterms = consdata->quadvarterms[i].nadjbilin;
3699  if( nbilinterms == 0 )
3700  continue;
3701 
3702  SCIP_CALL( SCIPreallocBufferArray(scip, &xvars, MIN(maxnrvar, nbilinterms)+2) ); /* add 2 for later use when creating linear constraints */
3703  SCIP_CALL( SCIPreallocBufferArray(scip, &xcoef, MIN(maxnrvar, nbilinterms)+2) );
3704 
3705  /* alloc array to store indices of bilinear terms that shall be deleted */
3706  SCIP_CALL( SCIPreallocBufferArray(scip, &todelete, nbilinterms) );
3707  ntodelete = 0;
3708 
3709  auxvarinitial = SCIPvarIsInitial(y);
3710  auxvarremovable = SCIPvarIsRemovable(y);
3711 
3712  /* setup a list of bounded variables x_i with coefficients a_i that are multiplied with binary y: y*(sum_i a_i*x_i)
3713  * and compute range of sum_i a_i*x_i for the cases y = 0 and y = 1
3714  * we may need several rounds if maxnrvar < nbilinterms
3715  */
3716  j = 0;
3717  do
3718  {
3719  nxvars = 0;
3720  SCIPintervalSet(&xbndszero, 0.0);
3721  SCIPintervalSet(&xbndsone, 0.0);
3722 
3723  mincoef = SCIPinfinity(scip);
3724  maxcoef = 0.0;
3725  integral = TRUE;
3726 
3727  /* collect at most maxnrvar variables for x term */
3728  for( ; j < nbilinterms && nxvars < maxnrvar; ++j )
3729  {
3730  bilinidx = consdata->quadvarterms[i].adjbilin[j];
3731  assert(bilinidx >= 0);
3732  assert(bilinidx < consdata->nbilinterms);
3733 
3734  bvar = consdata->bilinterms[bilinidx].var1;
3735  if( bvar == y )
3736  bvar = consdata->bilinterms[bilinidx].var2;
3737  assert(bvar != y);
3738 
3739  /* skip products with unbounded variables */
3740  if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(bvar)) || SCIPisInfinity(scip, SCIPvarGetUbGlobal(bvar)) )
3741  {
3742  SCIPdebugMsg(scip, "skip reform of <%s><%s> due to unbounded second variable [%g,%g]\n",
3744  continue;
3745  }
3746 
3747  /* skip products with non-binary variables if binreformbinaryonly is set */
3748  if( conshdlrdata->binreformbinaryonly && !SCIPvarIsBinary(bvar) )
3749  {
3750  SCIPdebugMsg(scip, "skip reform of <%s><%s> because second variable is not binary\n",
3751  SCIPvarGetName(y), SCIPvarGetName(bvar));
3752  continue;
3753  }
3754 
3755  bilincoef = consdata->bilinterms[bilinidx].coef;
3756  assert(bilincoef != 0.0);
3757 
3758  /* get activity of bilincoef * x if y = 0 */
3759  SCIP_CALL( getImpliedBounds(scip, y, FALSE, bvar, &act0) );
3760  SCIPintervalMulScalar(SCIPinfinity(scip), &act0, act0, bilincoef);
3761 
3762  /* get activity of bilincoef * x if y = 1 */
3763  SCIP_CALL( getImpliedBounds(scip, y, TRUE, bvar, &act1) );
3764  SCIPintervalMulScalar(SCIPinfinity(scip), &act1, act1, bilincoef);
3765 
3766  /* skip products that give rise to very large coefficients (big big-M's) */
3767  if( SCIPfeastol(scip) * REALABS(act0.inf) >= conshdlrdata->binreformmaxcoef || SCIPfeastol(scip) * REALABS(act0.sup) >= conshdlrdata->binreformmaxcoef )
3768  {
3769  SCIPdebugMsg(scip, "skip reform of %g<%s><%s> due to huge activity [%g,%g] for <%s> = 0.0\n",
3770  bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar), SCIPintervalGetInf(act0), SCIPintervalGetSup(act0), SCIPvarGetName(y));
3771  continue;
3772  }
3773  if( SCIPfeastol(scip) * REALABS(act1.inf) >= conshdlrdata->binreformmaxcoef || SCIPfeastol(scip) * REALABS(act1.sup) >= conshdlrdata->binreformmaxcoef )
3774  {
3775  SCIPdebugMsg(scip, "skip reform of %g<%s><%s> due to huge activity [%g,%g] for <%s> = 1.0\n",
3776  bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar), SCIPintervalGetInf(act1), SCIPintervalGetSup(act1), SCIPvarGetName(y));
3777  continue;
3778  }
3779  if( !SCIPisZero(scip, MIN(REALABS(act0.inf), REALABS(act0.sup))) &&
3780  SCIPfeastol(scip) * MAX(REALABS(act0.inf), REALABS(act0.sup)) / MIN(REALABS(act0.inf), REALABS(act0.sup)) >= conshdlrdata->binreformmaxcoef )
3781  {
3782  SCIPdebugMsg(scip, "skip reform of %g<%s><%s> due to huge activity ratio %g for <%s> = 0.0\n", bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar),
3783  MAX(REALABS(act0.inf), REALABS(act0.sup)) / MIN(REALABS(act0.inf), REALABS(act0.sup)), SCIPvarGetName(y));
3784  continue;
3785  }
3786  if( !SCIPisZero(scip, MIN(REALABS(act1.inf), REALABS(act1.sup))) &&
3787  SCIPfeastol(scip) * MAX(REALABS(act1.inf), REALABS(act1.sup)) / MIN(REALABS(act1.inf), REALABS(act1.sup)) >= conshdlrdata->binreformmaxcoef )
3788  {
3789  SCIPdebugMsg(scip, "skip reform of %g<%s><%s> due to huge activity ratio %g for <%s> = 0.0\n", bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar),
3790  MAX(REALABS(act1.inf), REALABS(act1.sup)) / MIN(REALABS(act1.inf), REALABS(act1.sup)), SCIPvarGetName(y));
3791  continue;
3792  }
3793 
3794  /* add bvar to x term */
3795  xvars[nxvars] = bvar;
3796  xcoef[nxvars] = bilincoef;
3797  ++nxvars;
3798 
3799  /* update bounds on x term */
3800  SCIPintervalAdd(SCIPinfinity(scip), &xbndszero, xbndszero, act0);
3801  SCIPintervalAdd(SCIPinfinity(scip), &xbndsone, xbndsone, act1);
3802 
3803  if( REALABS(bilincoef) < mincoef )
3804  mincoef = ABS(bilincoef);
3805  if( REALABS(bilincoef) > maxcoef )
3806  maxcoef = ABS(bilincoef);
3807 
3808  /* update whether all coefficients will be integral and if so, compute their gcd */
3809  integral &= (SCIPvarGetType(bvar) < SCIP_VARTYPE_CONTINUOUS) && SCIPisIntegral(scip, bilincoef); /*lint !e514 */
3810  if( integral )
3811  {
3812  if( nxvars == 1 )
3813  gcd = (SCIP_Longint)SCIPround(scip, REALABS(bilincoef));
3814  else
3815  gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)SCIPround(scip, REALABS(bilincoef)));
3816  }
3817 
3818  /* if bvar is initial, then also the auxiliary variable should be initial
3819  * if bvar is not removable, then also the auxiliary variable should not be removable
3820  */
3821  auxvarinitial |= SCIPvarIsInitial(bvar);
3822  auxvarremovable &= SCIPvarIsRemovable(bvar);
3823 
3824  /* remember that we have to remove this bilinear term later */
3825  assert(ntodelete < nbilinterms);
3826  todelete[ntodelete++] = bilinidx;
3827  }
3828 
3829  if( nxvars == 0 ) /* all (remaining) x_j seem to be unbounded */
3830  break;
3831 
3832  assert(!SCIPisInfinity(scip, -SCIPintervalGetInf(xbndszero)));
3833  assert(!SCIPisInfinity(scip, SCIPintervalGetSup(xbndszero)));
3834  assert(!SCIPisInfinity(scip, -SCIPintervalGetInf(xbndsone)));
3835  assert(!SCIPisInfinity(scip, SCIPintervalGetSup(xbndsone)));
3836 
3837 #ifdef SCIP_DEBUG
3838  if( SCIPintervalGetInf(xbndszero) != SCIPintervalGetInf(xbndsone) || /*lint !e777*/
3839  +SCIPintervalGetSup(xbndszero) != SCIPintervalGetSup(xbndsone) ) /*lint !e777*/
3840  {
3841  SCIPdebugMsg(scip, "got different bounds for y = 0: [%g, %g] and y = 1: [%g, %g]\n", xbndszero.inf, xbndszero.sup, xbndsone.inf, xbndsone.sup);
3842  }
3843 #endif
3844 
3845  if( nxvars == 1 && conshdlrdata->empathy4and >= 1 && SCIPvarIsBinary(xvars[0]) )
3846  {
3847  /* product of two binary variables, replace by auxvar and AND constraint */
3848  /* add auxiliary variable z */
3849  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3850  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT,
3851  auxvarinitial, auxvarremovable, NULL, NULL, NULL, NULL, NULL) );
3852  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3853 
3854 #ifdef WITH_DEBUG_SOLUTION
3855  if( SCIPdebugIsMainscip(scip) )
3856  {
3857  SCIP_Real var0val;
3858  SCIP_Real var1val;
3859  SCIP_CALL( SCIPdebugGetSolVal(scip, xvars[0], &var0val) );
3860  SCIP_CALL( SCIPdebugGetSolVal(scip, y, &var1val) );
3861  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, var0val * var1val) );
3862  }
3863 #endif
3864 
3865  /* add constraint z = x and y; need to be enforced, as it is not redundant w.r.t. existing constraints */
3866  xvars[1] = y;
3867  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%sAND%s_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3868  SCIP_CALL( SCIPcreateConsAnd(scip, &auxcons, name, auxvar, 2, xvars,
3869  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3870  SCIPconsIsSeparated(cons), TRUE, TRUE,
3873  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3874  SCIPdebugMsg(scip, "added AND constraint: ");
3875  SCIPdebugPrintCons(scip, auxcons, NULL);
3876  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3877  ++*naddconss;
3878 
3879  /* add linear term coef*auxvar */
3880  SCIP_CALL( addLinearCoef(scip, cons, auxvar, xcoef[0]) );
3881 
3882  /* forget about auxvar */
3883  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
3884  }
3885  else
3886  {
3887  /* product of binary variable with more than one binary or with continuous variables or with binary and user
3888  * did not like AND -> replace by auxvar and linear constraints */
3889  SCIP_Real scale;
3890 
3891  /* scale auxiliary constraint by some nice value,
3892  * if all coefficients are integral, take a value that preserves integrality (-> gcd), so we can make the auxiliary variable impl. integer
3893  */
3894  if( integral )
3895  {
3896  scale = (SCIP_Real)gcd;
3897  assert(scale >= 1.0);
3898  }
3899  else if( nxvars == 1 )
3900  {
3901  /* scaling by the only coefficient gives auxiliary variable = x * y, which thus will be implicit integral provided y is not continuous */
3902  assert(mincoef == maxcoef); /*lint !e777 */
3903  scale = mincoef;
3904  integral = SCIPvarGetType(xvars[0]) < SCIP_VARTYPE_CONTINUOUS;
3905  }
3906  else
3907  {
3908  scale = 1.0;
3909  if( maxcoef < 0.5 )
3910  scale = maxcoef;
3911  if( mincoef > 2.0 )
3912  scale = mincoef;
3913  if( scale != 1.0 )
3914  scale = SCIPselectSimpleValue(scale / 2.0, 1.5 * scale, MAXDNOM);
3915  }
3916  assert(scale > 0.0);
3917  assert(!SCIPisInfinity(scip, scale));
3918 
3919  /* if x-term is always negative for y = 1, negate scale so we get a positive auxiliary variable; maybe this is better sometimes? */
3920  if( !SCIPisPositive(scip, SCIPintervalGetSup(xbndsone)) )
3921  scale = -scale;
3922 
3923  SCIPdebugMsg(scip, "binary reformulation using scale %g, nxvars = %d, integral = %u\n", scale, nxvars, integral);
3924  if( scale != 1.0 )
3925  {
3926  SCIPintervalDivScalar(SCIPinfinity(scip), &xbndszero, xbndszero, scale);
3927  SCIPintervalDivScalar(SCIPinfinity(scip), &xbndsone, xbndsone, scale);
3928  for( k = 0; k < nxvars; ++k )
3929  xcoef[k] /= scale;
3930  }
3931 
3932  /* add auxiliary variable z */
3933  if( nxvars == 1 )
3934  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3935  else
3936  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_more_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3937  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, MIN(0., SCIPintervalGetInf(xbndsone)), MAX(0., SCIPintervalGetSup(xbndsone)),
3939  auxvarinitial, auxvarremovable, NULL, NULL, NULL, NULL, NULL) );
3940  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3941 
3942  /* compute value of auxvar in debug solution */
3943 #ifdef WITH_DEBUG_SOLUTION
3944  if( SCIPdebugIsMainscip(scip) )
3945  {
3946  SCIP_Real debugval;
3947  SCIP_Real varval;
3948 
3949  SCIP_CALL( SCIPdebugGetSolVal(scip, y, &varval) );
3950  if( SCIPisZero(scip, varval) )
3951  {
3952  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, 0.0) );
3953  }
3954  else
3955  {
3956  assert(SCIPisEQ(scip, varval, 1.0));
3957 
3958  debugval = 0.0;
3959  for( k = 0; k < nxvars; ++k )
3960  {
3961  SCIP_CALL( SCIPdebugGetSolVal(scip, xvars[k], &varval) );
3962  debugval += xcoef[k] * varval;
3963  }
3964  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, debugval) );
3965  }
3966  }
3967 #endif
3968 
3969  /* add auxiliary constraints
3970  * it seems to be advantageous to make the varbound constraints initial and the linear constraints not initial
3971  * maybe because it is more likely that a binary variable takes value 0 instead of 1, and thus the varbound constraints
3972  * are more often active, compared to the linear constraints added below
3973  * also, the varbound constraints are more sparse than the linear cons
3974  */
3975  if( SCIPisNegative(scip, SCIPintervalGetInf(xbndsone)) )
3976  {
3977  /* add 0 <= z - xbndsone.inf * y constraint (as varbound constraint), need to be enforced as not redundant */
3978  if( nxvars == 1 )
3979  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_1", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3980  else
3981  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_1", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3982  SCIP_CALL( SCIPcreateConsVarbound(scip, &auxcons, name, auxvar, y, -SCIPintervalGetInf(xbndsone), 0.0, SCIPinfinity(scip),
3983  SCIPconsIsInitial(cons) /*&& conshdlrdata->binreforminitial*/,
3984  SCIPconsIsSeparated(cons), TRUE, TRUE,
3987  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3988  SCIPdebugMsg(scip, "added varbound constraint: ");
3989  SCIPdebugPrintCons(scip, auxcons, NULL);
3990  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3991  ++*naddconss;
3992  }
3993  if( SCIPisPositive(scip, SCIPintervalGetSup(xbndsone)) )
3994  {
3995  /* add z - xbndsone.sup * y <= 0 constraint (as varbound constraint), need to be enforced as not redundant */
3996  if( nxvars == 1 )
3997  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_2", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3998  else
3999  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_2", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4000  SCIP_CALL( SCIPcreateConsVarbound(scip, &auxcons, name, auxvar, y, -SCIPintervalGetSup(xbndsone), -SCIPinfinity(scip), 0.0,
4001  SCIPconsIsInitial(cons) /*&& conshdlrdata->binreforminitial*/,
4002  SCIPconsIsSeparated(cons), TRUE, TRUE,
4005  SCIP_CALL( SCIPaddCons(scip, auxcons) );
4006  SCIPdebugMsg(scip, "added varbound constraint: ");
4007  SCIPdebugPrintCons(scip, auxcons, NULL);
4008  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
4009  ++*naddconss;
4010  }
4011 
4012  /* add xbndszero.inf <= sum_i a_i*x_i + xbndszero.inf * y - z constraint, need to be enforced as not redundant */
4013  xvars[nxvars] = y;
4014  xvars[nxvars+1] = auxvar;
4015  xcoef[nxvars] = SCIPintervalGetInf(xbndszero);
4016  xcoef[nxvars+1] = -1;
4017 
4018  if( nxvars == 1 )
4019  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_3", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4020  else
4021  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_3", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4022  SCIP_CALL( SCIPcreateConsLinear(scip, &auxcons, name, nxvars+2, xvars, xcoef, SCIPintervalGetInf(xbndszero), SCIPinfinity(scip),
4023  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
4024  SCIPconsIsSeparated(cons), TRUE, TRUE,
4027  SCIP_CALL( SCIPaddCons(scip, auxcons) );
4028  SCIPdebugMsg(scip, "added linear constraint: ");
4029  SCIPdebugPrintCons(scip, auxcons, NULL);
4030  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
4031  ++*naddconss;
4032 
4033  /* add sum_i a_i*x_i + xbndszero.sup * y - z <= xbndszero.sup constraint, need to be enforced as not redundant */
4034  xcoef[nxvars] = SCIPintervalGetSup(xbndszero);
4035 
4036  if( nxvars == 1 )
4037  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_4", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4038  else
4039  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_4", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4040  SCIP_CALL( SCIPcreateConsLinear(scip, &auxcons, name, nxvars+2, xvars, xcoef, -SCIPinfinity(scip), SCIPintervalGetSup(xbndszero),
4041  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
4042  SCIPconsIsSeparated(cons), TRUE, TRUE,
4045  SCIP_CALL( SCIPaddCons(scip, auxcons) );
4046  SCIPdebugMsg(scip, "added linear constraint: ");
4047  SCIPdebugPrintCons(scip, auxcons, NULL);
4048  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
4049  ++*naddconss;
4050 
4051  /* add linear term scale*auxvar to this constraint */
4052  SCIP_CALL( addLinearCoef(scip, cons, auxvar, scale) );
4053 
4054  /* forget about auxvar */
4055  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
4056  }
4057  }
4058  while( j < nbilinterms );
4059 
4060  /* remove bilinear terms that have been replaced */
4061  SCIP_CALL( removeBilinearTermsPos(scip, cons, ntodelete, todelete) );
4062  }
4063  SCIPdebugMsg(scip, "resulting quadratic constraint: ");
4064  SCIPdebugPrintCons(scip, cons, NULL);
4065 
4066  SCIPfreeBufferArrayNull(scip, &xvars);
4067  SCIPfreeBufferArrayNull(scip, &xcoef);
4068  SCIPfreeBufferArrayNull(scip, &todelete);
4069 
4070  return SCIP_OKAY;
4071 }
4072 
4073 /** tries to automatically convert a quadratic constraint (or a part of it) into a more specific and more specialized constraint */
4074 static
4076  SCIP* scip, /**< SCIP data structure */
4077  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
4078  SCIP_CONS* cons, /**< source constraint to try to convert */
4079  SCIP_Bool* upgraded, /**< buffer to store whether constraint was upgraded */
4080  int* nupgdconss, /**< buffer to increase if constraint was upgraded */
4081  int* naddconss, /**< buffer to increase with number of additional constraints created during upgrade */
4082  SCIP_PRESOLTIMING presoltiming /**< current presolving timing */
4083  )
4084 {
4085  SCIP_CONSHDLRDATA* conshdlrdata;
4086  SCIP_CONSDATA* consdata;
4087  SCIP_VAR* var;
4088  SCIP_Real lincoef;
4089  SCIP_Real quadcoef;
4090  SCIP_Real lb;
4091  SCIP_Real ub;
4092  int nbinlin;
4093  int nbinquad;
4094  int nintlin;
4095  int nintquad;
4096  int nimpllin;
4097  int nimplquad;
4098  int ncontlin;
4099  int ncontquad;
4100  SCIP_Bool integral;
4101  int i;
4102  int j;
4103  SCIP_CONS** upgdconss;
4104  int upgdconsssize;
4105  int nupgdconss_;
4106 
4107  assert(scip != NULL);
4108  assert(conshdlr != NULL);
4109  assert(cons != NULL);
4110  assert(!SCIPconsIsModifiable(cons));
4111  assert(upgraded != NULL);
4112  assert(nupgdconss != NULL);
4113  assert(naddconss != NULL);
4114 
4115  *upgraded = FALSE;
4116 
4117  nupgdconss_ = 0;
4118 
4119  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4120  assert(conshdlrdata != NULL);
4121 
4122  /* if there are no upgrade methods, we can also stop */
4123  if( conshdlrdata->nquadconsupgrades == 0 )
4124  return SCIP_OKAY;
4125 
4126  upgdconsssize = 2;
4127  SCIP_CALL( SCIPallocBufferArray(scip, &upgdconss, upgdconsssize) );
4128 
4129  consdata = SCIPconsGetData(cons);
4130  assert(consdata != NULL);
4131 
4132  /* calculate some statistics on quadratic constraint */
4133  nbinlin = 0;
4134  nbinquad = 0;
4135  nintlin = 0;
4136  nintquad = 0;
4137  nimpllin = 0;
4138  nimplquad = 0;
4139  ncontlin = 0;
4140  ncontquad = 0;
4141  integral = TRUE;
4142  for( i = 0; i < consdata->nlinvars; ++i )
4143  {
4144  var = consdata->linvars[i];
4145  lincoef = consdata->lincoefs[i];
4146  lb = SCIPvarGetLbLocal(var);
4147  ub = SCIPvarGetUbLocal(var);
4148  assert(!SCIPisZero(scip, lincoef));
4149 
4150  switch( SCIPvarGetType(var) )
4151  {
4152  case SCIP_VARTYPE_BINARY:
4153  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4154  integral = integral && SCIPisIntegral(scip, lincoef);
4155  nbinlin++;
4156  break;
4157  case SCIP_VARTYPE_INTEGER:
4158  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4159  integral = integral && SCIPisIntegral(scip, lincoef);
4160  nintlin++;
4161  break;
4162  case SCIP_VARTYPE_IMPLINT:
4163  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4164  integral = integral && SCIPisIntegral(scip, lincoef);
4165  nimpllin++;
4166  break;
4168  integral = integral && SCIPisRelEQ(scip, lb, ub) && SCIPisIntegral(scip, lincoef * lb);
4169  ncontlin++;
4170  break;
4171  default:
4172  SCIPerrorMessage("unknown variable type\n");
4173  return SCIP_INVALIDDATA;
4174  }
4175  }
4176 
4177  for( i = 0; i < consdata->nquadvars; ++i )
4178  {
4179  var = consdata->quadvarterms[i].var;
4180  lincoef = consdata->quadvarterms[i].lincoef;
4181  quadcoef = consdata->quadvarterms[i].sqrcoef;
4182  lb = SCIPvarGetLbLocal(var);
4183  ub = SCIPvarGetUbLocal(var);
4184 
4185  switch( SCIPvarGetType(var) )
4186  {
4187  case SCIP_VARTYPE_BINARY:
4188  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4189  integral = integral && SCIPisIntegral(scip, lincoef) && SCIPisIntegral(scip, quadcoef);
4190  nbinquad++;
4191  break;
4192  case SCIP_VARTYPE_INTEGER:
4193  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4194  integral = integral && SCIPisIntegral(scip, lincoef) && SCIPisIntegral(scip, quadcoef);
4195  nintquad++;
4196  break;
4197  case SCIP_VARTYPE_IMPLINT:
4198  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4199  integral = integral && SCIPisIntegral(scip, lincoef) && SCIPisIntegral(scip, quadcoef);
4200  nimplquad++;
4201  break;
4203  integral = integral && SCIPisRelEQ(scip, lb, ub) && SCIPisIntegral(scip, lincoef * lb + quadcoef * lb * lb);
4204  ncontquad++;
4205  break;
4206  default:
4207  SCIPerrorMessage("unknown variable type\n");
4208  return SCIP_INVALIDDATA;
4209  }
4210  }
4211 
4212  if( integral )
4213  {
4214  for( i = 0; i < consdata->nbilinterms && integral; ++i )
4215  {
4216  if( SCIPvarGetType(consdata->bilinterms[i].var1) < SCIP_VARTYPE_CONTINUOUS && SCIPvarGetType(consdata->bilinterms[i].var2) < SCIP_VARTYPE_CONTINUOUS )
4217  integral = integral && SCIPisIntegral(scip, consdata->bilinterms[i].coef);
4218  else
4219  integral = FALSE;
4220  }
4221  }
4222 
4223  /* call the upgrading methods */
4224 
4225  SCIPdebugMsg(scip, "upgrading quadratic constraint <%s> (%d upgrade methods):\n",
4226  SCIPconsGetName(cons), conshdlrdata->nquadconsupgrades);
4227  SCIPdebugMsg(scip, " binlin=%d binquad=%d intlin=%d intquad=%d impllin=%d implquad=%d contlin=%d contquad=%d integral=%u\n",
4228  nbinlin, nbinquad, nintlin, nintquad, nimpllin, nimplquad, ncontlin, ncontquad, integral);
4229  SCIPdebugPrintCons(scip, cons, NULL);
4230 
4231  /* try all upgrading methods in priority order in case the upgrading step is enable */
4232  for( i = 0; i < conshdlrdata->nquadconsupgrades; ++i )
4233  {
4234  if( !conshdlrdata->quadconsupgrades[i]->active )
4235  continue;
4236 
4237  SCIP_CALL( conshdlrdata->quadconsupgrades[i]->quadconsupgd(scip, cons,
4238  nbinlin, nbinquad, nintlin, nintquad, nimpllin, nimplquad, ncontlin, ncontquad, integral,
4239  &nupgdconss_, upgdconss, upgdconsssize, presoltiming) );
4240 
4241  while( nupgdconss_ < 0 )
4242  {
4243  /* upgrade function requires more memory: resize upgdconss and call again */
4244  assert(-nupgdconss_ > upgdconsssize);
4245  upgdconsssize = -nupgdconss_;
4246  SCIP_CALL( SCIPreallocBufferArray(scip, &upgdconss, -nupgdconss_) );
4247 
4248  SCIP_CALL( conshdlrdata->quadconsupgrades[i]->quadconsupgd(scip, cons,
4249  nbinlin, nbinquad, nintlin, nintquad, nimpllin, nimplquad, ncontlin, ncontquad, integral,
4250  &nupgdconss_, upgdconss, upgdconsssize, presoltiming) );
4251 
4252  assert(nupgdconss_ != 0);
4253  }
4254 
4255  if( nupgdconss_ > 0 )
4256  {
4257  /* got upgrade */
4258  SCIPdebugPrintCons(scip, cons, NULL);
4259  SCIPdebugMsg(scip, " -> upgraded to %d constraints:\n", nupgdconss_);
4260 
4261  /* add the upgraded constraints to the problem and forget them */
4262  for( j = 0; j < nupgdconss_; ++j )
4263  {
4264  SCIPdebugMsgPrint(scip, "\t");
4265  SCIPdebugPrintCons(scip, upgdconss[j], NULL);
4266 
4267  SCIP_CALL( SCIPaddCons(scip, upgdconss[j]) ); /*lint !e613*/
4268  SCIP_CALL( SCIPreleaseCons(scip, &upgdconss[j]) ); /*lint !e613*/
4269  }
4270 
4271  /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
4272  *nupgdconss += 1;
4273  *naddconss += nupgdconss_ - 1;
4274  *upgraded = TRUE;
4275 
4276  /* delete upgraded constraint */
4277  SCIPdebugMsg(scip, "delete constraint <%s> after upgrade\n", SCIPconsGetName(cons));
4278  SCIP_CALL( SCIPdelCons(scip, cons) );
4279 
4280  break;
4281  }
4282  }
4283 
4284  SCIPfreeBufferArray(scip, &upgdconss);
4285 
4286  return SCIP_OKAY;
4287 }
4288 
4289 /** helper function for presolveDisaggregate */
4290 static
4292  SCIP* scip, /**< SCIP data structure */
4293  SCIP_CONSDATA* consdata, /**< constraint data */
4294  int quadvaridx, /**< index of quadratic variable to mark */
4295  SCIP_HASHMAP* var2component, /**< variables to components mapping */
4296  int componentnr, /**< the component number to mark to */
4297  int* componentsize /**< buffer to store size of component (incremented by 1) */
4298  )
4299 {
4300  SCIP_QUADVARTERM* quadvarterm;
4301  SCIP_VAR* othervar;
4302  int othervaridx;
4303  int i;
4304 
4305  assert(consdata != NULL);
4306  assert(quadvaridx >= 0);
4307  assert(quadvaridx < consdata->nquadvars);
4308  assert(var2component != NULL);
4309  assert(componentnr >= 0);
4310 
4311  quadvarterm = &consdata->quadvarterms[quadvaridx];
4312 
4313  if( SCIPhashmapExists(var2component, quadvarterm->var) )
4314  {
4315  /* if we saw the variable before, then it should have the same component number */
4316  assert((int)(size_t)SCIPhashmapGetImage(var2component, quadvarterm->var) == componentnr);
4317  return SCIP_OKAY;
4318  }
4319 
4320  /* assign component number to variable */
4321  SCIP_CALL( SCIPhashmapInsert(var2component, quadvarterm->var, (void*)(size_t)componentnr) );
4322  ++*componentsize;
4323 
4324  /* assign same component number to all variables this variable is multiplied with */
4325  for( i = 0; i < quadvarterm->nadjbilin; ++i )
4326  {
4327  othervar = consdata->bilinterms[quadvarterm->adjbilin[i]].var1 == quadvarterm->var ?
4328  consdata->bilinterms[quadvarterm->adjbilin[i]].var2 : consdata->bilinterms[quadvarterm->adjbilin[i]].var1;
4329  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, othervar, &othervaridx) );
4330  assert(othervaridx >= 0);
4331  SCIP_CALL( presolveDisaggregateMarkComponent(scip, consdata, othervaridx, var2component, componentnr, componentsize) );
4332  }
4333 
4334  return SCIP_OKAY;
4335 }
4336 
4337 /** merges components in variables connectivity graph */
4338 static
4340  SCIP* scip, /**< SCIP data structure */
4341  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
4342  SCIP_HASHMAP* var2component, /**< variables to component mapping */
4343  int nvars, /**< number of variables */
4344  int* ncomponents, /**< number of components */
4345  int* componentssize /**< size of components */
4346 )
4347 {
4348  SCIP_CONSHDLRDATA* conshdlrdata;
4349  SCIP_HASHMAPENTRY* entry;
4350  int maxncomponents;
4351  int* oldcompidx;
4352  int* newcompidx;
4353  int i;
4354  int oldcomponent;
4355  int newcomponent;
4356 
4357  assert(scip != NULL);
4358  assert(conshdlr != NULL);
4359  assert(var2component != NULL);
4360  assert(ncomponents != NULL);
4361  assert(componentssize != NULL);
4362 
4363  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4364  assert(conshdlrdata != NULL);
4365 
4366  maxncomponents = conshdlrdata->maxdisaggrsize;
4367  assert(maxncomponents > 0);
4368 
4369  /* if already not too many components, then nothing to do */
4370  if( *ncomponents <= maxncomponents )
4371  return SCIP_OKAY;
4372 
4373  /*
4374  printf("component sizes before:");
4375  for( i = 0; i < *ncomponents; ++i )
4376  printf(" %d", componentssize[i]);
4377  printf("\n");
4378  */
4379 
4380  SCIP_CALL( SCIPallocBufferArray(scip, &oldcompidx, *ncomponents) );
4381  SCIP_CALL( SCIPallocBufferArray(scip, &newcompidx, *ncomponents) );
4382 
4383  for( i = 0; i < *ncomponents; ++i )
4384  oldcompidx[i] = i;
4385 
4386  switch( conshdlrdata->disaggrmergemethod )
4387  {
4388  case 's' :
4389  /* sort components by size, increasing order */
4390  SCIPsortIntInt(componentssize, oldcompidx, *ncomponents);
4391  break;
4392  case 'b' :
4393  case 'm' :
4394  /* sort components by size, decreasing order */
4395  SCIPsortDownIntInt(componentssize, oldcompidx, *ncomponents);
4396  break;
4397  default :
4398  SCIPerrorMessage("invalid value for constraints/quadratic/disaggrmergemethod parameter");
4399  return SCIP_PARAMETERWRONGVAL;
4400  }
4401 
4402  SCIPdebugMsg(scip, "%-30s: % 4d components of size % 4d to % 4d, median: % 4d\n", SCIPgetProbName(scip), *ncomponents, componentssize[0], componentssize[*ncomponents-1], componentssize[*ncomponents/2]);
4403 
4404  if( conshdlrdata->disaggrmergemethod == 'm' )
4405  {
4406  SCIP_Real targetsize;
4407  int count = 0;
4408 
4409  /* a minimal component size we should reach to have all components roughly the same size */
4410  targetsize = nvars / maxncomponents; /*lint !e653*/
4411  for( i = 0; i < *ncomponents; ++i )
4412  {
4413  newcompidx[oldcompidx[i]] = i;
4414  count += componentssize[i];
4415 
4416  /* fill with small components until we reach targetsize
4417  * Since targetsize might be fractional, we also add another component if
4418  * the number of variables remaining (=nvars-count) is larger than
4419  * what we expect to put into the remaining components (=targetsize * (maxncomponents - i-1)).
4420  * Thus, from time to time, a component is made larger than the targetsize to avoid
4421  * having to add much into the last component.
4422  */
4423  while( i < *ncomponents-1 && (componentssize[i] + componentssize[*ncomponents-1] <= targetsize ||
4424  nvars - count > targetsize * (maxncomponents - i)) )
4425  {
4426  /* map last (=smallest) component to component i */
4427  newcompidx[oldcompidx[*ncomponents-1]] = i;
4428 
4429  /* increase size of component i accordingly */
4430  componentssize[i] += componentssize[*ncomponents-1];
4431  count += componentssize[*ncomponents-1];
4432 
4433  /* forget about last component */
4434  --*ncomponents;
4435  }
4436  }
4437  assert(count == nvars);
4438  }
4439  else
4440  {
4441  /* get inverse permutation */
4442  for( i = 0; i < *ncomponents; ++i )
4443  newcompidx[oldcompidx[i]] = i;
4444  }
4445 
4446  /* assign new component numbers to variables, cutting off at maxncomponents */
4447  for( i = 0; i < SCIPhashmapGetNEntries(var2component); ++i )
4448  {
4449  entry = SCIPhashmapGetEntry(var2component, i);
4450  if( entry == NULL )
4451  continue;
4452 
4453  oldcomponent = (int)(size_t)SCIPhashmapEntryGetImage(entry);
4454 
4455  newcomponent = newcompidx[oldcomponent];
4456  if( newcomponent >= maxncomponents )
4457  {
4458  newcomponent = maxncomponents-1;
4459  ++componentssize[maxncomponents-1];
4460  }
4461 
4462  SCIPhashmapEntrySetImage(entry, (void*)(size_t)newcomponent); /*lint !e571*/
4463  }
4464  if( *ncomponents > maxncomponents )
4465  *ncomponents = maxncomponents;
4466 
4467  /*
4468  printf("component sizes after :");
4469  for( i = 0; i < *ncomponents; ++i )
4470  printf(" %d", componentssize[i]);
4471  printf("\n");
4472  */
4473 
4474  SCIPfreeBufferArray(scip, &newcompidx);
4475  SCIPfreeBufferArray(scip, &oldcompidx);
4476 
4477  return SCIP_OKAY;
4478 }
4479 
4480 /** compute the next highest power of 2 for a 32-bit argument
4481  *
4482  * Source: https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
4483  *
4484  * @note Returns 0 for v=0.
4485  */
4486 static
4487 unsigned int nextPowerOf2(
4488  unsigned int v /**< input */
4489  )
4490 {
4491  v--;
4492  v |= v >> 1;
4493  v |= v >> 2;
4494  v |= v >> 4;
4495  v |= v >> 8;
4496  v |= v >> 16;
4497  v++;
4498 
4499  return v;
4500 }
4501 
4502 
4503 /** for quadratic constraints that consists of a sum of quadratic terms, disaggregates the sum into a set of constraints by introducing auxiliary variables
4504  *
4505  * Assume the quadratic constraint can be written in the form
4506  * lhs <= b'x + sum_{k=1..p} q_k(x_k) <= rhs
4507  * where x_k denotes a subset of the variables in x and these subsets are pairwise disjunct
4508  * and q_k(.) is a quadratic form.
4509  * p is selected as large as possible, but to be <= conshdlrdata->maxdisaggrsize.
4510  *
4511  * Without additional scaling, the constraint is disaggregated into
4512  * lhs <= b'x + sum_k c_k z_k <= rhs
4513  * c_k z_k ~ q_k(x)
4514  * where "~" is either "<=", "==", or ">=", depending on whether lhs or rhs are infinite.
4515  * Further, c_k is chosen to be the maximal absolute value of the coefficients of the quadratic terms in q_k(x).
4516  * This is done to ensure that z_k takes values with a similar magnitute as the variables in x_k (better for separation).
4517  *
4518  * However, a solution of this disaggregated system can violate the original constraint by (p+1)*epsilon
4519  * (assuming unscaled violations are used, which is the default).
4520  * Therefore, all constraints are scaled by p+1:
4521  * (p+1)*lhs <= (p+1)*b'x + (p+1) * sum_k c_k z_k <= (p+1) * rhs
4522  * (p+1)*c_k z_k ~ (p+1)*q_k(x)
4523  */
4524 static
4526  SCIP* scip, /**< SCIP data structure */
4527  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
4528  SCIP_CONS* cons, /**< source constraint to try to convert */
4529  int* naddconss /**< pointer to counter of added constraints */
4530  )
4531 {
4532  SCIP_CONSDATA* consdata;
4533  SCIP_HASHMAP* var2component;
4534  int* componentssize;
4535  int ncomponents;
4536  int i;
4537  int comp;
4538  SCIP_CONS** auxconss;
4539  SCIP_VAR** auxvars;
4540  SCIP_Real* auxcoefs;
4541 #ifdef WITH_DEBUG_SOLUTION
4542  SCIP_Real* auxsolvals; /* value of auxiliary variable in debug solution */
4543 #endif
4544  SCIP_Real scale;
4545  char name[SCIP_MAXSTRLEN];
4546 
4547  assert(scip != NULL);
4548  assert(conshdlr != NULL);
4549  assert(cons != NULL);
4550  assert(naddconss != NULL);
4551 
4552  consdata = SCIPconsGetData(cons);
4553  assert(consdata != NULL);
4554 
4555  /* skip if constraint has been already disaggregated */
4556  if( consdata->isdisaggregated )
4557  return SCIP_OKAY;
4558 
4559  consdata->isdisaggregated = TRUE;
4560 
4561  /* make sure there are no quadratic variables without coefficients */
4562  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
4563  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, cons) );
4564 
4565  if( consdata->nquadvars <= 1 )
4566  return SCIP_OKAY;
4567 
4568  /* sort quadratic variable terms here, so we can later search in it without reordering the array */
4569  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
4570 
4571  /* check how many quadratic terms with non-overlapping variables we have
4572  * in other words, the number of components in the sparsity graph of the quadratic term matrix
4573  */
4574  ncomponents = 0;
4575  SCIP_CALL( SCIPhashmapCreate(&var2component, SCIPblkmem(scip), consdata->nquadvars) );
4576  SCIP_CALL( SCIPallocBufferArray(scip, &componentssize, consdata->nquadvars) );
4577  for( i = 0; i < consdata->nquadvars; ++i )
4578  {
4579  /* if variable was marked already, skip it */
4580  if( SCIPhashmapExists(var2component, (void*)consdata->quadvarterms[i].var) )
4581  continue;
4582 
4583  /* start a new component with variable i */
4584  componentssize[ncomponents] = 0;
4585  SCIP_CALL( presolveDisaggregateMarkComponent(scip, consdata, i, var2component, ncomponents, componentssize + ncomponents) );
4586  ++ncomponents;
4587  }
4588 
4589  assert(ncomponents >= 1);
4590 
4591  /* if there is only one component, we cannot disaggregate
4592  * @todo we could still split the constraint into several while keeping the number of variables sharing several constraints as small as possible
4593  */
4594  if( ncomponents == 1 )
4595  {
4596  SCIPhashmapFree(&var2component);
4597  SCIPfreeBufferArray(scip, &componentssize);
4598  return SCIP_OKAY;
4599  }
4600 
4601  /* merge some components, if necessary */
4602  SCIP_CALL( presolveDisaggregateMergeComponents(scip, conshdlr, var2component, consdata->nquadvars, &ncomponents, componentssize) );
4603 
4604  SCIPfreeBufferArray(scip, &componentssize);
4605 
4606  /* scale all new constraints (ncomponents+1 many) by ncomponents+1 (or its next power of 2), so violations sum up to at most epsilon */
4607  scale = nextPowerOf2((unsigned int)ncomponents + 1);
4608 
4609  SCIP_CALL( SCIPallocBufferArray(scip, &auxconss, ncomponents) );
4610  SCIP_CALL( SCIPallocBufferArray(scip, &auxvars, ncomponents) );
4611  SCIP_CALL( SCIPallocBufferArray(scip, &auxcoefs, ncomponents) );
4612 #ifdef WITH_DEBUG_SOLUTION
4613  SCIP_CALL( SCIPallocClearBufferArray(scip, &auxsolvals, ncomponents) );
4614 #endif
4615 
4616  /* create auxiliary variables and empty constraints for each component */
4617  for( comp = 0; comp < ncomponents; ++comp )
4618  {
4619  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_comp%d", SCIPconsGetName(cons), comp);
4620 
4621  SCIP_CALL( SCIPcreateVar(scip, &auxvars[comp], name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
4622  SCIP_VARTYPE_CONTINUOUS, SCIPconsIsInitial(cons), FALSE, NULL, NULL, NULL, NULL, NULL) );
4623 
4624  SCIP_CALL( SCIPcreateConsQuadratic2(scip, &auxconss[comp], name, 0, NULL, NULL, 0, NULL, 0, NULL,
4625  (SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : 0.0),
4626  (SCIPisInfinity(scip, consdata->rhs) ? SCIPinfinity(scip) : 0.0),
4629  SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons)) );
4630 
4631  auxcoefs[comp] = SCIPinfinity(scip);
4632  }
4633 
4634  /* add quadratic variables to each component constraint
4635  * delete adjacency information */
4636  for( i = 0; i < consdata->nquadvars; ++i )
4637  {
4638  assert(SCIPhashmapExists(var2component, consdata->quadvarterms[i].var));
4639 
4640  comp = (int)(size_t) SCIPhashmapGetImage(var2component, consdata->quadvarterms[i].var);
4641  assert(comp >= 0);
4642  assert(comp < ncomponents);
4643 
4644  /* add variable term to corresponding constraint */
4645  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, auxconss[comp], consdata->quadvarterms[i].var, scale * consdata->quadvarterms[i].lincoef, scale * consdata->quadvarterms[i].sqrcoef) );
4646 
4647  /* reduce coefficient of aux variable */
4648  if( !SCIPisZero(scip, consdata->quadvarterms[i].lincoef) && ABS(consdata->quadvarterms[i].lincoef) < auxcoefs[comp] )
4649  auxcoefs[comp] = REALABS(consdata->quadvarterms[i].lincoef);
4650  if( !SCIPisZero(scip, consdata->quadvarterms[i].sqrcoef) && ABS(consdata->quadvarterms[i].sqrcoef) < auxcoefs[comp] )
4651  auxcoefs[comp] = REALABS(consdata->quadvarterms[i].sqrcoef);
4652 
4653  SCIPfreeBlockMemoryArray(scip, &consdata->quadvarterms[i].adjbilin, consdata->quadvarterms[i].adjbilinsize);
4654  consdata->quadvarterms[i].nadjbilin = 0;
4655  consdata->quadvarterms[i].adjbilinsize = 0;
4656 
4657 #ifdef WITH_DEBUG_SOLUTION
4658  if( SCIPdebugIsMainscip(scip) )
4659  {
4660  SCIP_Real debugvarval;
4661 
4662  SCIP_CALL( SCIPdebugGetSolVal(scip, consdata->quadvarterms[i].var, &debugvarval) );
4663  auxsolvals[comp] += consdata->quadvarterms[i].lincoef * debugvarval + consdata->quadvarterms[i].sqrcoef * debugvarval * debugvarval;
4664  }
4665 #endif
4666  }
4667 
4668  /* add bilinear terms to each component constraint */
4669  for( i = 0; i < consdata->nbilinterms; ++i )
4670  {
4671  assert(SCIPhashmapExists(var2component, consdata->bilinterms[i].var1));
4672  assert(SCIPhashmapExists(var2component, consdata->bilinterms[i].var2));
4673 
4674  comp = (int)(size_t) SCIPhashmapGetImage(var2component, consdata->bilinterms[i].var1);
4675  assert(comp == (int)(size_t) SCIPhashmapGetImage(var2component, consdata->bilinterms[i].var2));
4676  assert(!SCIPisZero(scip, consdata->bilinterms[i].coef));
4677 
4678  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, auxconss[comp],
4679  consdata->bilinterms[i].var1, consdata->bilinterms[i].var2, scale * consdata->bilinterms[i].coef) );
4680 
4681  if( ABS(consdata->bilinterms[i].coef) < auxcoefs[comp] )
4682  auxcoefs[comp] = ABS(consdata->bilinterms[i].coef);
4683 
4684 #ifdef WITH_DEBUG_SOLUTION
4685  if( SCIPdebugIsMainscip(scip) )
4686  {
4687  SCIP_Real debugvarval1;
4688  SCIP_Real debugvarval2;
4689 
4690  SCIP_CALL( SCIPdebugGetSolVal(scip, consdata->bilinterms[i].var1, &debugvarval1) );
4691  SCIP_CALL( SCIPdebugGetSolVal(scip, consdata->bilinterms[i].var2, &debugvarval2) );
4692  auxsolvals[comp] += consdata->bilinterms[i].coef * debugvarval1 * debugvarval2;
4693  }
4694 #endif
4695  }
4696 
4697  /* forget about bilinear terms in cons */
4698  SCIPfreeBlockMemoryArray(scip, &consdata->bilinterms, consdata->bilintermssize);
4699  consdata->nbilinterms = 0;
4700  consdata->bilintermssize = 0;
4701 
4702  /* remove quadratic variable terms from cons */
4703  for( i = consdata->nquadvars - 1; i >= 0; --i )
4704  {
4705  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
4706  }
4707  assert(consdata->nquadvars == 0);
4708 
4709  /* scale remaining linear variables and sides by scale */
4710  for( i = 0; i < consdata->nlinvars; ++i )
4711  {
4712  SCIP_CALL( chgLinearCoefPos(scip, cons, i, scale * consdata->lincoefs[i]) );
4713  }
4714  if( !SCIPisInfinity(scip, -consdata->lhs) )
4715  {
4716  consdata->lhs *= scale;
4717  assert(!SCIPisInfinity(scip, -consdata->lhs) );
4718  }
4719  if( !SCIPisInfinity(scip, consdata->rhs) )
4720  {
4721  consdata->rhs *= scale;
4722  assert(!SCIPisInfinity(scip, consdata->rhs) );
4723  }
4724 
4725  /* add auxiliary variables to auxiliary constraints
4726  * add aux vars and constraints to SCIP
4727  * add aux vars to this constraint
4728  * set value of aux vars in debug solution, if any
4729  */
4730  SCIPdebugMsg(scip, "add %d constraints for disaggregation of quadratic constraint <%s>\n", ncomponents, SCIPconsGetName(cons));
4731  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars + ncomponents) );
4732  for( comp = 0; comp < ncomponents; ++comp )
4733  {
4734  SCIP_CONSDATA* auxconsdata;
4735 
4736  SCIP_CALL( SCIPaddLinearVarQuadratic(scip, auxconss[comp], auxvars[comp], -scale * auxcoefs[comp]) );
4737 
4738  SCIP_CALL( SCIPaddVar(scip, auxvars[comp]) );
4739 
4740  SCIP_CALL( SCIPaddCons(scip, auxconss[comp]) );
4741  SCIPdebugPrintCons(scip, auxconss[comp], NULL);
4742 
4743  SCIP_CALL( addLinearCoef(scip, cons, auxvars[comp], scale * auxcoefs[comp]) );
4744 
4745  /* mark that the constraint should not further be disaggregated */
4746  auxconsdata = SCIPconsGetData(auxconss[comp]);
4747  assert(auxconsdata != NULL);
4748  auxconsdata->isdisaggregated = TRUE;
4749 
4750 #ifdef WITH_DEBUG_SOLUTION
4751  if( SCIPdebugIsMainscip(scip) )
4752  {
4753  /* auxvar should take value from auxsolvals in debug solution, but we also scaled auxvar by auxcoefs[comp] */
4754  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvars[comp], auxsolvals[comp] / auxcoefs[comp]) );
4755  }
4756 #endif
4757 
4758  SCIP_CALL( SCIPreleaseCons(scip, &auxconss[comp]) );
4759  SCIP_CALL( SCIPreleaseVar(scip, &auxvars[comp]) );
4760  }
4761  *naddconss += ncomponents;
4762 
4763  SCIPdebugPrintCons(scip, cons, NULL);
4764 
4765  SCIPfreeBufferArray(scip, &auxconss);
4766  SCIPfreeBufferArray(scip, &auxvars);
4767  SCIPfreeBufferArray(scip, &auxcoefs);
4768 #ifdef WITH_DEBUG_SOLUTION
4769  SCIPfreeBufferArray(scip, &auxsolvals);
4770 #endif
4771  SCIPhashmapFree(&var2component);
4772 
4773  return SCIP_OKAY;
4774 }
4775 
4776 #ifdef CHECKIMPLINBILINEAR
4777 /** checks if there are bilinear terms x*y with a binary variable x and an implication x = {0,1} -> y = 0
4778  *
4779  * In this case, the bilinear term can be removed (x=0 case) or replaced by y (x=1 case).
4780  */
4781 static
4782 SCIP_RETCODE presolveApplyImplications(
4783  SCIP* scip, /**< SCIP data structure */
4784  SCIP_CONS* cons, /**< quadratic constraint */
4785  int* nbilinremoved /**< buffer to store number of removed bilinear terms */
4786  )
4787 {
4788  SCIP_CONSDATA* consdata;
4789  SCIP_VAR* x;
4790  SCIP_VAR* y;
4791  SCIP_INTERVAL implbnds;
4792  int i;
4793  int j;
4794  int k;
4795 
4796  assert(scip != NULL);
4797  assert(cons != NULL);
4798  assert(nbilinremoved != NULL);
4799 
4800  *nbilinremoved = 0;
4801 
4802  consdata = SCIPconsGetData(cons);
4803  assert(consdata != NULL);
4804 
4805  SCIPdebugMsg(scip, "apply implications in <%s>\n", SCIPconsGetName(cons));
4806 
4807  /* sort quadvarterms in case we need to search */
4808  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
4809 
4810  for( i = 0; i < consdata->nquadvars; ++i )
4811  {
4812  x = consdata->quadvarterms[i].var;
4813  assert(x != NULL);
4814 
4815  if( consdata->quadvarterms[i].nadjbilin == 0 )
4816  continue;
4817 
4818  if( !SCIPvarIsBinary(x) )
4819  continue;
4820 
4821  if( !SCIPvarIsActive(x) )
4822  continue;
4823 
4824  if( SCIPvarGetNImpls(x, TRUE) == 0 && SCIPvarGetNImpls(x, FALSE) == 0 )
4825  continue;
4826 
4827  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
4828  {
4829  k = consdata->quadvarterms[i].adjbilin[j];
4830  assert(k >= 0);
4831  assert(k < consdata->nbilinterms);
4832 
4833  if( consdata->bilinterms[k].coef == 0.0 )
4834  continue;
4835 
4836  y = consdata->bilinterms[k].var1 == x ? consdata->bilinterms[k].var2 : consdata->bilinterms[k].var1;
4837  assert(x != y);
4838 
4839  SCIP_CALL( getImpliedBounds(scip, x, TRUE, y, &implbnds) );
4840  if( SCIPisZero(scip, implbnds.inf) && SCIPisZero(scip, implbnds.sup) )
4841  {
4842  /* if x = 1 implies y = 0, then we can remove the bilinear term x*y, since it is always 0
4843  * we only set the coefficient to 0.0 here and mark the bilinterms as not merged */
4844  SCIPdebugMsg(scip, "remove bilinear term %g<%s><%s> from <%s> due to implication\n", consdata->bilinterms[k].coef, SCIPvarGetName(x), SCIPvarGetName(y), SCIPconsGetName(cons));
4845  consdata->bilinterms[k].coef = 0.0;
4846  consdata->bilinmerged = FALSE;
4847  ++*nbilinremoved;
4848  continue;
4849  }
4850 
4851  SCIP_CALL( getImpliedBounds(scip, x, FALSE, y, &implbnds) );
4852  if( SCIPisZero(scip, implbnds.inf) && SCIPisZero(scip, implbnds.sup) )
4853  {
4854  /* if x = 0 implies y = 0, then we can replace the bilinear term x*y by y
4855  * we only move the coefficient to the linear coef of y here and mark the bilinterms as not merged */
4856  SCIPdebugMsg(scip, "replace bilinear term %g<%s><%s> by %g<%s> in <%s> due to implication\n", consdata->bilinterms[k].coef, SCIPvarGetName(x), SCIPvarGetName(y), consdata->bilinterms[k].coef, SCIPvarGetName(y), SCIPconsGetName(cons));
4857  assert(consdata->quadvarssorted);
4858  SCIP_CALL( SCIPaddQuadVarLinearCoefQuadratic(scip, cons, y, consdata->bilinterms[k].coef) );
4859  consdata->bilinterms[k].coef = 0.0;
4860  consdata->bilinmerged = FALSE;
4861  ++*nbilinremoved;
4862  }
4863  }
4864  }
4865 
4866  if( *nbilinremoved > 0 )
4867  {
4868  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
4869 
4870  /* invalidate nonlinear row */
4871  if( consdata->nlrow != NULL )
4872  {
4873  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
4874  }
4875 
4876  consdata->ispropagated = FALSE;
4877  consdata->ispresolved = FALSE;
4878  consdata->iscurvchecked = FALSE;
4879  }
4880 
4881  consdata->isimpladded = FALSE;
4882 
4883  return SCIP_OKAY;
4884 }
4885 #endif
4886 
4887 /** checks a quadratic constraint for convexity and/or concavity without checking multivariate functions */
4888 static
4889 void checkCurvatureEasy(
4890  SCIP* scip, /**< SCIP data structure */
4891  SCIP_CONS* cons, /**< quadratic constraint */
4892  SCIP_Bool* determined, /**< pointer to store whether the curvature could be determined */
4893  SCIP_Bool checkmultivariate /**< whether curvature will be checked later on for multivariate functions */
4894  )
4895 {
4896  SCIP_CONSDATA* consdata;
4897  int nquadvars;
4898 
4899  assert(scip != NULL);
4900  assert(cons != NULL);
4901  assert(determined != NULL);
4902 
4903  consdata = SCIPconsGetData(cons);
4904  assert(consdata != NULL);
4905 
4906  nquadvars = consdata->nquadvars;
4907  *determined = TRUE;
4908 
4909  if( consdata->iscurvchecked )
4910  return;
4911 
4912  SCIPdebugMsg(scip, "Checking curvature of constraint <%s> without multivariate functions\n", SCIPconsGetName(cons));
4913 
4914  consdata->maxnonconvexity = 0.0;
4915  if( nquadvars == 1 )
4916  {
4917  assert(consdata->nbilinterms == 0);
4918  consdata->isconvex = !SCIPisNegative(scip, consdata->quadvarterms[0].sqrcoef);
4919  consdata->isconcave = !SCIPisPositive(scip, consdata->quadvarterms[0].sqrcoef);
4920  consdata->iscurvchecked = TRUE;
4921 
4922  if( !SCIPisInfinity(scip, -consdata->lhs) && consdata->quadvarterms[0].sqrcoef > 0.0 )
4923  consdata->maxnonconvexity = consdata->quadvarterms[0].sqrcoef;
4924  if( !SCIPisInfinity(scip, consdata->rhs) && consdata->quadvarterms[0].sqrcoef < 0.0 )
4925  consdata->maxnonconvexity = -consdata->quadvarterms[0].sqrcoef;
4926  }
4927  else if( nquadvars == 0 )
4928  {
4929  consdata->isconvex = TRUE;
4930  consdata->isconcave = TRUE;
4931  consdata->iscurvchecked = TRUE;
4932  }
4933  else if( consdata->nbilinterms == 0 )
4934  {
4935  int v;
4936 
4937  consdata->isconvex = TRUE;
4938  consdata->isconcave = TRUE;
4939 
4940  for( v = nquadvars - 1; v >= 0; --v )
4941  {
4942  consdata->isconvex = consdata->isconvex && !SCIPisNegative(scip, consdata->quadvarterms[v].sqrcoef);
4943  consdata->isconcave = consdata->isconcave && !SCIPisPositive(scip, consdata->quadvarterms[v].sqrcoef);
4944 
4945  if( !SCIPisInfinity(scip, -consdata->lhs) && consdata->quadvarterms[v].sqrcoef > consdata->maxnonconvexity )
4946  consdata->maxnonconvexity = consdata->quadvarterms[0].sqrcoef;
4947  if( !SCIPisInfinity(scip, consdata->rhs) && -consdata->quadvarterms[v].sqrcoef > consdata->maxnonconvexity )
4948  consdata->maxnonconvexity = -consdata->quadvarterms[0].sqrcoef;
4949  }
4950 
4951  consdata->iscurvchecked = TRUE;
4952  }
4953  else if( !checkmultivariate )
4954  {
4955  consdata->isconvex = FALSE;
4956  consdata->isconcave = FALSE;
4957  consdata->iscurvchecked = TRUE;
4958  consdata->maxnonconvexity = SCIPinfinity(scip);
4959  }
4960  else
4961  *determined = FALSE;
4962 }
4963 
4964 /** checks a quadratic constraint for convexity and/or concavity */
4965 static
4967  SCIP* scip, /**< SCIP data structure */
4968  SCIP_CONS* cons, /**< quadratic constraint */
4969  SCIP_Bool checkmultivariate /**< whether curvature should also be checked for multivariate functions */
4970  )
4971 {
4972  SCIP_CONSDATA* consdata;
4973  double* matrix;
4974  SCIP_HASHMAP* var2index;
4975  int i;
4976  int n;
4977  int nn;
4978  int row;
4979  int col;
4980  double* alleigval;
4981  SCIP_Bool determined;
4982 
4983  assert(scip != NULL);
4984  assert(cons != NULL);
4985 
4986  consdata = SCIPconsGetData(cons);
4987  assert(consdata != NULL);
4988 
4989  n = consdata->nquadvars;
4990 
4991  if( consdata->iscurvchecked )
4992  return SCIP_OKAY;
4993 
4994  /* easy checks for curvature detection */
4995  checkCurvatureEasy(scip, cons, &determined, checkmultivariate);
4996 
4997  /* if curvature was already detected stop */
4998  if( determined )
4999  {
5000  return SCIP_OKAY;
5001  }
5002 
5003  SCIPdebugMsg(scip, "Checking curvature of constraint <%s> with multivariate functions\n", SCIPconsGetName(cons));
5004 
5005  if( n == 2 )
5006  {
5007  SCIP_Real tracehalf;
5008  SCIP_Real discriminantroot;
5009 
5010  /* compute eigenvalues by hand */
5011  assert(consdata->nbilinterms == 1);
5012  consdata->isconvex =
5013  consdata->quadvarterms[0].sqrcoef >= 0 &&
5014  consdata->quadvarterms[1].sqrcoef >= 0 &&
5015  4 * consdata->quadvarterms[0].sqrcoef * consdata->quadvarterms[1].sqrcoef >= consdata->bilinterms[0].coef * consdata->bilinterms[0].coef;
5016  consdata->isconcave =
5017  consdata->quadvarterms[0].sqrcoef <= 0 &&
5018  consdata->quadvarterms[1].sqrcoef <= 0 &&
5019  4 * consdata->quadvarterms[0].sqrcoef * consdata->quadvarterms[1].sqrcoef >= consdata->bilinterms[0].coef * consdata->bilinterms[0].coef;
5020 
5021  /* store largest eigenvalue causing nonconvexity according to sides */
5022  tracehalf = (consdata->quadvarterms[0].sqrcoef + consdata->quadvarterms[1].sqrcoef) / 2.0;
5023  discriminantroot = consdata->quadvarterms[0].sqrcoef * consdata->quadvarterms[1].sqrcoef - SQR(consdata->bilinterms[0].coef / 2.0);
5024  discriminantroot = SQR(tracehalf) - discriminantroot;
5025  assert(!SCIPisNegative(scip, discriminantroot));
5026  discriminantroot = SQRT(MAX(0.0, discriminantroot));
5027 
5028  consdata->maxnonconvexity = 0.0;
5029  if( !SCIPisInfinity(scip, -consdata->lhs) )
5030  consdata->maxnonconvexity = MAX(consdata->maxnonconvexity, tracehalf + discriminantroot);
5031  if( !SCIPisInfinity(scip, consdata->rhs) )
5032  consdata->maxnonconvexity = MAX(consdata->maxnonconvexity, discriminantroot - tracehalf);
5033 
5034  consdata->iscurvchecked = TRUE;
5035  return SCIP_OKAY;
5036  }
5037 
5038  /* do not check curvature if n is too large */
5039  nn = n * n;
5040  if( nn < 0 || (unsigned) (int) nn > UINT_MAX / sizeof(SCIP_Real) )
5041  {
5042  SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL, "cons_quadratic - n is too large to check the curvature\n");
5043  consdata->isconvex = FALSE;
5044  consdata->isconcave = FALSE;
5045  consdata->iscurvchecked = TRUE;
5046  consdata->maxnonconvexity = SCIPinfinity(scip);
5047  return SCIP_OKAY;
5048  }
5049 
5050  /* lower triangular of quadratic term matrix */
5051  SCIP_CALL( SCIPallocBufferArray(scip, &matrix, nn) );
5052  BMSclearMemoryArray(matrix, nn);
5053 
5054  consdata->isconvex = TRUE;
5055  consdata->isconcave = TRUE;
5056  consdata->maxnonconvexity = 0.0;
5057 
5058  SCIP_CALL( SCIPhashmapCreate(&var2index, SCIPblkmem(scip), n) );
5059  for( i = 0; i < n; ++i )
5060  {
5061  if( consdata->quadvarterms[i].nadjbilin > 0 )
5062  {
5063  SCIP_CALL( SCIPhashmapInsert(var2index, consdata->quadvarterms[i].var, (void*)(size_t)i) );
5064  matrix[i*n + i] = consdata->quadvarterms[i].sqrcoef;
5065  }
5066  else
5067  {
5068  /* if pure square term, then update maximal nonconvex eigenvalue, as it will not be considered in lapack call below */
5069  if( !SCIPisInfinity(scip, -consdata->lhs) && consdata->quadvarterms[i].sqrcoef > consdata->maxnonconvexity )
5070  consdata->maxnonconvexity = consdata->quadvarterms[i].sqrcoef;
5071  if( !SCIPisInfinity(scip, consdata->rhs) && -consdata->quadvarterms[i].sqrcoef > consdata->maxnonconvexity )
5072  consdata->maxnonconvexity = -consdata->quadvarterms[i].sqrcoef;
5073  }
5074  /* nonzero elements on diagonal tell a lot about convexity/concavity */
5075  if( SCIPisNegative(scip, consdata->quadvarterms[i].sqrcoef) )
5076  consdata->isconvex = FALSE;
5077  if( SCIPisPositive(scip, consdata->quadvarterms[i].sqrcoef) )
5078  consdata->isconcave = FALSE;
5079  }
5080 
5081  /* skip lapack call, if we know already that we are indefinite
5082  * NOTE: this will leave out updating consdata->maxnonconvexity, so that it only provides a lower bound in this case
5083  */
5084  if( !consdata->isconvex && !consdata->isconcave )
5085  {
5086  SCIPfreeBufferArray(scip, &matrix);
5087  SCIPhashmapFree(&var2index);
5088  consdata->iscurvchecked = TRUE;
5089  /* make sure that maxnonconvexity is strictly different from zero if nonconvex
5090  * TODO one could think about doing some eigenvalue estimation here (Gershgorin)
5091  */
5092  consdata->maxnonconvexity = MAX(1000.0, consdata->maxnonconvexity);
5093  return SCIP_OKAY;
5094  }
5095 
5097  {
5098  for( i = 0; i < consdata->nbilinterms; ++i )
5099  {
5100  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var1));
5101  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var2));
5102  row = (int)(size_t)SCIPhashmapGetImage(var2index, consdata->bilinterms[i].var1);
5103  col = (int)(size_t)SCIPhashmapGetImage(var2index, consdata->bilinterms[i].var2);
5104  if( row < col )
5105  matrix[row * n + col] = consdata->bilinterms[i].coef/2;
5106  else
5107  matrix[col * n + row] = consdata->bilinterms[i].coef/2;
5108  }
5109 
5110  SCIP_CALL( SCIPallocBufferArray(scip, &alleigval, n) );
5111  /* @todo Can we compute only min and max eigen value?
5112  * @todo Can we estimate the numerical error?
5113  * @todo Trying a cholesky factorization may be much faster.
5114  */
5115  if( LapackDsyev(FALSE, n, matrix, alleigval) != SCIP_OKAY )
5116  {
5117  SCIPwarningMessage(scip, "Failed to compute eigenvalues of quadratic coefficient matrix of constraint %s. Assuming matrix is indefinite.\n", SCIPconsGetName(cons));
5118  consdata->isconvex = FALSE;
5119  consdata->isconcave = FALSE;
5120  }
5121  else
5122  {
5123  /* deconvexification reformulates a stricly convex quadratic function in binaries such that it becomes not-strictly convex
5124  * by adding the -lambda*(x^2-x) terms for lambda the smallest eigenvalue of the matrix
5125  * the result is still a convex form "but less so" (ref. papers by Guignard et.al.), but with hopefully tighter value for the continuous relaxation
5126  */
5127 #ifdef DECONVEXIFY
5128  SCIP_Bool allbinary;
5129  printf("cons <%s>[%g,%g] spectrum = [%g,%g]\n", SCIPconsGetName(cons), consdata->lhs, consdata->rhs, alleigval[0], alleigval[n-1]);
5130 #endif
5131  consdata->isconvex &= !SCIPisNegative(scip, alleigval[0]); /*lint !e514*/
5132  consdata->isconcave &= !SCIPisPositive(scip, alleigval[n-1]); /*lint !e514*/
5133  consdata->iscurvchecked = TRUE;
5134 #ifdef DECONVEXIFY
5135  for( i = 0; i < consdata->nquadvars; ++i )
5136  if( !SCIPvarIsBinary(consdata->quadvarterms[i].var) )
5137  break;
5138  allbinary = i == consdata->nquadvars;
5139 
5140  if( !SCIPisInfinity(scip, consdata->rhs) && alleigval[0] > 0.1 && allbinary )
5141  {
5142  printf("deconvexify cons <%s> by shifting hessian by %g\n", SCIPconsGetName(cons), alleigval[0]);
5143  for( i = 0; i < consdata->nquadvars; ++i )
5144  {
5145  consdata->quadvarterms[i].sqrcoef -= alleigval[0];
5146  consdata->quadvarterms[i].lincoef += alleigval[0];
5147  }
5148  }
5149 
5150  if( !SCIPisInfinity(scip, consdata->lhs) && alleigval[n-1] < -0.1 && allbinary )
5151  {
5152  printf("deconcavify cons <%s> by shifting hessian by %g\n", SCIPconsGetName(cons), alleigval[n-1]);
5153  for( i = 0; i < consdata->nquadvars; ++i )
5154  {
5155  consdata->quadvarterms[i].sqrcoef -= alleigval[n-1];
5156  consdata->quadvarterms[i].lincoef += alleigval[n-1];
5157  }
5158  }
5159 #endif
5160  }
5161 
5162  /* update largest eigenvalue causing nonconvexity according to sides */
5163  if( !SCIPisInfinity(scip, -consdata->lhs) )
5164  consdata->maxnonconvexity = MAX(consdata->maxnonconvexity, alleigval[n-1]);
5165  if( !SCIPisInfinity(scip, consdata->rhs) )
5166  consdata->maxnonconvexity = MAX(consdata->maxnonconvexity, -alleigval[0]);
5167 
5168  SCIPfreeBufferArray(scip, &alleigval);
5169  }
5170  else
5171  {
5172  consdata->isconvex = FALSE;
5173  consdata->isconcave = FALSE;
5174  consdata->iscurvchecked = TRUE; /* set to TRUE since it does not help to repeat this procedure again and again (that will not bring Ipopt in) */
5175  consdata->maxnonconvexity = SCIPinfinity(scip);
5176  }
5177 
5178  SCIPhashmapFree(&var2index);
5179  SCIPfreeBufferArray(scip, &matrix);
5180 
5181  return SCIP_OKAY;
5182 }
5183 
5184 /** check whether indefinite constraint function is factorable and store corresponding coefficients */
5185 static
5187  SCIP* scip, /**< SCIP data structure */
5188  SCIP_CONS* cons /**< constraint */
5189  )
5190 {
5191  SCIP_BILINTERM* bilinterm;
5192  SCIP_CONSDATA* consdata;
5193  SCIP_Real* a;
5194  SCIP_Real* eigvals;
5195  SCIP_Real sigma1;
5196  SCIP_Real sigma2;
5197  SCIP_Bool success;
5198  int n;
5199  int i;
5200  int idx1;
5201  int idx2;
5202  int posidx;
5203  int negidx;
5204 
5205  assert(scip != NULL);
5206  assert(cons != NULL);
5207 
5208  consdata = SCIPconsGetData(cons);
5209  assert(consdata != NULL);
5210  assert(consdata->factorleft == NULL);
5211  assert(consdata->factorright == NULL);
5212 
5213  /* we don't need this if there are no bilinear terms */
5214  if( consdata->nbilinterms == 0 )
5215  return SCIP_OKAY;
5216 
5217  /* write constraint as lhs <= linear + x'^T A x' <= rhs where x' = (x,1) and
5218  * A = ( Q b/2 )
5219  * ( b^T/2 0 )
5220  * compute an eigenvalue factorization of A and check if there are one positive and one negative eigenvalue
5221  * if so, then let sigma1^2 and -sigma2^2 be these eigenvalues and v1 and v2 be the first two rows of the inverse eigenvector matrix
5222  * thus, x'^T A x' = sigma1^2 (v1^T x')^2 - sigma2^2 (v2^T x')^2
5223  * = (sigma1 (v1^T x') - sigma2 (v2^T x')) * (sigma1 (v1^T x') + sigma2 (v2^T x'))
5224  * we then store sigma1 v1^T - sigma2 v2^T as left factor coef, and sigma1 v1^T + sigma2 v2^T as right factor coef
5225  */
5226 
5227  /* if we already know that there are only positive or only negative eigenvalues, then don't try */
5228  if( consdata->iscurvchecked && (consdata->isconvex || consdata->isconcave) )
5229  return SCIP_OKAY;
5230 
5231  n = consdata->nquadvars + 1;
5232 
5233  /* @todo handle case n=3 explicitly */
5234 
5235  /* skip too large matrices */
5236  if( n > 50 )
5237  return SCIP_OKAY;
5238 
5239  /* need routine to compute eigenvalues/eigenvectors */
5240  if( !SCIPisIpoptAvailableIpopt() )
5241  return SCIP_OKAY;
5242 
5243  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
5244 
5245  SCIP_CALL( SCIPallocBufferArray(scip, &a, n*n) );
5246  BMSclearMemoryArray(a, n*n);
5247 
5248  /* set lower triangular entries of A corresponding to bilinear terms */
5249  for( i = 0; i < consdata->nbilinterms; ++i )
5250  {
5251  bilinterm = &consdata->bilinterms[i];
5252 
5253  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var1, &idx1) );
5254  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var2, &idx2) );
5255  assert(idx1 >= 0);
5256  assert(idx2 >= 0);
5257  assert(idx1 != idx2);
5258 
5259  a[MIN(idx1,idx2) * n + MAX(idx1,idx2)] = bilinterm->coef / 2.0;
5260  }
5261 
5262  /* set lower triangular entries of A corresponding to square and linear terms */
5263  for( i = 0; i < consdata->nquadvars; ++i )
5264  {
5265  a[i*n + i] = consdata->quadvarterms[i].sqrcoef;
5266  a[i*n + n-1] = consdata->quadvarterms[i].lincoef / 2.0;
5267  }
5268 
5269  SCIP_CALL( SCIPallocBufferArray(scip, &eigvals, n) );
5270  if( LapackDsyev(TRUE, n, a, eigvals) != SCIP_OKAY )
5271  {
5272  SCIPdebugMsg(scip, "Failed to compute eigenvalues and eigenvectors of augmented quadratic form matrix for constraint <%s>.\n", SCIPconsGetName(cons));
5273  goto CLEANUP;
5274  }
5275 
5276  /* check if there is exactly one positive and one negative eigenvalue */
5277  posidx = -1;
5278  negidx = -1;
5279  for( i = 0; i < n; ++i )
5280  {
5281  if( SCIPisPositive(scip, eigvals[i]) )
5282  {
5283  if( posidx == -1 )
5284  posidx = i;
5285  else
5286  break;
5287  }
5288  else if( SCIPisNegative(scip, eigvals[i]) )
5289  {
5290  if( negidx == -1 )
5291  negidx = i;
5292  else
5293  break;
5294  }
5295  }
5296  if( i < n || posidx == -1 || negidx == -1 )
5297  {
5298  SCIPdebugMsg(scip, "Augmented quadratic form of constraint <%s> is not factorable.\n", SCIPconsGetName(cons));
5299  goto CLEANUP;
5300  }
5301  assert(SCIPisPositive(scip, eigvals[posidx]));
5302  assert(SCIPisNegative(scip, eigvals[negidx]));
5303 
5304  /* compute factorleft and factorright */
5305  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->factorleft, consdata->nquadvars + 1) );
5306  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->factorright, consdata->nquadvars + 1) );
5307 
5308  /* eigenvectors are stored in a, inverse eigenvector matrix is transposed of a
5309  * it seems that v1 and v2 are at &a[posidx*n] and &a[negidx*n]
5310  */
5311  sigma1 = sqrt( eigvals[posidx]);
5312  sigma2 = sqrt(-eigvals[negidx]);
5313  for( i = 0; i < n; ++i )
5314  {
5315  consdata->factorleft[i] = sigma1 * a[posidx * n + i] - sigma2 * a[negidx * n + i];
5316  consdata->factorright[i] = sigma1 * a[posidx * n + i] + sigma2 * a[negidx * n + i];
5317  /* set almost-zero elements to zero */
5318  if( SCIPisZero(scip, consdata->factorleft[i]) )
5319  consdata->factorleft[i] = 0.0;
5320  if( SCIPisZero(scip, consdata->factorright[i]) )
5321  consdata->factorright[i] = 0.0;
5322  }
5323 
5324 #ifdef SCIP_DEBUG
5325  SCIPdebugMsg(scip, "constraint <%s> has factorable quadratic form: (%g", SCIPconsGetName(cons), consdata->factorleft[n-1]);
5326  for( i = 0; i < consdata->nquadvars; ++i )
5327  {
5328  if( consdata->factorleft[i] != 0.0 )
5329  SCIPdebugMsgPrint(scip, " %+g<%s>", consdata->factorleft[i], SCIPvarGetName(consdata->quadvarterms[i].var));
5330  }
5331  SCIPdebugMsgPrint(scip, ") * (%g", consdata->factorright[n-1]);
5332  for( i = 0; i < consdata->nquadvars; ++i )
5333  {
5334  if( consdata->factorright[i] != 0.0 )
5335  SCIPdebugMsgPrint(scip, " %+g<%s>", consdata->factorright[i], SCIPvarGetName(consdata->quadvarterms[i].var));
5336  }
5337  SCIPdebugMsgPrint(scip, ")\n");
5338 #endif
5339 
5340  /* check whether factorleft * factorright^T is matrix of augmented quadratic form
5341  * we check here only the nonzero entries from the quadratic form
5342  */
5343  success = TRUE;
5344 
5345  /* check bilinear terms */
5346  for( i = 0; i < consdata->nbilinterms; ++i )
5347  {
5348  bilinterm = &consdata->bilinterms[i];
5349 
5350  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var1, &idx1) );
5351  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var2, &idx2) );
5352 
5353  if( !SCIPisRelEQ(scip, consdata->factorleft[idx1] * consdata->factorright[idx2] + consdata->factorleft[idx2] * consdata->factorright[idx1], bilinterm->coef) )
5354  {
5355  success = FALSE;
5356  break;
5357  }
5358  }
5359 
5360  /* set lower triangular entries of A corresponding to square and linear terms */
5361  for( i = 0; i < consdata->nquadvars; ++i )
5362  {
5363  if( !SCIPisRelEQ(scip, consdata->factorleft[i] * consdata->factorright[i], consdata->quadvarterms[i].sqrcoef) )
5364  {
5365  success = FALSE;
5366  break;
5367  }
5368 
5369  if( !SCIPisRelEQ(scip, consdata->factorleft[n-1] * consdata->factorright[i] + consdata->factorleft[i] * consdata->factorright[n-1], consdata->quadvarterms[i].lincoef) )
5370  {
5371  success = FALSE;
5372  break;
5373  }
5374  }
5375 
5376  if( !success )
5377  {
5378  SCIPdebugMsg(scip, "Factorization not accurate enough. Dropping it.\n");
5379  SCIPfreeBlockMemoryArray(scip, &consdata->factorleft, consdata->nquadvars + 1);
5380  SCIPfreeBlockMemoryArray(scip, &consdata->factorright, consdata->nquadvars + 1);
5381  }
5382 
5383  CLEANUP:
5384  SCIPfreeBufferArray(scip, &a);
5385  SCIPfreeBufferArray(scip, &eigvals);
5386 
5387  return SCIP_OKAY;
5388 }
5389 
5390 /** computes activity and violation of a constraint
5391  *
5392  * If solution violates bounds by more than feastol, the violation is still computed, but *solviolbounds is set to TRUE
5393  */
5394 static
5396  SCIP* scip, /**< SCIP data structure */
5397  SCIP_CONS* cons, /**< constraint */
5398  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
5399  SCIP_Bool* solviolbounds /**< buffer to store whether quadratic variables in solution are outside their bounds by more than feastol */
5400  )
5401 { /*lint --e{666}*/
5402  SCIP_CONSDATA* consdata;
5403  SCIP_Real varval;
5404  SCIP_Real varval2;
5405  SCIP_Real absviol;
5406  SCIP_Real relviol;
5407  SCIP_VAR* var;
5408  SCIP_VAR* var2;
5409  int i;
5410  int j;
5411 
5412  assert(scip != NULL);
5413  assert(cons != NULL);
5414  assert(solviolbounds != NULL);
5415 
5416  consdata = SCIPconsGetData(cons);
5417  assert(consdata != NULL);
5418 
5419  *solviolbounds = FALSE;
5420  consdata->activity = 0.0;
5421  consdata->lhsviol = 0.0;
5422  consdata->rhsviol = 0.0;
5423 
5424  for( i = 0; i < consdata->nlinvars; ++i )
5425  {
5426  SCIP_Real activity;
5427 
5428  var = consdata->linvars[i];
5429  varval = SCIPgetSolVal(scip, sol, var);
5430  activity = consdata->lincoefs[i] * varval;
5431 
5432  /* the contribution of a variable with |varval| = +inf is +inf when activity > 0.0, -inf when activity < 0.0, and
5433  * 0.0 otherwise
5434  */
5435  if( SCIPisInfinity(scip, REALABS(varval)) )
5436  {
5437  if( activity > 0.0 && !SCIPisInfinity(scip, consdata->rhs) )
5438  {
5439  consdata->activity = SCIPinfinity(scip);
5440  consdata->rhsviol = SCIPinfinity(scip);
5441  return SCIP_OKAY;
5442  }
5443 
5444  if( activity < 0.0 && !SCIPisInfinity(scip, -consdata->lhs) )
5445  {
5446  consdata->activity = -SCIPinfinity(scip);
5447  consdata->lhsviol = SCIPinfinity(scip);
5448  return SCIP_OKAY;
5449  }
5450  }
5451 
5452  consdata->activity += activity;
5453  }
5454 
5455  for( j = 0; j < consdata->nquadvars; ++j )
5456  {
5457  SCIP_Real activity;
5458 
5459  var = consdata->quadvarterms[j].var;
5460  varval = SCIPgetSolVal(scip, sol, var);
5461  activity = (consdata->quadvarterms[j].lincoef + consdata->quadvarterms[j].sqrcoef * varval) * varval;
5462 
5463  /* the contribution of a variable with |varval| = +inf is +inf when activity > 0.0, -inf when activity < 0.0, and
5464  * 0.0 otherwise
5465  */
5466  if( SCIPisInfinity(scip, REALABS(varval)) )
5467  {
5468  if( activity > 0.0 && !SCIPisInfinity(scip, consdata->rhs) )
5469  {
5470  consdata->activity = SCIPinfinity(scip);
5471  consdata->rhsviol = SCIPinfinity(scip);
5472  return SCIP_OKAY;
5473  }
5474 
5475  if( activity < 0.0 && !SCIPisInfinity(scip, -consdata->lhs) )
5476  {
5477  consdata->activity = -SCIPinfinity(scip);
5478  consdata->lhsviol = SCIPinfinity(scip);
5479  return SCIP_OKAY;
5480  }
5481  }
5482 
5483  /* project onto local box, in case the LP solution is slightly outside the bounds (which is not our job to enforce) */
5484  if( sol == NULL )
5485  {
5486  /* with non-initial columns, variables can shortly be a column variable before entering the LP and have value 0.0 in this case, which might violated the variable bounds */
5487  if( (!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) && !SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var))) ||
5488  (!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) && !SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var))) )
5489  *solviolbounds = TRUE;
5490  else
5491  {
5492  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
5493  activity = (consdata->quadvarterms[j].lincoef + consdata->quadvarterms[j].sqrcoef * varval) * varval;
5494  }
5495  }
5496 
5497  consdata->activity += activity;
5498  }
5499 
5500  for( j = 0; j < consdata->nbilinterms; ++j )
5501  {
5502  SCIP_Real activity;
5503 
5504  var = consdata->bilinterms[j].var1;
5505  var2 = consdata->bilinterms[j].var2;
5506  varval = SCIPgetSolVal(scip, sol, var);
5507  varval2 = SCIPgetSolVal(scip, sol, var2);
5508 
5509  /* project onto local box, in case the LP solution is slightly outside the bounds (which is not our job to enforce) */
5510  if( sol == NULL )
5511  {
5512  /* with non-initial columns, variables can shortly be a column variable before entering the LP and have value 0.0 in this case, which might violated the variable bounds */
5513  if( (!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) && !SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var))) ||
5514  (!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) && !SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var))) )
5515  *solviolbounds = TRUE;
5516  else
5517  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
5518 
5519  /* with non-initial columns, variables can shortly be a column variable before entering the LP and have value 0.0 in this case, which might violated the variable bounds */
5520  if( (!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var2)) && !SCIPisFeasGE(scip, varval2, SCIPvarGetLbLocal(var2))) ||
5521  (!SCIPisInfinity(scip, SCIPvarGetUbLocal(var2)) && !SCIPisFeasLE(scip, varval2, SCIPvarGetUbLocal(var2))) )
5522  *solviolbounds = TRUE;
5523  else
5524  varval2 = MAX(SCIPvarGetLbLocal(var2), MIN(SCIPvarGetUbLocal(var2), varval2));
5525  }
5526 
5527  activity = consdata->bilinterms[j].coef * varval * varval2;
5528 
5529  /* consider var*var2 as a new variable and handle it as it would appear linearly */
5530  if( SCIPisInfinity(scip, REALABS(varval*varval2)) )
5531  {
5532  if( activity > 0.0 && !SCIPisInfinity(scip, consdata->rhs) )
5533  {
5534  consdata->activity = SCIPinfinity(scip);
5535  consdata->rhsviol = SCIPinfinity(scip);
5536  return SCIP_OKAY;
5537  }
5538 
5539  if( activity < 0.0 && !SCIPisInfinity(scip, -consdata->lhs) )
5540  {
5541  consdata->activity = -SCIPinfinity(scip);
5542  consdata->lhsviol = SCIPinfinity(scip);
5543  return SCIP_OKAY;
5544  }
5545  }
5546 
5547  consdata->activity += activity;
5548  }
5549 
5550  absviol = 0.0;
5551  relviol = 0.0;
5552  /* compute absolute violation left hand side */
5553  if( consdata->activity < consdata->lhs && !SCIPisInfinity(scip, -consdata->lhs) )
5554  {
5555  consdata->lhsviol = consdata->lhs - consdata->activity;
5556  absviol = consdata->lhsviol;
5557  relviol = SCIPrelDiff(consdata->lhs, consdata->activity);
5558  }
5559  else
5560  consdata->lhsviol = 0.0;
5561 
5562  /* compute absolute violation right hand side */
5563  if( consdata->activity > consdata->rhs && !SCIPisInfinity(scip, consdata->rhs) )
5564  {
5565  consdata->rhsviol = consdata->activity - consdata->rhs;
5566  absviol = consdata->rhsviol;
5567  relviol = SCIPrelDiff(consdata->activity, consdata->rhs);
5568  }
5569  else
5570  consdata->rhsviol = 0.0;
5571 
5572  /* update absolute and relative violation of the solution */
5573  if( sol != NULL )
5574  SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
5575 
5576  return SCIP_OKAY;
5577 }
5578 
5579 /** computes violation of a set of constraints */
5580 static
5582  SCIP* scip, /**< SCIP data structure */
5583  SCIP_CONS** conss, /**< constraints */
5584  int nconss, /**< number of constraints */
5585  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
5586  SCIP_Bool* solviolbounds, /**< buffer to store whether quadratic variables in solution are outside their bounds by more than feastol in some constraint */
5587  SCIP_CONS** maxviolcon /**< buffer to store constraint with largest violation, or NULL if solution is feasible */
5588  )
5589 {
5590  SCIP_CONSDATA* consdata;
5591  SCIP_Real viol;
5592  SCIP_Real maxviol;
5593  SCIP_Bool solviolbounds1;
5594  int c;
5595 
5596  assert(scip != NULL);
5597  assert(conss != NULL || nconss == 0);
5598  assert(solviolbounds != NULL);
5599  assert(maxviolcon != NULL);
5600 
5601  *solviolbounds = FALSE;
5602  *maxviolcon = NULL;
5603 
5604  maxviol = 0.0;
5605 
5606  for( c = 0; c < nconss; ++c )
5607  {
5608  assert(conss != NULL);
5609  assert(conss[c] != NULL);
5610 
5611  SCIP_CALL( computeViolation(scip, conss[c], sol, &solviolbounds1) );
5612  *solviolbounds |= solviolbounds1;
5613 
5614  consdata = SCIPconsGetData(conss[c]);
5615  assert(consdata != NULL);
5616 
5617  viol = MAX(consdata->lhsviol, consdata->rhsviol);
5618  if( viol > maxviol && SCIPisGT(scip, viol, SCIPfeastol(scip)) )
5619  {
5620  maxviol = viol;
5621  *maxviolcon = conss[c];
5622  }
5623  }
5624 
5625  return SCIP_OKAY;
5626 }
5627 
5628 
5629 /** index comparison method for bilinear terms */
5630 static
5631 SCIP_DECL_SORTINDCOMP(bilinTermComp2)
5632 { /*lint --e{715}*/
5633  SCIP_BILINTERM* bilinterms = (SCIP_BILINTERM*)dataptr;
5634  int var1cmp;
5635 
5636  assert(bilinterms != NULL);
5637 
5638  var1cmp = SCIPvarCompare(bilinterms[ind1].var1, bilinterms[ind2].var1);
5639  if( var1cmp != 0 )
5640  return var1cmp;
5641 
5642  return SCIPvarCompare(bilinterms[ind1].var2, bilinterms[ind2].var2);
5643 }
5644 
5645 /** volume comparison method for bilinear terms; prioritizes bilinear products with a larger volume */
5646 static
5647 SCIP_DECL_SORTINDCOMP(bilinTermCompVolume)
5648 { /*lint --e{715}*/
5649  SCIP_BILINTERM* bilinterms = (SCIP_BILINTERM*)dataptr;
5650  SCIP_Real vol1;
5651  SCIP_Real vol2;
5652 
5653  assert(bilinterms != NULL);
5654 
5655  vol1 = (SCIPvarGetUbLocal(bilinterms[ind1].var1) - SCIPvarGetLbLocal(bilinterms[ind1].var1))
5656  * (SCIPvarGetUbLocal(bilinterms[ind1].var2) - SCIPvarGetLbLocal(bilinterms[ind1].var2));
5657  vol2 = (SCIPvarGetUbLocal(bilinterms[ind2].var1) - SCIPvarGetLbLocal(bilinterms[ind2].var1))
5658  * (SCIPvarGetUbLocal(bilinterms[ind2].var2) - SCIPvarGetLbLocal(bilinterms[ind2].var2));
5659 
5660  if( vol1 > vol2 )
5661  return -1;
5662  else if( vol1 < vol2 )
5663  return 1;
5664  return bilinTermComp2(dataptr, ind1, ind2);
5665 }
5666 
5667 /** helper function to sort all bilinear terms in the constraint handler data */
5668 static
5670  SCIP* scip, /**< SCIP data structure */
5671  SCIP_BILINTERM* bilinterms, /**< array containing all bilinear terms */
5672  int nbilinterms, /**< total number of bilinear terms */
5673  SCIP_CONS** bilinconss, /**< array for mapping each term to its constraint */
5674  int* bilinposs /**< array for mapping each term to its position in the corresponding
5675  * bilinconss constraint */
5676  )
5677 {
5678  int* perm;
5679  int i;
5680  int nexti;
5681  int v;
5682  SCIP_BILINTERM bilinterm;
5683  SCIP_CONS* bilincons;
5684  int bilinpos;
5685 
5686  assert(scip != NULL);
5687  assert(bilinterms != NULL);
5688  assert(nbilinterms > 0);
5689  assert(bilinconss != NULL);
5690  assert(bilinposs != NULL);
5691 
5692  /* get temporary memory to store the sorted permutation and the inverse permutation */
5693  SCIP_CALL( SCIPallocBufferArray(scip, &perm, nbilinterms) );
5694 
5695  /* call quicksort */
5696  SCIPsort(perm, bilinTermCompVolume, (void*)bilinterms, nbilinterms);
5697 
5698  /* permute the bilinear terms according to the resulting permutation */
5699  for( v = 0; v < nbilinterms; ++v )
5700  {
5701  if( perm[v] != v )
5702  {
5703  bilinterm = bilinterms[v];
5704  bilincons = bilinconss[v];
5705  bilinpos = bilinposs[v];
5706 
5707  i = v;
5708  do
5709  {
5710  assert(0 <= perm[i] && perm[i] < nbilinterms);
5711  assert(perm[i] != i);
5712 
5713  bilinterms[i] = bilinterms[perm[i]];
5714  bilinconss[i] = bilinconss[perm[i]];
5715  bilinposs[i] = bilinposs[perm[i]];
5716 
5717  nexti = perm[i];
5718  perm[i] = i;
5719  i = nexti;
5720  }
5721  while( perm[i] != v );
5722  bilinterms[i] = bilinterm;
5723  bilinconss[i] = bilincons;
5724  bilinposs[i] = bilinpos;
5725  perm[i] = i;
5726  }
5727  }
5728 
5729  /* free temporary memory */
5730  SCIPfreeBufferArray(scip, &perm);
5731 
5732  return SCIP_OKAY;
5733 }
5734 
5735 /** stores all bilinear terms in the quadratic constraint handler data; in addition, for each bilinear term we store
5736  * the number of nonconvex constraints that require to over- or underestimate this term, which only depends on the
5737  * lhs, rhs, and the bilinear coefficient
5738  */
5739 static
5741  SCIP* scip, /**< SCIP data structure */
5742  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5743  SCIP_CONS** conss, /**< constraints to process */
5744  int nconss /**< number of constraints */
5745  )
5746 {
5747  SCIP_BILINTERM* bilinterms;
5748  SCIP_CONS** bilincons;
5749  int* bilinpos;
5750  int nbilinterms;
5751  int pos;
5752  int c;
5753  int i;
5754 
5755  assert(scip != NULL);
5756  assert(conshdlrdata != NULL);
5757  assert(conss != NULL);
5758 
5759  /* check for all cases for which we don't want to spend time for collecting all bilinear terms */
5760  if( nconss == 0 || conshdlrdata->storedbilinearterms || SCIPgetSubscipDepth(scip) != 0 || SCIPgetDepth(scip) >= 1
5761  || SCIPinProbing(scip) || SCIPinDive(scip) )
5762  return SCIP_OKAY;
5763 
5764  assert(conshdlrdata->bilinestimators == NULL);
5765  assert(conshdlrdata->nbilinterms == 0);
5766 
5767  conshdlrdata->storedbilinearterms = TRUE;
5768  nbilinterms = 0;
5769 
5770  /* count the number of bilinear terms (including duplicates) */
5771  for( c = 0; c < nconss; ++c )
5772  {
5773  SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]);
5774  assert(consdata != NULL);
5775  nbilinterms += consdata->nbilinterms;
5776  }
5777 
5778  /* no bilinear terms available -> stop */
5779  if( nbilinterms == 0 )
5780  return SCIP_OKAY;
5781 
5782  /* allocate temporary memory for sorting all bilinear terms (including duplicates) */
5783  SCIP_CALL( SCIPallocBufferArray(scip, &bilinterms, nbilinterms) );
5784  SCIP_CALL( SCIPallocBufferArray(scip, &bilincons, nbilinterms) );
5785  SCIP_CALL( SCIPallocBufferArray(scip, &bilinpos, nbilinterms) );
5786 
5787  /* copy all bilinear terms; note that we need separate entries for x*y and y*x */
5788  pos = 0;
5789  for( c = 0; c < nconss; ++c )
5790  {
5791  SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]);
5792 
5793  /* allocate memory to store the later computed indices of each bilinear term in the bilinterms array of the
5794  * constraint handler data
5795  */
5796  if( consdata->nbilinterms > 0 )
5797  {
5798  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->bilintermsidx, consdata->nbilinterms) );
5799  }
5800 
5801  for( i = 0; i < consdata->nbilinterms; ++i )
5802  {
5803  assert(consdata->bilinterms != NULL);
5804  assert(consdata->bilinterms[i].var1 != consdata->bilinterms[i].var2);
5805 
5806  /* add xy */
5807  bilinterms[pos] = consdata->bilinterms[i];
5808  bilincons[pos] = conss[c];
5809  bilinpos[pos] = i;
5810  ++pos;
5811 
5812  /* invalidate bilinear term index */
5813  assert(consdata->bilintermsidx != NULL);
5814  consdata->bilintermsidx[i] = -1;
5815  }
5816  }
5817  assert(pos == nbilinterms);
5818 
5819  /* sorts all bilinear terms (including duplicates) */
5820  SCIP_CALL( sortAllBilinTerms(scip, bilinterms, nbilinterms, bilincons, bilinpos) );
5821 
5822  /* count the number of bilinear terms without duplicates */
5823  conshdlrdata->nbilinterms = nbilinterms;
5824  for( i = 0; i < nbilinterms - 1; ++i )
5825  {
5826  assert(bilinTermCompVolume((void*)bilinterms, i, i+1) != 0 || bilinTermComp2((void*)bilinterms, i, i+1) <= 0);
5827 
5828  if( bilinTermComp2((void*)bilinterms, i, i+1) == 0 )
5829  --(conshdlrdata->nbilinterms);
5830  }
5831  assert(conshdlrdata->nbilinterms <= nbilinterms && conshdlrdata->nbilinterms > 0);
5832 
5833  /* store all information for each bilinear term into the constraint handler data */
5834  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bilinestimators, conshdlrdata->nbilinterms) );
5835 
5836  /* filter duplicates and update entries in the corresponding constraint datas */
5837  pos = 0;
5838  for( i = 0; i < nbilinterms; ++i )
5839  {
5840  SCIP_CONSDATA* consdata = SCIPconsGetData(bilincons[i]);
5841  SCIP_VAR* x;
5842  SCIP_Bool haslhs = !SCIPisInfinity(scip, -consdata->lhs);
5843  SCIP_Bool hasrhs = !SCIPisInfinity(scip, consdata->rhs);
5844 
5845  assert(consdata != NULL);
5846  assert(bilinpos[i] >= 0 && bilinpos[i] < consdata->nbilinterms);
5847 
5848  /* check for a new bilinear term */
5849  if( i == 0 || bilinTermComp2((void*)bilinterms, i-1, i) != 0 )
5850  {
5851  conshdlrdata->bilinestimators[pos].x = bilinterms[i].var1;
5852  conshdlrdata->bilinestimators[pos].y = bilinterms[i].var2;
5853  conshdlrdata->bilinestimators[pos].lastimprfac = 0.0;
5854  conshdlrdata->bilinestimators[pos].maxnonconvexity = 0.0;
5855  ++pos;
5856  }
5857 
5858  /* store whether under- or overestimation is needed for each bilinear term; note that we do not consider convex
5859  * constraints because they will not be used in separated generateCutNonConvex(), which is the only function that
5860  * uses a term-wise relaxation
5861  */
5862  if( SCIPisPositive(scip, bilinterms[i].coef) )
5863  {
5864  conshdlrdata->bilinestimators[pos-1].nunderest += (hasrhs && !consdata->isconvex) ? 1 : 0;
5865  conshdlrdata->bilinestimators[pos-1].noverest += (haslhs && !consdata->isconcave) ? 1 : 0;
5866  conshdlrdata->bilinestimators[pos-1].maxnonconvexity = MAX(conshdlrdata->bilinestimators[pos-1].maxnonconvexity, consdata->maxnonconvexity);
5867  }
5868  else
5869  {
5870  assert(SCIPisNegative(scip, bilinterms[i].coef));
5871  conshdlrdata->bilinestimators[pos-1].nunderest += (haslhs && !consdata->isconcave) ? 1 : 0;
5872  conshdlrdata->bilinestimators[pos-1].noverest += (hasrhs && !consdata->isconvex) ? 1 : 0;
5873  conshdlrdata->bilinestimators[pos-1].maxnonconvexity = MAX(conshdlrdata->bilinestimators[pos-1].maxnonconvexity, consdata->maxnonconvexity);
5874  }
5875 
5876  /* update index of bilinear term in the constraint data */
5877  x = consdata->bilinterms[bilinpos[i]].var1;
5878 
5879  assert(pos > 0);
5880  if( x == conshdlrdata->bilinestimators[pos-1].x )
5881  {
5882  assert(consdata->bilinterms[bilinpos[i]].var2 == conshdlrdata->bilinestimators[pos-1].y);
5883  consdata->bilintermsidx[bilinpos[i]] = pos-1;
5884  }
5885  }
5886  assert(pos == conshdlrdata->nbilinterms);
5887 
5888 #ifndef NDEBUG
5889  /* check whether
5890  * - all bilintermsidx entries have been set
5891  * - variables in bilinear terms of each constraint data and the constraint handler data match
5892  */
5893  for( c = 0; c < nconss; ++c )
5894  {
5895  SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]);
5896  assert(consdata != NULL);
5897 
5898  for( i = 0; i < consdata->nbilinterms; ++i )
5899  {
5900  SCIP_VAR* x = consdata->bilinterms[i].var1;
5901  SCIP_VAR* y = consdata->bilinterms[i].var2;
5902  int idx = consdata->bilintermsidx[i];
5903 
5904  assert(idx >= 0 && idx < conshdlrdata->nbilinterms);
5905  assert(x == conshdlrdata->bilinestimators[idx].x);
5906  assert(y == conshdlrdata->bilinestimators[idx].y);
5907 
5908  /* at least one direction is important if the constraint is not convex */
5909  if( !SCIPisInfinity(scip, consdata->rhs) && !consdata->isconvex )
5910  assert(conshdlrdata->bilinestimators[idx].nunderest + conshdlrdata->bilinestimators[idx].noverest > 0);
5911  if( !SCIPisInfinity(scip, -consdata->lhs) && !consdata->isconcave )
5912  assert(conshdlrdata->bilinestimators[idx].nunderest + conshdlrdata->bilinestimators[idx].noverest > 0);
5913  }
5914  }
5915 #endif
5916 
5917  /* free memory */
5918  SCIPfreeBufferArray(scip, &bilinpos);
5919  SCIPfreeBufferArray(scip, &bilincons);
5920  SCIPfreeBufferArray(scip, &bilinterms);
5921 
5922  return SCIP_OKAY;
5923 }
5924 
5925 /** frees memory allocated in storeAllBilinearTerms() */
5926 static
5928  SCIP* scip, /**< SCIP data structure */
5929  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5930  SCIP_CONS** conss, /**< constraints to process */
5931  int nconss /**< number of constraints */
5932 
5933  )
5934 {
5935  int c;
5936 
5937  assert(conshdlrdata != NULL);
5938 
5939  for( c = 0; c < nconss; ++c )
5940  {
5941  SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
5942  assert(consdata != NULL);
5943 
5944  SCIPfreeBlockMemoryArrayNull(scip, &consdata->bilintermsidx, consdata->nbilinterms);
5945  }
5946 
5947  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bilinestimators, conshdlrdata->nbilinterms);
5948 
5949  conshdlrdata->nbilinterms = 0;
5950  conshdlrdata->storedbilinearterms = FALSE;
5951 
5952  return SCIP_OKAY;
5953 }
5954 
5955 /** tries to compute cut for multleft * <coefleft, x'> * multright <= rhs / (multright * <coefright, x'>) where x'=(x,1) */
5956 static
5958  SCIP* scip, /**< SCIP data structure */
5959  SCIP_CONS* cons, /**< constraint */
5960  SCIP_Real* ref, /**< reference solution where to generate the cut */
5961  SCIP_Real multleft, /**< multiplicator on lhs */
5962  SCIP_Real* coefleft, /**< coefficient for factor on lhs */
5963  SCIP_Real multright, /**< multiplicator on both sides */
5964  SCIP_Real* coefright, /**< coefficient for factor that goes to rhs */
5965  SCIP_Real rightminactivity, /**< minimal activity of <coefright, x> */
5966  SCIP_Real rightmaxactivity, /**< maximal activity of <coefright, x> */
5967  SCIP_Real rhs, /**< denominator on rhs */
5968  SCIP_ROWPREP* rowprep, /**< rowprep to store cut coefs and constant */
5969  SCIP_Bool* success /**< buffer to indicate whether a cut was successfully computed */
5970  )
5971 {
5972  SCIP_CONSDATA* consdata;
5973  SCIP_Real constant;
5974  SCIP_Real coef;
5975  int i;
5976 
5977  assert(rowprep != NULL);
5978  assert(rightminactivity * multright > 0.0);
5979  assert(rightmaxactivity * multright > 0.0);
5980  assert(multright == 1.0 || multright == -1.0);
5981 
5982  consdata = SCIPconsGetData(cons);
5983  assert(consdata != NULL);
5984 
5985  rowprep->sidetype = SCIP_SIDETYPE_RIGHT;
5986 
5987  if( rhs > 0.0 )
5988  {
5989  /* if rhs > 0.0, then rhs / (multright * <coefright, x'>) is convex, thus need secant:
5990  * 1 / multright*<coefright, x'> <= 1/minact + 1/maxact - 1/(minact * maxact) multright*<coefright, x'>
5991  * where [minact, maxact] = multright * [rightminactivity, rightmaxactivity]
5992  *
5993  * assuming multright is either -1 or 1, and substituting gives
5994  * multright/rightminactivity + multright/rightmaxactivity - multright/(rightminactivity * rightmaxactivity) *<coefright, x'>
5995  *
5996  * multiplying by rhs, gives the estimate
5997  * rhs / (multright * <coefright, x'>) <= rhs * multright * (1/rightminactivity + 1/rightmaxactivity - 1/(rightminactivity * rightmaxactivity) * <coefright, x'>)
5998  */
5999 
6000  /* cannot do if unbounded */
6001  if( SCIPisInfinity(scip, rightmaxactivity * multright) )
6002  {
6003  *success = FALSE;
6004  return SCIP_OKAY;
6005  }
6006 
6007  assert(SCIPisFeasLE(scip, rightminactivity, rightmaxactivity));
6008 
6009  constant = multleft * multright * coefleft[consdata->nquadvars];
6010  constant -= rhs * multright * (1.0 / rightminactivity + 1.0 / rightmaxactivity);
6011  constant += rhs * multright * coefright[consdata->nquadvars] / (rightminactivity * rightmaxactivity);
6012 
6013  SCIPaddRowprepConstant(rowprep, constant);
6014 
6015  for( i = 0; i < consdata->nquadvars; ++i )
6016  {
6017  coef = multleft * multright * coefleft[i];
6018  coef += rhs * multright / (rightminactivity * rightmaxactivity) * coefright[i];
6019  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, consdata->quadvarterms[i].var, coef) );
6020  }
6021 
6022  (void) SCIPsnprintf(rowprep->name, SCIP_MAXSTRLEN, "%s_factorablesecant_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
6023  }
6024  else
6025  {
6026  SCIP_Real refvalue;
6027 
6028  /* if rhs < 0.0, then rhs / (multright * <coefright, x'>) is convex, thus need linearization:
6029  * rhs / (multright * <coefright, x'>)
6030  * <= rhs / (multright * <coefright, ref'>) - rhs / (multright * <coefright, ref'>)^2 * (multright * <coefright, x'> - multright * <coefright, ref'>)
6031  * = 2*rhs / (multright * <coefright, ref'>) - rhs / (multright * <coefright, ref'>)^2 * (multright * <coefright, x'>)
6032  *
6033  * where ref' = (ref, 1)
6034  */
6035 
6036  /* compute <coefright, ref'> */
6037  refvalue = coefright[consdata->nquadvars];
6038  for( i = 0; i < consdata->nquadvars; ++i )
6039  refvalue += coefright[i] * ref[i];
6040 
6041  /* should not happen, since we checked activity of <coefright,x> before, and assume ref within bounds */
6042  assert(!SCIPisZero(scip, refvalue));
6043 
6044  constant = multleft * multright * coefleft[consdata->nquadvars];
6045  constant -= 2.0 * rhs / (multright * refvalue);
6046  constant += rhs / (refvalue * refvalue) * multright * coefright[consdata->nquadvars];
6047 
6048  SCIPaddRowprepConstant(rowprep, constant);
6049 
6050  for( i = 0; i < consdata->nquadvars; ++i )
6051  {
6052  coef = multleft * multright * coefleft[i];
6053  coef += rhs / (refvalue * refvalue) * multright * coefright[i];
6054  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, consdata->quadvarterms[i].var, coef) );
6055  }
6056 
6057  (void) SCIPsnprintf(rowprep->name, SCIP_MAXSTRLEN, "%s_factorablelinearization_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
6058  }
6059 
6060  /* @todo does not always need to be local */
6061  rowprep->local = TRUE;
6062  *success = TRUE;
6063 
6064  return SCIP_OKAY;
6065 }
6066 
6067 /** tries to generate a cut if constraint quadratic function is factorable and there are no linear variables
6068  * (ax+b)(cx+d) <= rhs and cx+d >= 0 -> (ax+b) <= rhs / (cx+d), where the right hand side is concave and can be linearized
6069  */
6070 static
6072  SCIP* scip, /**< SCIP data structure */
6073  SCIP_CONS* cons, /**< constraint */
6074  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
6075  SCIP_Real* ref, /**< reference solution where to generate the cut */
6076  SCIP_ROWPREP* rowprep, /**< data structure to store cut coefficients */
6077  SCIP_Bool* success /**< buffer to indicate whether a cut was successfully computed */
6078  )
6079 {
6080  SCIP_CONSDATA* consdata;
6081  SCIP_Real leftminactivity;
6082  SCIP_Real leftmaxactivity;
6083  SCIP_Real rightminactivity;
6084  SCIP_Real rightmaxactivity;
6085  SCIP_Real multleft;
6086  SCIP_Real multright;
6087  SCIP_Real rhs;
6088  int i;
6089 
6090  assert(scip != NULL);
6091  assert(cons != NULL);
6092  assert(ref != NULL);
6093  assert(rowprep != NULL);
6094  assert(success != NULL);
6095 
6096  consdata = SCIPconsGetData(cons);
6097  assert(consdata != NULL);
6098  assert(consdata->nlinvars == 0);
6099  assert(consdata->factorleft != NULL);
6100  assert(consdata->factorright != NULL);
6101 
6102  *success = FALSE;
6103 
6104  leftminactivity = consdata->factorleft[consdata->nquadvars];
6105  leftmaxactivity = consdata->factorleft[consdata->nquadvars];
6106  rightminactivity = consdata->factorright[consdata->nquadvars];
6107  rightmaxactivity = consdata->factorright[consdata->nquadvars];
6108  for( i = 0; i < consdata->nquadvars; ++i )
6109  {
6110  if( !SCIPisInfinity(scip, -leftminactivity) )
6111  {
6112  if( consdata->factorleft[i] > 0.0 )
6113  {
6114  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6115  leftminactivity = -SCIPinfinity(scip);
6116  else
6117  leftminactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6118  }
6119  else if( consdata->factorleft[i] < 0.0 )
6120  {
6121  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6122  leftminactivity = -SCIPinfinity(scip);
6123  else
6124  leftminactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6125  }
6126  }
6127  if( !SCIPisInfinity(scip, leftmaxactivity) )
6128  {
6129  if( consdata->factorleft[i] > 0.0 )
6130  {
6131  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6132  leftmaxactivity = SCIPinfinity(scip);
6133  else
6134  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6135  }
6136  else if( consdata->factorleft[i] < 0.0 )
6137  {
6138  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6139  leftmaxactivity = SCIPinfinity(scip);
6140  else
6141  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6142  }
6143  }
6144 
6145  if( !SCIPisInfinity(scip, -rightminactivity) )
6146  {
6147  if( consdata->factorright[i] > 0.0 )
6148  {
6149  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6150  rightminactivity = -SCIPinfinity(scip);
6151  else
6152  rightminactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6153  }
6154  else if( consdata->factorright[i] < 0.0 )
6155  {
6156  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6157  rightminactivity = -SCIPinfinity(scip);
6158  else
6159  rightminactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6160  }
6161  }
6162  if( !SCIPisInfinity(scip, rightmaxactivity) )
6163  {
6164  if( consdata->factorright[i] > 0.0 )
6165  {
6166  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6167  rightmaxactivity = SCIPinfinity(scip);
6168  else
6169  rightmaxactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6170  }
6171  else if( consdata->factorright[i] < 0.0 )
6172  {
6173  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6174  rightmaxactivity = SCIPinfinity(scip);
6175  else
6176  rightmaxactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6177  }
6178  }
6179  }
6180 
6181  /* write violated constraints as multleft * factorleft * factorright <= rhs */
6182  if( violside == SCIP_SIDETYPE_RIGHT )
6183  {
6184  rhs = consdata->rhs;
6185  multleft = 1.0;
6186  }
6187  else
6188  {
6189  rhs = -consdata->lhs;
6190  multleft = -1.0;
6191  }
6192 
6193  if( SCIPisZero(scip, rhs) )
6194  {
6195  /* @todo do something for rhs == 0.0? */
6196  return SCIP_OKAY;
6197  }
6198 
6199  if( !SCIPisFeasPositive(scip, leftminactivity) && !SCIPisFeasNegative(scip, leftmaxactivity) )
6200  {
6201  /* left factor has 0 within activity bounds, or is very close, at least */
6202  if( !SCIPisFeasPositive(scip, rightminactivity) && !SCIPisFeasNegative(scip, rightmaxactivity) )
6203  {
6204  /* right factor also has 0 within activity bounds, or is very close, at least
6205  * -> cannot separate
6206  */
6207  return SCIP_OKAY;
6208  }
6209 
6210  /* write violated constraint as multleft * factorleft * multright * (multright * factorright) <= rhs
6211  * such that multright * factorright > 0.0
6212  */
6213  if( rightminactivity < 0.0 )
6214  multright = -1.0;
6215  else
6216  multright = 1.0;
6217 
6218  /* generate cut for multleft * factorleft * multright <= rhs / (factorright * multright) */
6219  SCIP_CALL( generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorleft, multright, consdata->factorright, rightminactivity, rightmaxactivity, rhs, rowprep, success) );
6220  }
6221  else if( !SCIPisFeasPositive(scip, rightminactivity) && !SCIPisFeasNegative(scip, rightmaxactivity) )
6222  {
6223  /* left factor is bounded away from 0
6224  * right factor has 0 within activity bounds, or is very close, at least
6225  * -> so divide by left factor
6226  */
6227 
6228  /* write violated constraint as multleft * factorright * multright * (multright * factorleft) <= rhs
6229  * such that multright * factorleft > 0.0
6230  */
6231  if( leftminactivity < 0.0 )
6232  multright = -1.0;
6233  else
6234  multright = 1.0;
6235 
6236  /* generate cut for multleft * factorright * multright <= rhs / (factorleft * multright) */
6237  SCIP_CALL( generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorright, multright, consdata->factorleft, leftminactivity, leftmaxactivity, rhs, rowprep, success) );
6238  }
6239  else if( SCIPisInfinity(scip, -leftminactivity) || SCIPisInfinity(scip, leftmaxactivity) ||
6240  (!SCIPisInfinity(scip, -rightminactivity) && !SCIPisInfinity(scip, rightmaxactivity) && rightmaxactivity - rightminactivity < leftmaxactivity - leftminactivity) )
6241  {
6242  /* both factors are bounded away from 0, but the right one has a smaller activity range, so divide by that one */
6243 
6244  /* write violated constraint as multleft * factorleft * multright * (multright * factorright) <= rhs
6245  * such that multright * factorright > 0.0
6246  */
6247  if( rightminactivity < 0.0 )
6248  multright = -1.0;
6249  else
6250  multright = 1.0;
6251 
6252  /* generate cut for multleft * factorleft * multright <= rhs / (factorright * multright) */
6253  SCIP_CALL( generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorleft, multright, consdata->factorright, rightminactivity, rightmaxactivity, rhs, rowprep, success) );
6254  }
6255  else
6256  {
6257  /* both factors are bounded away from 0, but the left one has a smaller activity range, so divide by that one */
6258 
6259  /* write violated constraint as multleft * factorright * multright * (multright * factorleft) <= rhs
6260  * such that multright * factorleft > 0.0
6261  */
6262  if( leftminactivity < 0.0 )
6263  multright = -1.0;
6264  else
6265  multright = 1.0;
6266 
6267  /* generate cut for multleft * factorright * multright <= rhs / (factorleft * multright) */
6268  SCIP_CALL( generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorright, multright, consdata->factorleft, leftminactivity, leftmaxactivity, rhs, rowprep, success) );
6269  }
6270 
6271  return SCIP_OKAY;
6272 }
6273 
6274 /* finds intersections of a parametric line (x,y) = (x0,y0) + t [(x1,y1) - (x0,y0)] on curves x*y = wl and x*y = wu;
6275  * returns TRUE if unsuccessful and FALSE otherwise
6276  */
6277 static
6279  SCIP* scip,
6280  SCIP_Real x0,
6281  SCIP_Real y0_,
6282  SCIP_Real x1,
6283  SCIP_Real y1_,
6284  SCIP_Real wl,
6285  SCIP_Real wu,
6286  SCIP_Real* xl,
6287  SCIP_Real* yl,
6288  SCIP_Real* xu,
6289  SCIP_Real* yu
6290  )
6291 {
6292  SCIP_Real a;
6293  SCIP_Real b;
6294  SCIP_Real c;
6295  SCIP_Real tl;
6296  SCIP_Real tu;
6297 
6298  assert(wl == SCIP_INVALID || (xl != NULL && yl != NULL)); /*lint !e777 */
6299  assert(wu == SCIP_INVALID || (xu != NULL && yu != NULL)); /*lint !e777 */
6300 
6301  /* The parametric line is of the form
6302  *
6303  * x = x0 + t (x1-x0)
6304  * y = y0 + t (y1-y0)
6305  *
6306  * and for that to satisfy xy = wl and xy = wu we must have
6307  *
6308  * x0 y0 + t [x0 (y1-y0) + y0 (x1-x0)] + t^2 (x1-x0) (y1-y0) = wl
6309  * = wu
6310  *
6311  * or a t^2 + b t + c - wl = 0 for proper values of a,b,c.
6312  * a t^2 + b t + c - wu = 0
6313  *
6314  * Because of the way this procedure will be used, one of the two
6315  * solutions found we must always use the minimum nonnegative one
6316  */
6317 
6318  a = (x1 - x0) * (y1_ - y0_);
6319  c = x0 * y0_;
6320  b = x0 * y1_ + y0_ * x1 - 2.0 * c;
6321 
6322  tl = 0.0;
6323  tu = 0.0;
6324 
6325  if( !SCIPisZero(scip, (SCIP_Real)a) )
6326  {
6327  if( wl != SCIP_INVALID ) /*lint !e777 */
6328  {
6329  SCIP_Real tl1;
6330  SCIP_Real tl2;
6331  SCIP_Real denom;
6332  SCIP_Real q;
6333 
6334  if( b * b - 4.0 * a * (c - wl) < 0.0 )
6335  {
6336  SCIPdebugMsg(scip, "probable numerical difficulties, give up\n");
6337  return TRUE;
6338  }
6339 
6340  denom = sqrt(b * b - 4.0 * a * (c - wl));
6341  q = -0.5 * (b + COPYSIGN(denom, b));
6342  tl1 = q / a;
6343  tl2 = (c - wl) / q;
6344 
6345  /* choose the smallest non-negative root */
6346  tl = (tl1 >= 0.0 && (tl2 < 0.0 || tl1 < tl2)) ? tl1 : tl2;
6347  }
6348 
6349  if( wu != SCIP_INVALID ) /*lint !e777 */
6350  {
6351  SCIP_Real tu1;
6352  SCIP_Real tu2;
6353  SCIP_Real denom;
6354  SCIP_Real q;
6355 
6356  if( b * b - 4.0 * a * (c - wu) < 0.0 )
6357  {
6358  SCIPdebugMsg(scip, "probable numerical difficulties, give up\n");
6359  return TRUE;
6360  }
6361 
6362  denom = sqrt(b * b - 4.0 * a * (c - wu));
6363  q = -0.5 * (b + COPYSIGN(denom, b));
6364  tu1 = q / a;
6365  tu2 = (c - wu) / q;
6366 
6367  /* choose the smallest non-negative root */
6368  tu = (tu1 >= 0.0 && (tu2 < 0.0 || tu1 < tu2)) ? tu1 : tu2;
6369  }
6370  }
6371  else if( !SCIPisZero(scip, (SCIP_Real)b) )
6372  {
6373  if( wl != SCIP_INVALID ) /*lint !e777 */
6374  tl = (wl - c) / b;
6375  if( wu != SCIP_INVALID ) /*lint !e777 */
6376  tu = (wu - c) / b;
6377  }
6378  else
6379  {
6380  /* no or infinitely many solutions */
6381  return TRUE;
6382  }
6383 
6384  if( wl != SCIP_INVALID ) /*lint !e777 */
6385  {
6386  *xl = (SCIP_Real)(x0 + tl * (x1 - x0 ));
6387  *yl = (SCIP_Real)(y0_ + tl * (y1_ - y0_));
6388 
6389  if( !SCIPisRelEQ(scip, *xl * *yl, wl) )
6390  {
6391  SCIPdebugMsg(scip, "probable numerical difficulties, give up\n");
6392  return TRUE;
6393  }
6394  }
6395 
6396  if( wu != SCIP_INVALID ) /*lint !e777 */
6397  {
6398  *xu = (SCIP_Real)(x0 + tu * (x1 - x0));
6399  *yu = (SCIP_Real)(y0_ + tu * (y1_ - y0_));
6400 
6401  if( !SCIPisRelEQ(scip, *xu * *yu, wu) )
6402  {
6403  SCIPdebugMsg(scip, "probable numerical difficulties, give up\n");
6404  return TRUE;
6405  }
6406  }
6407 
6408  /* do not use the computed points if one of the components is infinite */
6409  if( (xu != NULL && SCIPisInfinity(scip, *xu)) || (xl != NULL && SCIPisInfinity(scip, -*xl)) ||
6410  (yu != NULL && SCIPisInfinity(scip, *yu)) || (yl != NULL && SCIPisInfinity(scip, -*yl)) )
6411  {
6412  SCIPdebugMsg(scip, "probable numerical difficulties, give up\n");
6413  return TRUE;
6414  }
6415 
6416  return FALSE;
6417 }
6418 
6419 /** generate coefficients for a plane through points (x1, y1_, x1*y1) and (x2, y2, x2*y2)
6420  * such that intersecting it with one of them (the first if whichuse is FALSE, the second otherwise)
6421  * gives a tangent to the curve x*y = k
6422  *
6423  * Returns TRUE on error and FALSE on success.
6424  */
6425 static
6427  SCIP* scip,
6428  SCIP_Real x1,
6429  SCIP_Real y1_,
6430  SCIP_Real x2,
6431  SCIP_Real y2,
6432  SCIP_Bool whichuse,
6433  SCIP_Real* cx,
6434  SCIP_Real* cy,
6435  SCIP_Real* cw
6436  )
6437 {
6438  SCIP_Real xd;
6439  SCIP_Real yd;
6440  SCIP_Real xo;
6441  SCIP_Real yo;
6442 
6443  assert(cx != NULL);
6444  assert(cy != NULL);
6445  assert(cw != NULL);
6446 
6447  /* the x-y slope of this constraint must be tangent to a curve x*y = k at (xD,yD) */
6448  if( !whichuse )
6449  {
6450  xd = x1;
6451  xo = x2;
6452  yd = y1_;
6453  yo = y2;
6454  }
6455  else
6456  {
6457  xd = x2;
6458  xo = x1;
6459  yd = y2;
6460  yo = y1_;
6461  }
6462 
6463  *cx = yd;
6464  *cy = xd;
6465 
6466  /* lift it so that it touches the other curve */
6467 
6468  /* if the two points are on the same curve, then no cut */
6469  if( SCIPisZero(scip, xo * yo - xd * yd) )
6470  return TRUE;
6471 
6472  /* should ALWAYS be negative */
6473  *cw = (2.0 * xd * yd - (*cx * xo + *cy * yo)) / (xo * yo - xd * yd);
6474 
6475  return FALSE;
6476 }
6477 
6478 /** computes coefficients of a lifted-tangent inequality for x*y = w
6479  *
6480  * The code is an adaptation of the methods in exprMul-upperHull.cpp in Couenne/stable/0.4 rev773,
6481  * written by P. Belotti and licensed under Eclipse Public License.
6482  */
6483 static
6485  SCIP* scip, /**< SCIP data structure */
6486  SCIP_Real xl, /**< lower bound on x */
6487  SCIP_Real xu, /**< upper bound on x */
6488  SCIP_Real x0, /**< reference point for x */
6489  SCIP_Real yl, /**< lower bound on y */
6490  SCIP_Real yu, /**< upper bound on y */
6491  SCIP_Real y0_, /**< reference point for y */
6492  SCIP_Real wl, /**< lower bound on w */
6493  SCIP_Real wu, /**< upper bound on w */
6494  SCIP_Real w0, /**< reference point for w */
6495  SCIP_Real* cx, /**< buffer where to store cut coefficient for x */
6496  SCIP_Real* cy, /**< buffer where to store cut coefficient for y */
6497  SCIP_Real* cw, /**< buffer where to store cut coefficient for w */
6498  SCIP_Real* c0, /**< buffer where to store cut left-hand-side */
6499  SCIP_Bool* success /**< buffer where to indicate whether cut coefficients were computed */
6500  )
6501 {
6502  SCIP_Bool flipx;
6503  SCIP_Bool flipy;
6504  SCIP_Bool flipw;
6505  SCIP_Real tmp;
6506  SCIP_Real xlow;
6507  SCIP_Real ylow;
6508  SCIP_Real xupp;
6509  SCIP_Real yupp;
6510  SCIP_Real c0x;
6511  SCIP_Real c0y;
6512  SCIP_Real c0w;
6513 
6514  assert(scip != NULL);
6515  assert(cx != NULL);
6516  assert(cy != NULL);
6517  assert(cw != NULL);
6518  assert(c0 != NULL);
6519  assert(success != NULL);
6520 
6521  *success = FALSE;
6522  *cx = 0.0;
6523  *cy = 0.0;
6524  *cw = 0.0;
6525  *c0 = 0.0;
6526 
6527  SCIPdebugMsg(scip, "entering points:\n");
6528  SCIPdebugMsg(scip, "x: %9g\t[%9g\t%9g]\n", x0, xl, xu);
6529  SCIPdebugMsg(scip, "y: %9g\t[%9g\t%9g]\n", y0_, yl, yu);
6530  SCIPdebugMsg(scip, "w: %9g\t[%9g\t%9g]\n", w0, wl, wu);
6531 
6532  /* generateCutLTI should have recognized these */
6533  assert(wl >= 0.0 || wu <= 0.0);
6534  assert(!SCIPisInfinity(scip, -wl));
6535  assert(!SCIPisInfinity(scip, wu));
6536 
6537  assert(SCIPisFeasGE(scip, x0, xl));
6538  assert(SCIPisFeasLE(scip, x0, xu));
6539  assert(SCIPisFeasGE(scip, y0_, yl));
6540  assert(SCIPisFeasLE(scip, y0_, yu));
6541 
6542  /* preliminary bound tightening */
6543  if( wl >= 0.0 )
6544  {
6545  if( xl >= 0.0 || yl >= 0.0 || SCIPisLT(scip, xl * yl, wl) )
6546  {
6547  xl = MAX(xl, 0.0);
6548  yl = MAX(yl, 0.0);
6549  }
6550  else if( xu <= 0.0 || yu <= 0.0 || SCIPisLT(scip, xu * yu, wl) )
6551  {
6552  xu = MIN(xu, 0.0);
6553  yu = MIN(yu, 0.0);
6554  }
6555  else
6556  {
6557  /* both variables have mixed sign (xl < 0 && xu > 0 && yl < 0 && yu > 0) and both xl*yl and xu*yu are feasible
6558  * cannot generate cut for this
6559  */
6560  return;
6561  }
6562  }
6563  else
6564  {
6565  if( xl >= 0.0 || yu <= 0.0 || SCIPisGT(scip, xl * yu, wu) )
6566  {
6567  xl = MAX(xl, 0.0);
6568  yu = MIN(yu, 0.0);
6569  }
6570  else if( xu <= 0.0 || yl >= 0.0 || SCIPisGT(scip, xu * yl, wu))
6571  {
6572  xu = MIN(xu, 0.0);
6573  yl = MAX(yl, 0.0);
6574  }
6575  else
6576  {
6577  /* both variables have mixed sign (xl < 0 && xu > 0 && yl < 0 && yu > 0) and both xl*yu and xu*yl are feasible
6578  * cannot generate cut for this
6579  */
6580  return;
6581  }
6582  }
6583 
6584  /* if x or y is fixed now or even infeasible, then do not think about a cut */
6585  if( SCIPisGE(scip, xl, xu) || SCIPisGE(scip, yl, yu) )
6586  return;
6587 
6588  /* reduce to positive orthant by flipping variables */
6589  if( xl < 0.0 )
6590  {
6591  flipx = TRUE;
6592  tmp = xu;
6593  xu = -xl;
6594  xl = -tmp;
6595  x0 = -x0;
6596  }
6597  else
6598  flipx = FALSE;
6599 
6600  if( yl < 0.0 )
6601  {
6602  flipy = TRUE;
6603  tmp = yu;
6604  yu = -yl;
6605  yl = -tmp;
6606  y0_ = -y0_;
6607  }
6608  else
6609  flipy = FALSE;
6610 
6611  if( flipx ^ flipy )
6612  {
6613  flipw = TRUE;
6614  tmp = wu;
6615  wu = -wl;
6616  wl = -tmp;
6617  w0 = -w0;
6618  }
6619  else
6620  flipw = FALSE;
6621 
6622  /* project refpoint into box not only for numerical reasons, but also due to preliminary bound tightening above */
6623  x0 = MIN(xu, MAX(x0, xl));
6624  y0_ = MIN(yu, MAX(y0_, yl));
6625  w0 = MIN(wu, MAX(w0, wl));
6626 
6627  SCIPdebugMsg(scip, "reduced points:\n");
6628  SCIPdebugMsg(scip, "x: %9g\t[%9g\t%9g]\n", x0, xl, xu);
6629  SCIPdebugMsg(scip, "y: %9g\t[%9g\t%9g]\n", y0_, yl, yu);
6630  SCIPdebugMsg(scip, "w: %9g\t[%9g\t%9g]\n", w0, wl, wu);
6631 
6632  if( SCIPisGE(scip, xl * yl, wl) && SCIPisLE(scip, xu * yu, wu) )
6633  {
6634  SCIPdebugMsg(scip, "box for x and y inside feasible region -> nothing to separate\n");
6635  return;
6636  }
6637  if( SCIPisGE(scip, x0 * y0_, w0) )
6638  {
6639  SCIPdebugMsg(scip, "point to separate not below curve -> cannot separate\n");
6640  return;
6641  }
6642 
6643  /* find intersections of halfline from origin
6644  * return if no proper point could be found
6645  */
6646  if( generateCutLTIfindIntersection(scip, 0.0, 0.0, x0, y0_, wl, wu, &xlow, &ylow, &xupp, &yupp) )
6647  return;
6648 
6649  SCIPdebugMsg(scip, "intersections:\n");
6650  SCIPdebugMsg(scip, "lower: %9g\t%9g\tprod %9g\n", xlow, ylow, xlow*ylow);
6651  SCIPdebugMsg(scip, "upper: %9g\t%9g\tprod %9g\n", xupp, yupp, xupp*yupp);
6652 
6653  /* Case 1: If both are outside of bounding box, either NW or SE, then McCormick is sufficient, so return */
6654  if( (xlow <= xl && yupp >= yu) || (ylow <= yl && xupp >= xu) )
6655  return;
6656 
6657  /* There will be at least one cut. Define coefficients and rhs ---will have to change them back if (flipX || flipY) */
6658  if( xlow >= xl && xupp <= xu && ylow >= yl && yupp <= yu )
6659  {
6660  /* Case 2: both are inside. Easy lifting... */
6661  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, FALSE, cx, cy, cw) )
6662  return;
6663 
6664  c0x = *cx * xlow;
6665  c0y = *cy * ylow;
6666  c0w = *cw * wl;
6667  }
6668  else if( xlow >= xl && ylow >= yl && (xupp > xu || yupp > yu) )
6669  {
6670  /* Case 3a and 3b: through lower curve, but not upper. */
6671  if( yupp > yu )
6672  {
6673  /* upper intersect is North; place it within box */
6674  assert(!SCIPisInfinity(scip, yu));
6675  yupp = yu;
6676  xupp = wu / yu;
6677  }
6678  else
6679  {
6680  /* upper intersect is East; place it within box */
6681  assert(!SCIPisInfinity(scip, xu));
6682  xupp = xu;
6683  yupp = wu / xu;
6684  }
6685 
6686  /* find intersection on low curve on half line through new point and (x0,y0_) */
6687  if( generateCutLTIfindIntersection(scip, xupp, yupp, x0, y0_, wl, SCIP_INVALID, &xlow, &ylow, NULL, NULL) )
6688  return;
6689 
6690  /* check whether McCormick is sufficient */
6691  if( xlow < xl || ylow < yl )
6692  return;
6693 
6694  /* lift inequality on lower point */
6695  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, FALSE, cx, cy, cw) )
6696  return;
6697 
6698  c0x = *cx * xlow;
6699  c0y = *cy * ylow;
6700  c0w = *cw * wl;
6701  }
6702  else if( xupp <= xu && yupp <= yu && (xlow < xl || ylow < yl) )
6703  {
6704  /* Case 4a and 4b: viceversa (lift for validity) */
6705  if( ylow < yl )
6706  {
6707  /* upper intersect is South; place it within box */
6708  assert(!SCIPisZero(scip, yl));
6709  ylow = yl;
6710  xlow = wl / yl;
6711  }
6712  else
6713  {
6714  /* upper intersect is West; place it within box */
6715  assert(!SCIPisZero(scip, xl));
6716  xlow = xl;
6717  ylow = wl / xl;
6718  }
6719 
6720  /* find intersection on low curve on half line through new point and (x0,y0) */
6721  if( generateCutLTIfindIntersection(scip, xlow, ylow, x0, y0_, SCIP_INVALID, wu, NULL, NULL, &xupp, &yupp) )
6722  return;
6723 
6724  /* check whether McCormick is sufficient */
6725  if( xupp > xu || yupp > yu )
6726  return;
6727 
6728  /* lift inequality on UPPER point */
6729  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, TRUE, cx, cy, cw) )
6730  return;
6731 
6732  c0x = *cx * xupp;
6733  c0y = *cy * yupp;
6734  c0w = *cw * wu;
6735  }
6736  else if( (xlow < xl && xupp > xu) || (ylow < yl && yupp > yu) )
6737  {
6738  /* Case 5: both outside of bounding box, N and S or W and E. */
6739 #if 0
6740  SCIP_Real xlow2;
6741  SCIP_Real ylow2;
6742  SCIP_Real xupp2;
6743  SCIP_Real yupp2;
6744 #endif
6745 
6746  if( ylow < yl )
6747  {
6748  /* upper intersect is South; place it within box */
6749  assert(!SCIPisZero(scip, yl));
6750  assert(!SCIPisZero(scip, yu));
6751  ylow = yl;
6752  yupp = yu;
6753  xlow = wl / yl;
6754  xupp = wu / yu;
6755  }
6756  else
6757  {
6758  /* upper intersect is West; place it within box */
6759  assert(!SCIPisZero(scip, xl));
6760  assert(!SCIPisZero(scip, xu));
6761  xlow = xl;
6762  xupp = xu;
6763  ylow = wl / xl;
6764  yupp = wu / xu;
6765  }
6766 
6767  SCIPdebugMsg(scip, "New intersections:\n");
6768  SCIPdebugMsg(scip, "lower: %9g\t%9g\tprod %9g\n", xlow, ylow, xlow*ylow);
6769  SCIPdebugMsg(scip, "upper: %9g\t%9g\tprod %9g\n", xupp, yupp, xupp*yupp);
6770 
6771 #if 1
6772  /* Nothing to find. Just separate two inequalities at the same point, just using different support */
6773  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, FALSE, cx, cy, cw) )
6774  {
6775  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, TRUE, cx, cy, cw) )
6776  return;
6777 
6778  c0x = *cx * xupp;
6779  c0y = *cy * yupp;
6780  c0w = *cw * wu;
6781  }
6782  else
6783  {
6784  c0x = *cx * xlow;
6785  c0y = *cy * ylow;
6786  c0w = *cw * wl;
6787  }
6788 
6789 #else
6790  /* find the intersection on the lower (upper) curve on the line through xLP and the upper (lower) point
6791  * this does not seem to work (cuts off solution at nous2), so it is disabled for now
6792  */
6793  if( generateCutLTIfindIntersection(scip, xlow, ylow, x0, y0_, SCIP_INVALID, wu, NULL, NULL, &xupp2, &yupp2) ||
6794  generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp2, yupp2, FALSE, cx, cx, cw) )
6795  {
6796  if( generateCutLTIfindIntersection(scip, xupp, yupp, x0, y0_, wl, SCIP_INVALID, &xlow2, &ylow2, NULL, NULL) ||
6797  generateCutLTIgenMulCoeff(scip, xlow2, ylow2, xupp, yupp, TRUE, cx, cy, cw) )
6798  return;
6799 
6800  c0x = *cx * xupp;
6801  c0y = *cy * yupp;
6802  c0w = *cw * wu;
6803  }
6804  else
6805  {
6806  c0x = *cx * xlow;
6807  c0y = *cy * ylow;
6808  c0w = *cw * wl;
6809  }
6810 #endif
6811  }
6812  else
6813  {
6814  SCIPdebugMsg(scip, "points are in a weird position:\n");
6815  SCIPdebugMsg(scip, "lower: %9g\t%9g\tprod %9g\n", xlow, ylow, xlow*ylow);
6816  SCIPdebugMsg(scip, "upper: %9g\t%9g\tprod %9g\n", xupp, yupp, xupp*yupp);
6817 
6818  return;
6819  }
6820 
6821  SCIPdebugMsg(scip, "cut w.r.t. reduced points: %gx-%g %+gy-%g %+gw-%g >= 0\n",
6822  *cx, c0x, *cy, c0y, *cw, c0w);
6823 
6824  /* re-transform back into original variables */
6825  if( flipx )
6826  *cx = -*cx;
6827  if( flipy )
6828  *cy = -*cy;
6829  if( flipw )
6830  *cw = -*cw;
6831 
6832  *c0 = c0x + c0y + c0w;
6833 
6834  *success = TRUE;
6835 }
6836 
6837 /** tries to generate a cut if constraint quadratic function is factorable and there are linear variables
6838  *
6839  * Computes what is called a lifted tangent inequality described in@n
6840  * Belotti, Miller, Namazifar, Lifted inequalities for bounded products of variables, SIAG/OPT Views-and-News 22:1, 2011
6841  */
6842 static
6844  SCIP* scip, /**< SCIP data structure */
6845  SCIP_CONS* cons, /**< constraint */
6846  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
6847  SCIP_Real* ref, /**< reference solution where to generate the cut */
6848  SCIP_SOL* sol, /**< solution that shall be cutoff, NULL for LP solution */
6849  SCIP_ROWPREP* rowprep, /**< rowprep to store cut data */
6850  SCIP_Bool* success /**< buffer to indicate whether a cut was successfully computed */
6851  )
6852 {
6853  SCIP_CONSDATA* consdata;
6854  SCIP_Real leftminactivity;
6855  SCIP_Real leftmaxactivity;
6856  SCIP_Real leftrefactivity;
6857  SCIP_Real rightminactivity;
6858  SCIP_Real rightmaxactivity;
6859  SCIP_Real rightrefactivity;
6860  SCIP_Real rhsminactivity;
6861  SCIP_Real rhsmaxactivity;
6862  SCIP_Real rhsrefactivity;
6863  SCIP_Real coefleft;
6864  SCIP_Real coefright;
6865  SCIP_Real coefrhs;
6866  SCIP_Real cutlhs;
6867  int i;
6868 
6869  assert(scip != NULL);
6870  assert(cons != NULL);
6871  assert(ref != NULL);
6872  assert(rowprep != NULL);
6873  assert(success != NULL);
6874  /* currently only separate LP solution or solutions given as SCIP_SOL, i.e., no cutgeneration during initlp */
6875  assert(sol != NULL || SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL);
6876 
6877  consdata = SCIPconsGetData(cons);
6878  assert(consdata != NULL);
6879  assert(consdata->nlinvars > 0);
6880  assert(consdata->factorleft != NULL);
6881  assert(consdata->factorright != NULL);
6882 
6883  *success = FALSE;
6884  rowprep->sidetype = SCIP_SIDETYPE_LEFT;
6885 
6886  /* write violated constraints as factorleft * factorright '==' rhs
6887  * where rhs are constraint sides - activity bound of linear part
6888  */
6889  rhsminactivity = consdata->lhs;
6890  rhsmaxactivity = consdata->rhs;
6891  rhsrefactivity = (violside == SCIP_SIDETYPE_LEFT ? consdata->lhs : consdata->rhs);
6892 
6893  for( i = 0; i < consdata->nlinvars; ++i )
6894  {
6895  if( !SCIPisInfinity(scip, -rhsminactivity) )
6896  {
6897  if( consdata->lincoefs[i] < 0.0 )
6898  {
6899  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i])) )
6900  rhsminactivity = -SCIPinfinity(scip);
6901  else
6902  rhsminactivity -= consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
6903  }
6904  else
6905  {
6906  assert(consdata->lincoefs[i] > 0.0);
6907  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i])) )
6908  rhsminactivity = -SCIPinfinity(scip);
6909  else
6910  rhsminactivity -= consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
6911  }
6912  }
6913  if( !SCIPisInfinity(scip, rhsmaxactivity) )
6914  {
6915  if( consdata->lincoefs[i] < 0.0 )
6916  {
6917  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i])) )
6918  rhsmaxactivity = SCIPinfinity(scip);
6919  else
6920  rhsmaxactivity -= consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
6921  }
6922  else
6923  {
6924  assert(consdata->lincoefs[i] > 0.0);
6925  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i])) )
6926  rhsmaxactivity = SCIPinfinity(scip);
6927  else
6928  rhsmaxactivity -= consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
6929  }
6930  }
6931  rhsrefactivity -= consdata->lincoefs[i] * SCIPgetSolVal(scip, sol, consdata->linvars[i]);
6932  }
6933 
6934  if( SCIPisInfinity(scip, -rhsminactivity) || SCIPisInfinity(scip, rhsmaxactivity) )
6935  {
6936  /* if right hand side is unbounded, then cannot do LTI */
6937  return SCIP_OKAY;
6938  }
6939 
6940  if( !SCIPisFeasPositive(scip, rhsminactivity) && !SCIPisFeasNegative(scip, rhsmaxactivity) )
6941  {
6942  /* if right hand side has 0 inside activity, then cannot do anything
6943  * if it has 0.0 as min or max activity, then a usual McCormick should be sufficient, too
6944  */
6945  return SCIP_OKAY;
6946  }
6947 
6948  leftminactivity = consdata->factorleft[consdata->nquadvars];
6949  leftmaxactivity = consdata->factorleft[consdata->nquadvars];
6950  leftrefactivity = consdata->factorleft[consdata->nquadvars];
6951  rightminactivity = consdata->factorright[consdata->nquadvars];
6952  rightmaxactivity = consdata->factorright[consdata->nquadvars];
6953  rightrefactivity = consdata->factorright[consdata->nquadvars];
6954  for( i = 0; i < consdata->nquadvars; ++i )
6955  {
6956  if( !SCIPisInfinity(scip, -leftminactivity) )
6957  {
6958  if( consdata->factorleft[i] > 0.0 )
6959  {
6960  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6961  leftminactivity = -SCIPinfinity(scip);
6962  else
6963  leftminactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6964  }
6965  else if( consdata->factorleft[i] < 0.0 )
6966  {
6967  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6968  leftminactivity = -SCIPinfinity(scip);
6969  else
6970  leftminactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6971  }
6972  }
6973  if( !SCIPisInfinity(scip, leftmaxactivity) )
6974  {
6975  if( consdata->factorleft[i] > 0.0 )
6976  {
6977  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6978  leftmaxactivity = SCIPinfinity(scip);
6979  else
6980  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6981  }
6982  else if( consdata->factorleft[i] < 0.0 )
6983  {
6984  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6985  leftmaxactivity = SCIPinfinity(scip);
6986  else
6987  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6988  }
6989  }
6990  leftrefactivity += consdata->factorleft[i] * ref[i];
6991 
6992  if( !SCIPisInfinity(scip, -rightminactivity) )
6993  {
6994  if( consdata->factorright[i] > 0.0 )
6995  {
6996  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6997  rightminactivity = -SCIPinfinity(scip);
6998  else
6999  rightminactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
7000  }
7001  else if( consdata->factorright[i] < 0.0 )
7002  {
7003  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
7004  rightminactivity = -SCIPinfinity(scip);
7005  else
7006  rightminactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
7007  }
7008  }
7009  if( !SCIPisInfinity(scip, rightmaxactivity) )
7010  {
7011  if( consdata->factorright[i] > 0.0 )
7012  {
7013  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
7014  rightmaxactivity = SCIPinfinity(scip);
7015  else
7016  rightmaxactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
7017  }
7018  else if( consdata->factorright[i] < 0.0 )
7019  {
7020  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
7021  rightmaxactivity = SCIPinfinity(scip);
7022  else
7023  rightmaxactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
7024  }
7025  }
7026  rightrefactivity += consdata->factorright[i] * ref[i];
7027  }
7028 
7029  /* if activities exceed "opposite" infinity, huge bounds seem to be involved, for which the below method is not prepared */
7030  if( SCIPisInfinity(scip, leftminactivity) || SCIPisInfinity(scip, -leftmaxactivity) ||
7031  SCIPisInfinity(scip, rightminactivity) || SCIPisInfinity(scip, -rightmaxactivity) )
7032  return SCIP_OKAY;
7033 
7034  /* if any of the factors is essentially fixed, give up and do usual method (numerically less sensitive, I hope) */
7035  if( SCIPisRelEQ(scip, leftminactivity, leftmaxactivity) || SCIPisRelEQ(scip, rightminactivity, rightmaxactivity) )
7036  return SCIP_OKAY;
7037 
7038  /* success can only be expected for separation of violated x*y <= w, assuming x>=0, y>=0
7039  * @todo we should check this early? */
7040 
7041  /* call Couenne magic */
7043  leftminactivity, leftmaxactivity, leftrefactivity,
7044  rightminactivity, rightmaxactivity, rightrefactivity,
7045  rhsminactivity, rhsmaxactivity, rhsrefactivity,
7046  &coefleft, &coefright, &coefrhs, &cutlhs,
7047  success);
7048 
7049  if( !*success )
7050  return SCIP_OKAY;
7051 
7052  SCIPdebugMsg(scip, "LTI for x[%g,%g] * y[%g,%g] = w[%g,%g]: %gx %+gy %+gw >= %g; feas: %g\n",
7053  leftminactivity, leftmaxactivity, rightminactivity, rightmaxactivity, rhsminactivity, rhsmaxactivity,
7054  coefleft, coefright, coefrhs, cutlhs,
7055  coefleft * leftrefactivity + coefright * rightrefactivity + coefrhs * rhsrefactivity - cutlhs
7056  );
7057 
7058  if( coefleft * leftrefactivity + coefright * rightrefactivity + coefrhs * rhsrefactivity >= cutlhs )
7059  {
7060  SCIPdebugMsg(scip, "does not cutoff point? :-(\n");
7061  *success = FALSE;
7062  return SCIP_OKAY;
7063  }
7064 
7065  /* setup cut coefs for
7066  * coefleft * leftfactor + coefright * rightfactor + coefrhs * w >= cutlhs, where conslhs - lincoefs <= w <= consrhs - lincoefs
7067  */
7068  for( i = 0; i < consdata->nquadvars; ++i )
7069  {
7070  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, consdata->quadvarterms[i].var, coefleft * consdata->factorleft[i] + coefright * consdata->factorright[i]) );
7071  }
7072  SCIPaddRowprepConstant(rowprep, coefleft * consdata->factorleft[i] + coefright * consdata->factorright[i]);
7073 
7074  for( i = 0; i < consdata->nlinvars; ++i )
7075  {
7076  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, consdata->linvars[i], -coefrhs * consdata->lincoefs[i]) );
7077  }
7078  if( coefrhs > 0.0 )
7079  {
7080  /* use coefrhs * w <= coefrhs * (consrhs - lincoefs) */
7081  assert(!SCIPisInfinity(scip, consdata->rhs));
7082  SCIPaddRowprepConstant(rowprep, coefrhs * consdata->rhs);
7083  }
7084  else
7085  {
7086  /* use coefrhs * w <= coeflhs * (conslhs - lincoefs) */
7087  assert(!SCIPisInfinity(scip, -consdata->lhs));
7088  SCIPaddRowprepConstant(rowprep, coefrhs * consdata->lhs);
7089  }
7090  SCIPaddRowprepSide(rowprep, cutlhs);
7091 
7092  rowprep->local = TRUE;
7093 
7094  (void) SCIPsnprintf(rowprep->name, SCIP_MAXSTRLEN, "%s_lti_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
7095 
7096  *success = TRUE;
7097 
7098  return SCIP_OKAY;
7099 }
7100 
7101 /** computes cut coefficients by linearizing a quadratic function */
7102 static
7104  SCIP* scip, /**< SCIP data structure */
7105  SCIP_CONS* cons, /**< constraint */
7106  SCIP_SIDETYPE violside, /**< side for which to generate cut */
7107  SCIP_Real* ref, /**< reference solution where to generate the cut */
7108  SCIP_ROWPREP* rowprep, /**< rowprep to store cut data */
7109  SCIP_Bool* success /**< buffer to indicate whether a cut was successfully computed */
7110  )
7111 {
7112  SCIP_CONSDATA* consdata;
7113  SCIP_BILINTERM* bilinterm;
7114  SCIP_Real constant;
7115  SCIP_Real coef;
7116  SCIP_Real coef2;
7117  SCIP_VAR* var;
7118  int var2pos;
7119  int j;
7120  int k;
7121 
7122  assert(scip != NULL);
7123  assert(cons != NULL);
7124  assert(ref != NULL);
7125  assert(success != NULL);
7126 
7127  consdata = SCIPconsGetData(cons);
7128  assert(consdata != NULL);
7129 
7130  *success = TRUE;
7131 
7132  /* do first-order Taylor for each term */
7133  for( j = 0; j < consdata->nquadvars && *success; ++j )
7134  {
7135  var = consdata->quadvarterms[j].var;
7136 
7137  /* initialize coefficients to linear coefficients of quadratic variables */
7138  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, consdata->quadvarterms[j].lincoef) );
7139 
7140  /* add linearization of square term */
7141  coef = 0.0;
7142  constant = 0.0;
7143  SCIPaddSquareLinearization(scip, consdata->quadvarterms[j].sqrcoef, ref[j],
7144  consdata->quadvarterms[j].nadjbilin == 0 && SCIPvarGetType(var) < SCIP_VARTYPE_CONTINUOUS, &coef, &constant, success);
7145  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, coef) );
7146  SCIPaddRowprepConstant(rowprep, constant);
7147 
7148  /* add linearization of bilinear terms that have var as first variable */
7149  for( k = 0; k < consdata->quadvarterms[j].nadjbilin && *success; ++k )
7150  {
7151  bilinterm = &consdata->bilinterms[consdata->quadvarterms[j].adjbilin[k]];
7152  if( bilinterm->var1 != var )
7153  continue;
7154  assert(bilinterm->var2 != var);
7155  assert(consdata->sepabilinvar2pos != NULL);
7156 
7157  var2pos = consdata->sepabilinvar2pos[consdata->quadvarterms[j].adjbilin[k]];
7158  assert(var2pos >= 0);
7159  assert(var2pos < consdata->nquadvars);
7160  assert(consdata->quadvarterms[var2pos].var == bilinterm->var2);
7161 
7162  coef = 0.0;
7163  coef2 = 0.0;
7164  constant = 0.0;
7165  SCIPaddBilinLinearization(scip, bilinterm->coef, ref[j], ref[var2pos], &coef, &coef2, &constant, success);
7166  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, coef) );
7167  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, bilinterm->var2, coef2) );
7168  SCIPaddRowprepConstant(rowprep, constant);
7169  }
7170  }
7171 
7172  if( !*success )
7173  {
7174  SCIPdebugMsg(scip, "no success in linearization of <%s> in reference point\n", SCIPconsGetName(cons));
7175  return SCIP_OKAY;
7176  }
7177 
7178  rowprep->sidetype = violside;
7179  SCIPaddRowprepSide(rowprep, violside == SCIP_SIDETYPE_LEFT ? consdata->lhs : consdata->rhs);
7180 
7181  (void) SCIPsnprintf(rowprep->name, SCIP_MAXSTRLEN, "%s_side%d_linearization_%d", SCIPconsGetName(cons), violside, SCIPgetNLPs(scip));
7182 
7183  return SCIP_OKAY;
7184 }
7185 
7186 /** helper function to update the best relaxation for a bilinear term when using valid linear inequalities */
7187 static
7189  SCIP* scip, /**< SCIP data structure */
7190  SCIP_VAR* RESTRICT x, /**< first variable */
7191  SCIP_VAR* RESTRICT y, /**< second variable */
7192  SCIP_Real bilincoef, /**< coefficient of the bilinear term */
7193  SCIP_SIDETYPE violside, /**< side of quadratic constraint that is violated */
7194  SCIP_Real refx, /**< reference point for the x variable */
7195  SCIP_Real refy, /**< reference point for the y variable */
7196  SCIP_Real* RESTRICT ineqs, /**< coefficients of each linear inequality; stored as triple (xcoef,ycoef,constant) */
7197  int nineqs, /**< total number of inequalities */
7198  SCIP_Real mccormickval, /**< value of the McCormick relaxation at the reference point */
7199  SCIP_Real* RESTRICT bestcoefx, /**< pointer to update the x coefficient */
7200  SCIP_Real* RESTRICT bestcoefy, /**< pointer to update the y coefficient */
7201  SCIP_Real* RESTRICT bestconst, /**< pointer to update the constant */
7202  SCIP_Real* RESTRICT bestval, /**< value of the best relaxation that have been found so far */
7203  SCIP_Bool* success /**< buffer to store whether we found a better relaxation */
7204  )
7205 {
7206  SCIP_Real constshift[2] = {0.0, 0.0};
7207  SCIP_Real constant;
7208  SCIP_Real xcoef;
7209  SCIP_Real ycoef;
7210  SCIP_Real lbx;
7211  SCIP_Real ubx;
7212  SCIP_Real lby;
7213  SCIP_Real uby;
7214  SCIP_Bool update;
7215  SCIP_Bool overestimate;
7216  int i;
7217 
7218  assert(x != y);
7219  assert(!SCIPisZero(scip, bilincoef));
7220  assert(nineqs >= 0 && nineqs <= 2);
7221  assert(bestcoefx != NULL);
7222  assert(bestcoefy != NULL);
7223  assert(bestconst != NULL);
7224  assert(bestval != NULL);
7225 
7226  /* no inequalities available */
7227  if( nineqs == 0 )
7228  return;
7229  assert(ineqs != NULL);
7230 
7231  lbx = SCIPvarGetLbLocal(x);
7232  ubx = SCIPvarGetUbLocal(x);
7233  lby = SCIPvarGetLbLocal(y);
7234  uby = SCIPvarGetUbLocal(y);
7235  overestimate = (violside == SCIP_SIDETYPE_LEFT);
7236 
7237  /* check cases for which we can't compute a tighter relaxation */
7238  if( SCIPisFeasLE(scip, refx, lbx) || SCIPisFeasGE(scip, refx, ubx)
7239  || SCIPisFeasLE(scip, refy, lby) || SCIPisFeasGE(scip, refy, uby) )
7240  return;
7241 
7242  /* due to the feasibility tolerances of the LP and NLP solver, it might possible that the reference point is
7243  * violating the linear inequalities; to ensure that we compute a valid underestimate, we relax the linear
7244  * inequality by changing its constant part
7245  */
7246  for( i = 0; i < nineqs; ++i )
7247  {
7248  constshift[i] = MAX(0.0, ineqs[3*i] * refx - ineqs[3*i+1] * refy - ineqs[3*i+2]);
7249  SCIPdebugMsg(scip, "constant shift of inequality %d = %.16f\n", constshift[i]);
7250  }
7251 
7252  /* try to use both inequalities */
7253  if( nineqs == 2 )
7254  {
7255  SCIPcomputeBilinEnvelope2(scip, bilincoef, lbx, ubx, refx, lby, uby, refy, overestimate, ineqs[0], ineqs[1],
7256  ineqs[2] + constshift[0], ineqs[3], ineqs[4], ineqs[5] + constshift[1], &xcoef, &ycoef, &constant, &update);
7257 
7258  if( update )
7259  {
7260  SCIP_Real val = xcoef * refx + ycoef * refy + constant;
7261  SCIP_Real relimpr = 1.0 - (REALABS(val - bilincoef * refx * refy) + 1e-4) / (REALABS(*bestval - bilincoef * refx * refy) + 1e-4);
7262  SCIP_Real absimpr = REALABS(val - (*bestval));
7263 
7264  /* update relaxation if possible */
7265  if( relimpr > 0.05 && absimpr > 1e-3 && ((overestimate && SCIPisRelLT(scip, val, *bestval)) || (!overestimate && SCIPisRelGT(scip, val, *bestval))) )
7266  {
7267  *bestcoefx = xcoef;
7268  *bestcoefy = ycoef;
7269  *bestconst = constant;
7270  *bestval = val;
7271  *success = TRUE;
7272  }
7273  }
7274  }
7275 
7276  /* use inequalities individually */
7277  for( i = 0; i < nineqs; ++i )
7278  {
7279  SCIPcomputeBilinEnvelope1(scip, bilincoef, lbx, ubx, refx, lby, uby, refy, overestimate, ineqs[3*i], ineqs[3*i+1],
7280  ineqs[3*i+2] + constshift[i], &xcoef, &ycoef, &constant, &update);
7281 
7282  if( update )
7283  {
7284  SCIP_Real val = xcoef * refx + ycoef * refy + constant;
7285  SCIP_Real relimpr = 1.0 - (REALABS(val - bilincoef * refx * refy) + 1e-4) / (REALABS(mccormickval - bilincoef * refx * refy) + 1e-4);
7286  SCIP_Real absimpr = REALABS(val - (*bestval));
7287 
7288  /* update relaxation if possible */
7289  if( relimpr > 0.05 && absimpr > 1e-3 && ((overestimate && SCIPisRelLT(scip, val, *bestval)) || (!overestimate && SCIPisRelGT(scip, val, *bestval))) )
7290  {
7291  *bestcoefx = xcoef;
7292  *bestcoefy = ycoef;
7293  *bestconst = constant;
7294  *bestval = val;
7295  *success = TRUE;
7296  }
7297  }
7298  }
7299 }
7300 
7301 /* returns the interiority of a reference point w.r.t. given bounds */
7302 static
7304  SCIP* scip, /**< SCIP data structure */
7305  SCIP_Real lbx, /**< lower bound of the first variable */
7306  SCIP_Real ubx, /**< upper bound of the first variable */
7307  SCIP_Real refx, /**< reference point of the first variable */
7308  SCIP_Real lby, /**< lower bound of the second variable */
7309  SCIP_Real uby, /**< upper bound of the second variable */
7310  SCIP_Real refy /**< reference point of the second variable */
7311  )
7312 {
7313  SCIP_Real interiorityx;
7314  SCIP_Real interiorityy;
7315 
7316  interiorityx = MIN(refx-lbx, ubx-refx) / MAX(ubx-lbx, SCIPepsilon(scip)); /*lint !e666*/
7317  interiorityy = MIN(refy-lby, uby-refy) / MAX(uby-lby, SCIPepsilon(scip)); /*lint !e666*/
7318 
7319  return 2.0*MIN(interiorityx, interiorityy);
7320 }
7321 
7322 /** computes cut coefficients for a nonconvex quadratic function */
7323 static
7325  SCIP* scip, /**< SCIP data structure */
7326  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7327  SCIP_CONS* cons, /**< constraint */
7328  SCIP_SIDETYPE violside, /**< side for which to generate cut */
7329  SCIP_Real* ref, /**< reference solution where to generate the cut */
7330  SCIP_ROWPREP* rowprep, /**< rowprep to store cut data */
7331  SCIP_Bool* success /**< buffer to indicate whether a cut was successfully computed */
7332  )
7333 {
7334  SCIP_CONSDATA* consdata;
7335  SCIP_BILINTERM* bilinterm;
7336  SCIP_Real sqrcoef;
7337  SCIP_Real coef;
7338  SCIP_Real coef2;
7339  SCIP_Real constant;
7340  SCIP_VAR* var;
7341  int var2pos;
7342  int j;
7343  int k;
7344 
7345  assert(scip != NULL);
7346  assert(conshdlrdata != NULL);
7347  assert(cons != NULL);
7348  assert(ref != NULL);
7349  assert(success != NULL);
7350 
7351  consdata = SCIPconsGetData(cons);
7352  assert(consdata != NULL);
7353 
7354  rowprep->local = TRUE;
7355  *success = TRUE;
7356 
7357  /* underestimate (secant, McCormick) or linearize each term separately */
7358  for( j = 0; j < consdata->nquadvars && *success; ++j )
7359  {
7360  var = consdata->quadvarterms[j].var;
7361 
7362  /* initialize coefficients to linear coefficients of quadratic variables */
7363  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, consdata->quadvarterms[j].lincoef) );
7364 
7365  sqrcoef = consdata->quadvarterms[j].sqrcoef;
7366  if( sqrcoef != 0.0 )
7367  {
7368  coef = 0.0;
7369  constant = 0.0;
7370  if( (violside == SCIP_SIDETYPE_LEFT && sqrcoef <= 0.0) || (violside == SCIP_SIDETYPE_RIGHT && sqrcoef > 0.0) )
7371  {
7372  /* convex -> linearize */
7373  SCIPaddSquareLinearization(scip, sqrcoef, ref[j], SCIPvarGetType(var) < SCIP_VARTYPE_CONTINUOUS, &coef,
7374  &constant, success);
7375  }
7376  else
7377  {
7378  /* not convex -> secant approximation */
7379  SCIPaddSquareSecant(scip, sqrcoef, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), ref[j], &coef,
7380  &constant, success);
7381  }
7382  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, coef) );
7383  SCIPaddRowprepConstant(rowprep, constant);
7384  }
7385 
7386  /* relax each bilinear term */
7387  for( k = 0; k < consdata->quadvarterms[j].nadjbilin && (*success); ++k )
7388  {
7389  SCIP_VAR* x;
7390  SCIP_VAR* y;
7391  SCIP_Real refx;
7392  SCIP_Real refy;
7393  SCIP_Real lbx;
7394  SCIP_Real ubx;
7395  SCIP_Real lby;
7396  SCIP_Real uby;
7397  int idx;
7398 
7399  idx = consdata->quadvarterms[j].adjbilin[k];
7400  bilinterm = &consdata->bilinterms[idx];
7401  if( bilinterm->var1 != var )
7402  continue;
7403  assert(bilinterm->var2 != var);
7404  assert(consdata->sepabilinvar2pos != NULL);
7405 
7406  var2pos = consdata->sepabilinvar2pos[consdata->quadvarterms[j].adjbilin[k]];
7407  assert(var2pos >= 0);
7408  assert(var2pos < consdata->nquadvars);
7409  assert(consdata->quadvarterms[var2pos].var == bilinterm->var2);
7410 
7411  /* get data of the variables in the bilinear term */
7412  x = var;
7413  y = bilinterm->var2;
7414  refx = ref[j];
7415  refy = ref[var2pos];
7416  lbx = SCIPvarGetLbLocal(x);
7417  ubx = SCIPvarGetUbLocal(x);
7418  lby = SCIPvarGetLbLocal(y);
7419  uby = SCIPvarGetUbLocal(y);
7420  SCIPdebugMsg(scip, "bilinear term %g %s %s with (%g,%g) in [%g,%g]x[%g,%g] overestimate=%u\n", bilinterm->coef,
7421  SCIPvarGetName(x), SCIPvarGetName(y), refx, refy, lbx, ubx, lby, uby, violside == SCIP_SIDETYPE_LEFT);
7422 
7423  /* use the McCormick relaxation for under- or overestimating the bilinear term */
7424  coef = 0.0;
7425  coef2 = 0.0;
7426  constant = 0.0;
7427  SCIPaddBilinMcCormick(scip, bilinterm->coef, lbx, ubx, refx, lby, uby, refy,
7428  violside == SCIP_SIDETYPE_LEFT, &coef, &coef2, &constant, success);
7429  SCIPdebugMsg(scip, "McCormick = %g (%u)\n", refx * coef + refy * coef2 + constant, *success);
7430 
7431  /* tries to compute a tighter relaxation for xy by using valid linear inequalities */
7432  if( conshdlrdata->bilinestimators != NULL && ubx - lbx >= 0.1 && uby - lby >= 0.1
7433  && (SCIPgetNSepaRounds(scip) <= conshdlrdata->bilinineqmaxseparounds || SCIPgetDepth(scip) == 0) )
7434  {
7435  BILINESTIMATOR* bilinestimator;
7436  SCIP_Real mccormick;
7437  SCIP_Real score;
7438  int bilintermidx;
7439 
7440  mccormick = refx * coef + refy * coef2 + constant;
7441  score = getInteriority(scip, lbx, ubx, refx, lby, uby, refy);
7442 
7443  /* get data for bilinear term */
7444  bilintermidx = consdata->bilintermsidx[idx];
7445  assert(conshdlrdata->bilinestimators != NULL);
7446  bilinestimator = &(conshdlrdata->bilinestimators[bilintermidx]);
7447  assert(bilinestimator->x == x);
7448  assert(bilinestimator->y == y);
7449 
7450  /* reset the last improvement factor (used for getting better branching decisions) */
7451  bilinestimator->lastimprfac = 0.0;
7452 
7453  /* compute tighter relaxation for xy if the current score is large enough */
7454  if( SCIPisGE(scip, score, conshdlrdata->minscorebilinterms)
7455  && bilinestimator->nineqoverest + bilinestimator->ninequnderest > 0 )
7456  {
7457  SCIP_Real bestval = mccormick;
7458  SCIP_Bool updaterelax = FALSE;
7459 
7460  /*
7461  * note that we check the sign of the bilinear coefficient together with violside in
7462  * updateBilinearRelaxation in order to decide whether a valid under- or overestimate can be computed
7463  */
7464 
7465  /* use overestimates */
7466  updateBilinearRelaxation(scip, x, y, bilinterm->coef, violside, refx, refy, bilinestimator->ineqoverest,
7467  bilinestimator->nineqoverest, mccormick, &coef, &coef2, &constant, &bestval, &updaterelax);
7468 
7469  /* use underestimates */
7470  updateBilinearRelaxation(scip, x, y, bilinterm->coef, violside, refx, refy, bilinestimator->inequnderest,
7471  bilinestimator->ninequnderest, mccormick, &coef, &coef2, &constant, &bestval, &updaterelax);
7472 
7473  SCIPdebugMsg(scip, "found better relaxation value: %u (%g)\n", updaterelax, bestval);
7474 
7475  /* check whether the new relaxation is under- or overestimating xy properly */
7476  if( updaterelax )
7477  {
7478  /* update improvement factor */
7479  bilinestimator->lastimprfac = 1.0 - REALABS(bestval - bilinterm->coef * refx * refy) / REALABS(mccormick - bilinterm->coef * refx * refy);
7480 
7481 #ifndef NDEBUG
7482  assert(SCIPisEQ(scip, bestval, coef * refx + coef2 * refy + constant));
7483  if( violside == SCIP_SIDETYPE_LEFT )
7484  {
7485  assert(SCIPisRelGE(scip, bestval, bilinterm->coef * refx * refy));
7486  assert(SCIPisRelLE(scip, bestval, mccormick));
7487  }
7488  else
7489  {
7490  assert(SCIPisRelLE(scip, bestval, bilinterm->coef * refx * refy));
7491  assert(SCIPisRelGE(scip, bestval, mccormick));
7492  }
7493 #endif
7494  }
7495  }
7496  }
7497 
7498  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, coef) );
7499  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, bilinterm->var2, coef2) );
7500  SCIPaddRowprepConstant(rowprep, constant);
7501  }
7502  }
7503 
7504  if( !*success )
7505  {
7506  SCIPdebugMsg(scip, "no success to find estimator for nonconvex <%s>\n", SCIPconsGetName(cons));
7507  return SCIP_OKAY;
7508  }
7509 
7510  rowprep->sidetype = violside;
7511  SCIPaddRowprepSide(rowprep, violside == SCIP_SIDETYPE_LEFT ? consdata->lhs : consdata->rhs);
7512 
7513  (void) SCIPsnprintf(rowprep->name, SCIP_MAXSTRLEN, "%s_side%d_estimation_%d", SCIPconsGetName(cons), violside, SCIPgetNLPs(scip));
7514 
7515  return SCIP_OKAY;
7516 }
7517 
7518 /** generates a cut based on linearization (if convex) or McCormick (if nonconvex) in a given reference point */
7519 static
7521  SCIP* scip, /**< SCIP data structure */
7522  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7523  SCIP_CONS* cons, /**< constraint */
7524  SCIP_Real* ref, /**< reference solution where to generate the cut */
7525  SCIP_SOL* sol, /**< point that we aim to separate, or NULL for LP solution */
7526  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
7527  SCIP_ROW** row, /**< storage for cut */
7528  SCIP_Real* efficacy, /**< buffer to store efficacy of row in reference solution, or NULL if not of interest */
7529  SCIP_Bool checkcurvmultivar, /**< are we allowed to check the curvature of a multivariate quadratic function, if not done yet */
7530  SCIP_Real minefficacy /**< minimal required efficacy */
7531  )
7532 {
7533  SCIP_CONSHDLRDATA* conshdlrdata;
7534  SCIP_CONSDATA* consdata;
7535  SCIP_ROWPREP* rowprep;
7536  SCIP_Bool success;
7537  SCIP_Real viol = 0.0;
7538 
7539  assert(scip != NULL);
7540  assert(conshdlr != NULL);
7541  assert(cons != NULL);
7542  assert(ref != NULL);
7543  assert(row != NULL);
7544 
7545  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7546  assert(conshdlrdata != NULL);
7547 
7548  consdata = SCIPconsGetData(cons);
7549  assert(consdata != NULL);
7550  assert(violside != SCIP_SIDETYPE_LEFT || !SCIPisInfinity(scip, -consdata->lhs));
7551  assert(violside != SCIP_SIDETYPE_RIGHT || !SCIPisInfinity(scip, consdata->rhs));
7552 
7553  *row = NULL;
7554 
7556  success = FALSE;
7557 
7558  /* if constraint function is factorable, then try to use factorable form to generate cut */
7559  if( consdata->factorleft != NULL )
7560  {
7561  if( consdata->nlinvars == 0 )
7562  {
7563  SCIP_CALL( generateCutFactorable(scip, cons, violside, ref, rowprep, &success) );
7564  }
7565  else if( sol != NULL || SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
7566  {
7567  /* generateCutLTI needs reference values also for the linear variables, which we only have if sol is given or LP has been solved */
7568  SCIP_CALL( generateCutLTI(scip, cons, violside, ref, sol, rowprep, &success) );
7569  }
7570  }
7571 
7572  /* if constraint is not factorable or failed to generate cut, try default method */
7573  if( !success )
7574  {
7575  SCIP_CALL( checkCurvature(scip, cons, checkcurvmultivar) );
7576 
7577  if( (violside == SCIP_SIDETYPE_LEFT && consdata->isconcave) || (violside == SCIP_SIDETYPE_RIGHT && consdata->isconvex) )
7578  {
7579  SCIP_CALL( generateCutConvex(scip, cons, violside, ref, rowprep, &success) );
7580  }
7581  else
7582  {
7583  SCIP_CALL( generateCutNonConvex(scip, conshdlrdata, cons, violside, ref, rowprep, &success) );
7584  }
7585 
7586  SCIP_CALL( SCIPaddRowprepTerms(scip, rowprep, consdata->nlinvars, consdata->linvars, consdata->lincoefs) );
7587  }
7588 
7589  /* check if reference point violates cut at least a little bit */
7590  if( success && !SCIPisInfinity(scip, -minefficacy) )
7591  {
7592  viol = SCIPgetRowprepViolation(scip, rowprep, sol);
7593  if( viol <= 0.0 ) /*lint !e644*/
7594  {
7595  SCIPdebugMsg(scip, "skip cut for constraint <%s> because efficacy %g too low (< %g)\n", SCIPconsGetName(cons), viol, minefficacy);
7596  success = FALSE;
7597  }
7598  }
7599 
7600  /* cleanup and improve cut */
7601  if( success )
7602  {
7603  SCIP_Real coefrange;
7604 
7605  /* merge terms */
7606  SCIPmergeRowprepTerms(scip, rowprep);
7607 
7608  /* improve coefficients */
7609  SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, conshdlrdata->cutmaxrange, minefficacy, &coefrange, &viol) );
7610  success = coefrange <= conshdlrdata->cutmaxrange;
7611  }
7612 
7613  /* check that side is finite */ /*lint --e{514} */
7614  success &= !SCIPisInfinity(scip, REALABS(rowprep->side)); /*lint !e514*/
7615 
7616  /* check whether maximal coef is finite, if any */ /*lint --e{514} */
7617  success &= (rowprep->nvars == 0) || !SCIPisInfinity(scip, REALABS(rowprep->coefs[0])); /*lint !e514*/
7618 
7619  /* check if reference point violates cut sufficiently */
7620  if( success && !SCIPisInfinity(scip, -minefficacy) && viol < minefficacy ) /*lint !e644*/
7621  {
7622  SCIPdebugMsg(scip, "skip cut for constraint <%s> because efficacy %g too low (< %g)\n", SCIPconsGetName(cons), viol, minefficacy);
7623  success = FALSE;
7624  }
7625 
7626  /* generate row */
7627  if( success )
7628  {
7629  SCIP_CALL( SCIPgetRowprepRowCons(scip, row, rowprep, SCIPconsGetHdlr(cons)) );
7630 
7631  SCIPdebugMsg(scip, "found cut <%s>, lhs=%g, rhs=%g, mincoef=%g, maxcoef=%g, range=%g, nnz=%d, efficacy=%g\n",
7632  SCIProwGetName(*row), SCIProwGetLhs(*row), SCIProwGetRhs(*row),
7633  rowprep->nvars > 0 ? rowprep->coefs[rowprep->nvars-1] : 0.0, rowprep->nvars > 0 ? rowprep->coefs[0] : 0.0,
7634  rowprep->nvars > 0 ? rowprep->coefs[0]/rowprep->coefs[rowprep->nvars-1] : 1.0,
7635  SCIProwGetNNonz(*row), viol); /*lint !e414 */
7636 
7637  if( efficacy != NULL )
7638  *efficacy = viol;
7639  }
7640 
7641  SCIPfreeRowprep(scip, &rowprep);
7642 
7643  return SCIP_OKAY;
7644 }
7645 
7646 /** computes eigen decomposition of A, where \f$ f(x) = x^T A x + b^T x \f$.
7647  *
7648  * The eigen decomposition is given by A = P D P^T, where D is diagonal formed by the eigenvalues and P is orthonormal
7649  * whose columns are the eigenvectors; we also compute b^T * P, in case one needs the change of variables P^T x = y <=>
7650  * x = P y We store P^T in an array, specifically, in consdata->eigenvectors we store P^T row-wise, i.e., the first row
7651  * of P^T is stored in eigenvector[0..n-1], the second row is stored in eigenvectors[n..2n-1], etc; equivalently, the
7652  * first eigenvector is eigenvector[0..n-1], the second one is eigenvectors[n..2n-1], etc.
7653  *
7654  * @todo: - at the moment of writing, checkCurvature computes the eigenvalues (and vectors) for determining curvature
7655  * when it can't to it via other considerations. so one could try to merge both methods together.
7656  * - it seems that if A is of the form [I 0; 0 A'], one only needs to compute the decomposition for A' so one
7657  * could do better in terms of memory and speed. For instance, when the matrix is diagonal, the eigenvectors
7658  * are the identity matrix and the eigenvalues are readily available from the constraint, so one could adapt
7659  * the functions that uses the eigenvectors in this particular case. One could also think about storing the
7660  * eigenvectors in a sparse fashion, though eigenvectors are seldom sparse.
7661  */
7662 static
7664  SCIP* scip, /**< SCIP data structure */
7665  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7666  SCIP_CONS* cons /**< constraint */
7667  )
7668 {
7669  SCIP_CONSDATA* consdata;
7670  int n;
7671  int nn;
7672  int row;
7673  int col;
7674  int i;
7675  int j;
7676  double* matrix;
7677  SCIP_HASHMAP* var2index;
7678 
7679  SCIPdebugMsg(scip, "computing ED for cons %s\n", SCIPconsGetName(cons));
7680 
7681  assert(scip != NULL);
7682  assert(conshdlr != NULL);
7683  assert(cons != NULL);
7684 
7685  consdata = SCIPconsGetData(cons);
7686  assert(consdata != NULL);
7687 
7688  /* function has to be convex with finite rhs or concave with finite lhs */
7689  assert((consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
7690  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)));
7691 
7692  /* can't compute eigenvectors without IPOPT */
7693  if( !SCIPisIpoptAvailableIpopt() )
7694  {
7695  consdata->isedavailable = FALSE;
7696  return SCIP_OKAY;
7697  }
7698 
7699  /* @todo: - it seems that if A is of the form [I 0; 0 A'], one only needs to compute the decomposition for A'
7700  * so one could do better in terms of memory and speed
7701  * - if n too big don't compute SVD
7702  */
7703  n = consdata->nquadvars;
7704 
7705  /* do not compute eigendecomposition if n is too large */
7706  nn = n * n;
7707  if( nn < 0 || (unsigned) (int) nn > UINT_MAX / sizeof(SCIP_Real) )
7708  {
7709  SCIPdebugMsg(scip, "n is too large to compute eigendecomposition\n");
7710  consdata->isedavailable = FALSE;
7711  return SCIP_OKAY;
7712  }
7713 
7714  /* we just need to pass the upper triangle of A since it is symmetric; build it here */
7715  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->eigenvectors, nn) );
7716  matrix = consdata->eigenvectors;
7717  BMSclearMemoryArray(matrix, nn);
7718 
7719  /* @todo if we are called in solving stage (or late from initsol), we can avoid the hashmap by using sepabilinvar2pos */
7720  SCIP_CALL( SCIPhashmapCreate(&var2index, SCIPblkmem(scip), n) );
7721 
7722  for( i = 0; i < n; ++i )
7723  {
7724  SCIP_CALL( SCIPhashmapInsert(var2index, consdata->quadvarterms[i].var, (void*)(size_t)i) );
7725  matrix[i*n + i] = consdata->quadvarterms[i].sqrcoef;
7726 #ifdef DEBUG_PROJ
7727  printf("inserting in position %d, value %g\n", i*n + i, consdata->quadvarterms[i].sqrcoef);
7728 #endif
7729  }
7730 
7731  for( i = 0; i < consdata->nbilinterms; ++i )
7732  {
7733  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var1));
7734  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var2));
7735  row = (int)(size_t)SCIPhashmapGetImage(var2index, consdata->bilinterms[i].var1);
7736  col = (int)(size_t)SCIPhashmapGetImage(var2index, consdata->bilinterms[i].var2);
7737  if( row < col )
7738  {
7739  matrix[row * n + col] = consdata->bilinterms[i].coef/2;
7740 #ifdef DEBUG_PROJ
7741  printf("inserting in position %d, value %g\n", row*n + col, consdata->bilinterms[i].coef/2);
7742 #endif
7743  }
7744  else
7745  {
7746  matrix[col * n + row] = consdata->bilinterms[i].coef/2;
7747 #ifdef DEBUG_PROJ
7748  printf("inserting in position %d, value %g\n", col*n + row, consdata->bilinterms[i].coef/2);
7749 #endif
7750  }
7751  }
7752 
7753 #ifdef DEBUG_PROJ
7754  printf("matrix built:\n");
7755  for( i = 0; i < n; i++ )
7756  {
7757  for( j = 0; j < n; j++ )
7758  printf("%g ", matrix[i*n + j]);
7759  printf("\n");
7760  }
7761 #endif
7762 
7763  /* compute eigenvalues and eigenvectors */
7764  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->eigenvalues, n) );
7765 
7766  if( LapackDsyev(TRUE, n, matrix, consdata->eigenvalues) != SCIP_OKAY )
7767  {
7768  SCIPdebugMsg(scip, "couldn't compute ED for cons %s\n", SCIPconsGetName(cons));
7769  consdata->isedavailable = FALSE;
7770  }
7771  else
7772  {
7773  consdata->isedavailable = TRUE;
7774 
7775  /* compute b^T*P */
7776  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &consdata->bp, n) );
7777  for( i = 0; i < n; i++ )
7778  for( j = 0; j < n; j++ )
7779  consdata->bp[i] += consdata->quadvarterms[j].lincoef * matrix[i*n + j];
7780 
7781 #ifdef DEBUG_PROJ
7782  printf("eigenvalues:\n");
7783  for( j = 0; j < n; j++ )
7784  printf("%g ", consdata->eigenvalues[j]);
7785 
7786  printf("\neigenvectors (P^T):\n");
7787  for( i = 0; i < n; i++ )
7788  {
7789  for( j = 0; j < n; j++ )
7790  printf("%g ", matrix[i*n + j]);
7791  printf("\n");
7792  }
7793 
7794  printf("b*P^T:\n");
7795  for( j = 0; j < n; j++ )
7796  printf("%g ", consdata->bp[j]);
7797  printf("svd computed successfully\n");
7798 #endif
7799  }
7800 
7801  SCIPhashmapFree(&var2index);
7802 
7803  return SCIP_OKAY;
7804 }
7805 
7806 /** computes an interior point for the quadratic part of the convex constraint
7807  *
7808  * There are different methods for computing the interior point
7809  * - 'a'ny: solves min 0, f(x) <= rhs, x in bounds
7810  * - 'm'ost interior: solves min f(x), x in bounds
7811  *
7812  * @todo: other methods for computing an interior point?
7813  */
7814 static
7816  SCIP* scip, /**< SCIP data structure */
7817  SCIP_CONS* cons, /**< constraint */
7818  char method, /**< method for computing interior point ('a' any point, 'm'ost interior) */
7819  SCIP_Bool* success /**< buffer to store if an interior point was found */
7820  )
7821 {
7822  SCIP_CONSDATA* consdata;
7823  SCIP_QUADELEM* nlrowquadelems;
7824  SCIP_NLPIPROBLEM* prob;
7825  SCIP_NLPI* nlpi;
7826  SCIP_Real* interiorpoint;
7827  SCIP_Real* lbs;
7828  SCIP_Real* ubs;
7829  SCIP_Real* lincoefs;
7830  SCIP_Real nlpiside;
7831  char probname[SCIP_MAXSTRLEN];
7832  int* lininds;
7833  int nlrownquadelems;
7834  int nquadvars;
7835  int i;
7836 
7837  assert(scip != NULL);
7838  assert(cons != NULL);
7839 
7840  assert(success != NULL);
7841  *success = FALSE;
7842 
7843  consdata = SCIPconsGetData(cons);
7844  assert(consdata != NULL);
7845 
7846  assert((consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
7847  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)));
7848 
7849  /* need an NLP solver */
7850  if( SCIPgetNNlpis(scip) == 0 )
7851  return SCIP_OKAY;
7852 
7853  nlpi = NULL;
7854  prob = NULL;
7855  lbs = NULL;
7856  ubs = NULL;
7857  lincoefs = NULL;
7858  lininds = NULL;
7859 
7860 #ifdef SCIP_DEBUG_INT
7861  SCIPinfoMessage(scip, NULL, "Computing interior point for\n");
7862  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
7863  SCIPinfoMessage(scip, NULL, ";\n");
7864 #endif
7865 
7866  /* in the convex case, we try to find an interior point of x^T A x + b^T x <= rhs - maximum activity linear part
7867  * in the concave case: lhs - minimum activity linear part <= x^T A x + b^T x; we compute activities ourselves,
7868  * since consdata->max(min)linactivity are only computed when lhs (rhs) is finite and this not always holds
7869  */
7870  if( consdata->isconvex )
7871  {
7872  /* compute maximum activity */
7873  nlpiside = 0;
7874  for( i = 0; i < consdata->nlinvars; ++i )
7875  {
7876  if( consdata->lincoefs[i] >= 0.0 )
7877  {
7878  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i]) ) )
7879  nlpiside = SCIPinfinity(scip);
7880  else
7881  nlpiside += consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
7882  }
7883  else
7884  {
7885  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i]) ) )
7886  nlpiside = SCIPinfinity(scip);
7887  else
7888  nlpiside += consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
7889  }
7890 
7891  if( SCIPisInfinity(scip, nlpiside) )
7892  {
7893  SCIPdebugMsg(scip, "maximum activity is infinity: there is no interior point for fun <= rhs - maxlinactivity!\n");
7894  return SCIP_OKAY;
7895  }
7896  }
7897 
7898  if( consdata->nlinvars == 0 )
7899  nlpiside = INTERIOR_EPS;
7900 
7901  nlpiside = consdata->rhs - nlpiside;
7902  }
7903  else
7904  {
7905  /* compute minimum activity */
7906  nlpiside = 0;
7907  for( i = 0; i < consdata->nlinvars; ++i )
7908  {
7909  if( consdata->lincoefs[i] >= 0.0 )
7910  {
7911  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i])) )
7912  nlpiside = -SCIPinfinity(scip);
7913  else
7914  nlpiside += consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
7915  }
7916  else
7917  {
7918  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i])) )
7919  nlpiside = -SCIPinfinity(scip);
7920  else
7921  nlpiside += consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
7922  }
7923 
7924  if( SCIPisInfinity(scip, -nlpiside) )
7925  {
7926  SCIPdebugMsg(scip, "minimum activity is -infinity: there is no interior point for fun >= lhs - minlinactivity!\n");
7927  return SCIP_OKAY;
7928  }
7929  }
7930 
7931  if( consdata->nlinvars == 0 )
7932  nlpiside = INTERIOR_EPS;
7933 
7934  nlpiside = consdata->lhs - nlpiside;
7935  }
7936 
7937  nquadvars = consdata->nquadvars;
7938 
7939  /* if we are looking for any interior point and the 0 is one, then use it */
7940  if( method == 'a' && ((consdata->isconvex && SCIPisGE(scip, nlpiside, 0.0))
7941  || (consdata->isconcave && SCIPisLE(scip, nlpiside, 0.0))) )
7942  {
7943  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &(consdata->interiorpoint), nquadvars) );
7944 
7945  *success = TRUE;
7946  goto TERMINATE;
7947  }
7948 
7949  /* build nlrow */
7950  if( consdata->nlrow == NULL )
7951  {
7952  SCIP_CALL( createNlRow(scip, cons) );
7953  assert(consdata->nlrow != NULL);
7954  }
7955 
7956  nlpi = SCIPgetNlpis(scip)[0];
7957  assert(nlpi != NULL);
7958 
7959  /* initializing the subproblem */
7960  (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "%s_subquad", SCIPgetProbName(scip));
7961  SCIP_CALL( SCIPnlpiCreateProblem(nlpi, &prob, probname) );
7962  assert(prob != NULL);
7963 
7964 #ifdef SCIP_DEBUG_INT
7966 #endif
7967  /* TODO: maybe one should set some generous iteration limit and/or a timelimit (remaining scip solve time)? */
7968 
7969  /* ask for memory to store data needed to create vars and linear coefficients */
7970  SCIP_CALL( SCIPallocBufferArray(scip, &lbs, nquadvars) );
7971  SCIP_CALL( SCIPallocBufferArray(scip, &ubs, nquadvars) );
7972  SCIP_CALL( SCIPallocBufferArray(scip, &lininds, nquadvars) );
7973  SCIP_CALL( SCIPallocBufferArray(scip, &lincoefs, nquadvars) );
7974 
7975  /* get bounds and linear coefficients */
7976  for( i = 0; i < nquadvars; i++ )
7977  {
7978  lbs[i] = SCIPvarGetLbGlobal(consdata->quadvarterms[i].var);
7979  ubs[i] = SCIPvarGetUbGlobal(consdata->quadvarterms[i].var);
7980 
7981  lincoefs[i] = consdata->quadvarterms[i].lincoef;
7982  lininds[i] = i;
7983  }
7984 
7985  /* add vars */
7986  SCIP_CALL( SCIPnlpiAddVars(nlpi, prob, nquadvars, lbs, ubs, NULL) );
7987 
7988  /* get nlrow info */
7989  nlrownquadelems = SCIPnlrowGetNQuadElems(consdata->nlrow);
7990  nlrowquadelems = SCIPnlrowGetQuadElems(consdata->nlrow);
7991 
7992 #ifndef NDEBUG
7993  {
7994  SCIP_VAR** nlrowquadvars;
7995 
7996  nlrowquadvars = SCIPnlrowGetQuadVars(consdata->nlrow);
7997  for( i = 0; i < nlrownquadelems; i++ )
7998  {
7999  assert(nlrowquadvars[nlrowquadelems[i].idx1] == consdata->quadvarterms[nlrowquadelems[i].idx1].var);
8000  assert(nlrowquadvars[nlrowquadelems[i].idx2] == consdata->quadvarterms[nlrowquadelems[i].idx2].var);
8001  }
8002  }
8003 #endif
8004 
8005  (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "%s", SCIPconsGetName(cons));
8006 
8007  switch( method )
8008  {
8009  case 'a':
8010  /* add constraint */
8011  if( consdata->isconvex )
8012  {
8013  SCIP_CALL( SCIPnlpiAddConstraints(nlpi, prob, 1, NULL, &nlpiside, &nquadvars, &lininds, &lincoefs,
8014  &nlrownquadelems, &nlrowquadelems, NULL, NULL, NULL) );
8015  }
8016  else
8017  {
8018  SCIP_CALL( SCIPnlpiAddConstraints(nlpi, prob, 1, &nlpiside, NULL, &nquadvars, &lininds, &lincoefs,
8019  &nlrownquadelems, &nlrowquadelems, NULL, NULL, NULL) );
8020  }
8021  break;
8022 
8023  case 'm':
8024  /* add objective */
8025  if( consdata->isconvex )
8026  {
8027  SCIP_CALL( SCIPnlpiSetObjective(nlpi, prob, nquadvars, lininds, lincoefs,
8028  nlrownquadelems, nlrowquadelems, NULL, NULL, 0.0) );
8029  }
8030  else
8031  {
8032  /* NLPI assumes minimization: change signs */
8033  for( i = 0; i < nquadvars; i++ )
8034  lincoefs[i] *= -1;
8035 
8036  /* WARNING: this pointer is not ours, information should be restored! */
8037  for( i = 0; i < nlrownquadelems; i++ )
8038  nlrowquadelems->coef *= -1;
8039 
8040  SCIP_CALL( SCIPnlpiSetObjective(nlpi, prob, nquadvars, lininds, lincoefs,
8041  nlrownquadelems, nlrowquadelems, NULL, NULL, 0.0) );
8042 
8043  /* WARNING: restore information! */
8044  for( i = 0; i < nlrownquadelems; i++ )
8045  nlrowquadelems->coef *= -1;
8046  }
8047  break;
8048 
8049  default:
8050  SCIPerrorMessage("undefined method for computing interior point: %c\n", method);
8051  return SCIP_INVALIDDATA;
8052  }
8053 
8054  /* set NLP tolerances; we don't really need an optimal solution to this NLP */
8055  SCIP_CALL( SCIPnlpiSetRealPar(nlpi, prob, SCIP_NLPPAR_FEASTOL, SCIPfeastol(scip)) ); /*lint !e666*/
8056  SCIP_CALL( SCIPnlpiSetRealPar(nlpi, prob, SCIP_NLPPAR_RELOBJTOL, MAX(SCIPfeastol(scip), SCIPdualfeastol(scip))) ); /*lint !e666*/
8057 
8058  /* solve NLP problem */
8059  SCIP_CALL( SCIPnlpiSolve(nlpi, prob) );
8060 
8061  /* check termination status */
8062  if( SCIPnlpiGetTermstat(nlpi, prob) != SCIP_NLPTERMSTAT_OKAY )
8063  {
8064  SCIPdebugMsg(scip, "cons <%s>: NLP Solver termination status not okay: %d\n",
8065  SCIPconsGetName(cons), SCIPnlpiGetTermstat(nlpi, prob));
8066  *success = FALSE;
8067  goto TERMINATE;
8068  }
8069 
8070  /* check solution status */
8071  switch( SCIPnlpiGetSolstat(nlpi, prob) )
8072  {
8076  /* fallthrough */
8077  SCIPdebugMsg(scip, "cons <%s>: found an interior point. solution status: %d, termination status: %d\n",
8078  SCIPconsGetName(cons), SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
8079  break;
8080 
8084  /* fallthrough */
8085  /* TODO: we could still use the point, and let evaluateGauge decide whether the point is interior or not */
8086  SCIPdebugMsg(scip, "cons <%s>: failed to find an interior point. solution status: %d, termination status: %d\n",
8087  SCIPconsGetName(cons), SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
8088  goto TERMINATE;
8089 
8091  default:
8092  /* fallthrough */
8093  SCIPerrorMessage("cons <%s>: undefined behaviour of NLP Solver. solution status: %d, termination status: %d\n",
8094  SCIPconsGetName(cons), SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
8095  SCIPABORT();
8096  goto TERMINATE; /*lint !e527*/
8097  }
8098 
8099  /* fetch solution
8100  * note: nlpiGetSolution (at least for IPOPT) makes interiorpoint point to the internal solution stored in the
8101  * nlpi problem data structure; we need to copy it here because it will be destroyed once the problem is free'd
8102  */
8103  SCIP_CALL( SCIPnlpiGetSolution(nlpi, prob, &interiorpoint, NULL, NULL, NULL, NULL) );
8104 
8105  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(consdata->interiorpoint), nquadvars) );
8106 
8107  for( i = 0; i < nquadvars; i++ )
8108  {
8109  if( SCIPisFeasZero(scip, interiorpoint[i]) )
8110  consdata->interiorpoint[i] = 0.0;
8111  else
8112  consdata->interiorpoint[i] = interiorpoint[i];
8113  }
8114 
8115  *success = TRUE;
8116 
8117 TERMINATE:
8118 
8119 #ifdef SCIP_DEBUG_INT
8120  printf("Computation of interior point for cons <%s>:\n", SCIPconsGetName(cons));
8121  printf(" - has %d linear variables\n", consdata->nlinvars);
8122  if( consdata->isconvex )
8123  {
8124  printf(" - is convex. rhs: %g maximum activity of linear variables: %g\n", consdata->rhs, consdata->rhs - nlpiside);
8125  printf(" - searched for point whose quadratic part is <= %g\n", nlpiside);
8126  }
8127  else
8128  {
8129  printf(" - is concave. lhs: %g minimum activity of linear variables: %g\n", consdata->lhs, consdata->lhs - nlpiside);
8130  printf(" - searched for point whose quadratic part is >= %g\n", nlpiside);
8131  }
8132 
8133  if( *success )
8134  {
8135  if( prob == NULL )
8136  {
8137  printf("Computation successful, 0 is interior point.\n");
8138  for( i = 0; i < nquadvars; i++ )
8139  {
8140  assert(consdata->interiorpoint[i] == 0.0);
8141  }
8142  }
8143  else
8144  {
8145  printf("Computation successful, NLP soltat: %d, termstat: %d\nPoint found:\n",
8146  SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
8147  for( i = 0; i < nquadvars; i++ )
8148  {
8149  printf("%s = %g\n", SCIPvarGetName(consdata->quadvarterms[i].var), consdata->interiorpoint[i]);
8150  }
8151  }
8152  }
8153  else
8154  {
8155  printf("Computation failed. NLP soltat: %d, termstat: %d\n",
8156  SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
8157  printf("run with SCIP_DEBUG for more info\n");
8158  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
8159  SCIPinfoMessage(scip, NULL, ";\n");
8160  /* FIXME: instance camshape100 says that there is no interior point (interior empty)
8161  * is there something intelligent that can be said?
8162  */
8163  }
8164 #endif
8165 
8166  /* free memory */
8167  SCIPfreeBufferArrayNull(scip, &lbs);
8168  SCIPfreeBufferArrayNull(scip, &ubs);
8169  SCIPfreeBufferArrayNull(scip, &lininds);
8170  SCIPfreeBufferArrayNull(scip, &lincoefs);
8171 
8172  if( prob != NULL )
8173  {
8174  SCIP_CALL( SCIPnlpiFreeProblem(nlpi, &prob) );
8175  }
8176 
8177  return SCIP_OKAY;
8178 }
8179 
8180 /** compute gauge function of the set \f$S - s_0\f$ where \f$ S = \{ x : f(x) \le c \}\f$ and \f$ s_0 \in \mathring S\f$.
8181  *
8182  * Here, \f$ f(x) \f$ is a purely quadratic (i.e, all \f$x\f$ variables appear in a bilinear or quadratic term).
8183  * Explicitly, \f$ f(x) = \pm x^T A x \pm b^T x \f$ depending whether \f$A\f$
8184  * is positive semidefinite (+) or negative semidefinite (-).
8185  * The constant \f$c\f$ is rhs - maximum activity of the purely linear part of the constraint
8186  * if \f$A \succeq 0\f$ and minimum activity - lhs if \f$A \preceq 0\f$.
8187  * This is computed only at INITSOL.
8188  *
8189  * The method does:
8190  * 1. compute interior point
8191  * 2. compute gauge function
8192  */
8193 static
8195  SCIP* scip, /**< SCIP data structure */
8196  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8197  SCIP_CONS* cons /**< constraint */
8198  )
8199 {
8200  SCIP_CONSHDLRDATA* conshdlrdata;
8201  SCIP_CONSDATA* consdata;
8202  SCIP_QUADVARTERM* quadvarterm;
8203  SCIP_BILINTERM* bilinterm;
8204  SCIP_Bool success;
8205  SCIP_Bool convex;
8206  int i;
8207  int j;
8208 
8209  assert(scip != NULL);
8210  assert(conshdlr != NULL);
8211  assert(cons != NULL);
8212 
8213  consdata = SCIPconsGetData(cons);
8214  assert(consdata != NULL);
8215 
8216  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8217  assert(conshdlrdata != NULL);
8218  assert(conshdlrdata->gaugecuts);
8219 
8220  /* function has to be convex with finite rhs or concave with finite lhs */
8221  convex = consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs);
8222  assert(convex || (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)));
8223 
8224  SCIPdebugMsg(scip, "cons %s: is %s\n", SCIPconsGetName(cons), convex ? "convex" : "concave");
8225 
8226  /* 1. */
8227  SCIP_CALL( computeInteriorPoint(scip, cons, conshdlrdata->interiorcomputation, &success) );
8228 
8229  /* if success, compute gaugecoefs (b_gauge) and gaugeconst (c_gauge) */
8230  if( !success )
8231  {
8232  SCIPdebugMsg(scip, "failed to compute gauge function\n");
8233  consdata->isgaugeavailable = FALSE;
8234  return SCIP_OKAY;
8235  }
8236 
8237  /* 2.
8238  * we are going to evaluate the function at interiorpoint; so, we need to compute interiorpoint^T A interiorpoint;
8239  * therefore, we need a mechanism that for a given variable, it returns its interior point value
8240  * fortunately, sepabilinvar2pos in consdata gives us all the information that we need
8241  */
8242 
8243  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &(consdata->gaugecoefs), consdata->nquadvars) );
8244 
8245  /* compute value of quadratic part at interior point, build map and compute gaugeconst (c_gauge) */
8246  consdata->interiorpointval = 0;
8247  consdata->gaugeconst = 0;
8248  for( i = 0; i < consdata->nquadvars; i++ )
8249  {
8250  SCIP_Real val;
8251  SCIP_Real val2;
8252 
8253  val = consdata->interiorpoint[i];
8254  quadvarterm = &consdata->quadvarterms[i];
8255 
8256  consdata->interiorpointval += (quadvarterm->lincoef + quadvarterm->sqrcoef * val) * val;
8257  consdata->gaugeconst += quadvarterm->sqrcoef * val * val;
8258 
8259  for( j = 0; j < quadvarterm->nadjbilin; ++j )
8260  {
8261  int bilintermidx;
8262 
8263  bilintermidx = quadvarterm->adjbilin[j];
8264  bilinterm = &consdata->bilinterms[bilintermidx];
8265 
8266  if( bilinterm->var1 != quadvarterm->var )
8267  continue;
8268 
8269  /* the index of the variable associated with var2 in bilinterm should be given by sepabilinvar2pos */
8270  assert(consdata->sepabilinvar2pos != NULL); /* this should have been computed in INITSOL */
8271  assert(consdata->quadvarterms[consdata->sepabilinvar2pos[bilintermidx]].var == bilinterm->var2);
8272 
8273  val2 = consdata->interiorpoint[consdata->sepabilinvar2pos[bilintermidx]];
8274 
8275  consdata->interiorpointval += bilinterm->coef * val * val2;
8276  consdata->gaugeconst += bilinterm->coef * val * val2;
8277  }
8278  }
8279 
8280  /* compute gaugecoefs (b_gauge = b + 2 * A * interiorpoint) */
8281  for( i = 0; i < consdata->nquadvars; i++ )
8282  {
8283  quadvarterm = &consdata->quadvarterms[i];
8284  consdata->gaugecoefs[i] += quadvarterm->lincoef + 2.0 * quadvarterm->sqrcoef * consdata->interiorpoint[i];
8285 
8286  for( j = 0; j < quadvarterm->nadjbilin; j++ )
8287  {
8288  int varpos;
8289  int bilintermidx;
8290 
8291  bilintermidx = quadvarterm->adjbilin[j];
8292  bilinterm = &consdata->bilinterms[bilintermidx];
8293 
8294  if( bilinterm->var1 == quadvarterm->var )
8295  {
8296  varpos = consdata->sepabilinvar2pos[bilintermidx];
8297 
8298  /* the index of the variable associated with var2 in bilinterm should be given by sepabilinvar2pos */
8299  assert(consdata->quadvarterms[varpos].var == bilinterm->var2);
8300 
8301  consdata->gaugecoefs[i] += bilinterm->coef * consdata->interiorpoint[varpos];
8302  consdata->gaugecoefs[varpos] += bilinterm->coef * consdata->interiorpoint[i];
8303  }
8304  }
8305  }
8306 
8307 #ifdef SCIP_DEBUG_INT
8308  printf("quadratic part at interior point: %g\n", consdata->interiorpointval);
8309 
8310  for( j = 0; j < consdata->nquadvars; j++ )
8311  {
8312  printf("b_gauge[%s] = %g\n", SCIPvarGetName(consdata->quadvarterms[j].var), consdata->gaugecoefs[j]);
8313  }
8314  printf("c_gauge = %g\n", consdata->gaugeconst);
8315 #endif
8316 
8317  SCIPdebugMsg(scip, "gauge function computed successfully\n");
8318  consdata->isgaugeavailable = TRUE;
8319 
8320  return SCIP_OKAY;
8321 }
8322 
8323 /** evaluates gauge function of the set \f$S - s_0\f$ where \f$ S = \{ x : f(x) \le c \}\f$ and \f$ s_0 \in \mathring S\f$.
8324  *
8325  * \f$ S = \{ x : f(x) \le c \}\f$ at \f$sol - s_0\f$;
8326  * see computeGauge() for more details
8327  *
8328  * @todo Think about if user should tell that function is convex or ...
8329  */
8330 static
8332  SCIP* scip, /**< SCIP data structure */
8333  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8334  SCIP_CONS* cons, /**< constraint */
8335  SCIP_SOL* refsol, /**< reference point where to generate cut, or NULL if sol should be used */
8336  SCIP_Real* gaugeval, /**< buffer to store the value of the gauge function */
8337  SCIP_Bool* success /**< buffer to store if evaluation was successful */
8338  )
8339 {
8340  SCIP_CONSDATA* consdata;
8341  SCIP_Real side;
8342  SCIP_Real aterm;
8343  SCIP_Real bterm;
8344  SCIP_Real cterm;
8345  SCIP_Bool convex;
8346  int i;
8347 
8348  assert(scip != NULL);
8349  assert(conshdlr != NULL);
8350  assert(cons != NULL);
8351 
8352  consdata = SCIPconsGetData(cons);
8353  assert(consdata != NULL);
8354  assert(consdata->isgaugeavailable);
8355 
8356  *success = FALSE;
8357 
8358  convex = consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs);
8359 
8360  SCIPdebugMsg(scip, "cons %s: is %s\n", SCIPconsGetName(cons), convex ? "convex" : "concave");
8361 
8362  /* evaluate gauge function at x0 = (refsol - interior point)
8363  *
8364  * compute aterm = side - function(interior point)
8365  */
8366  if( convex )
8367  {
8368  side = consdata->rhs;
8369  for( i = 0; i < consdata->nlinvars; i++ )
8370  side -= SCIPgetSolVal(scip, refsol, consdata->linvars[i]) * consdata->lincoefs[i];
8371 
8372  aterm = side - consdata->interiorpointval;
8373 
8374  /* it can happen that the interior point is not really interior, since we are not so strict at the moment of
8375  * computing the interior point, which makes sense in the case that the constraint is quadratic <= linear expr,
8376  * since we compute a point in quadratic <= min linear expr and it might be that this set consists of a single
8377  * point which will not be interior. furthermore, if this set is empty, we could just take any point and it could
8378  * happen that for some value of linear expr, the point is actually interior, but for many it could not be.
8379  * also, if min linear expr = -infinity, we might have computed an interior point using some finite value.
8380  * the point will not be an interior point, if and only if aterm is negative.
8381  */
8382 #ifdef SCIP_DEBUG_GAUGE
8383  if( SCIPisLE(scip, aterm, 0.0) )
8384  {
8385  printf("For current level, there is no interior point. ");
8386  printf("rhs: %g level: %15.20g interiorpointval: %15.20g\n", consdata->rhs, side, consdata->interiorpointval);
8387  if( consdata->nlinvars == 1 )
8388  {
8389  SCIP_VAR* var;
8390 
8391  var = consdata->linvars[0];
8392  printf("var <%s> = %g in [%15.20g, %15.20g] is linpart\n", SCIPvarGetName(var),
8393  SCIPgetSolVal(scip, refsol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
8394  }
8395  }
8396  else
8397  {
8398  printf("For current level, there is interior point. ");
8399  printf("rhs: %g level: %15.20g interiorpointval: %15.20g\n", consdata->rhs, side, consdata->interiorpointval);
8400  }
8401 #endif
8402  if( !SCIPisPositive(scip, aterm) )
8403  {
8404  *gaugeval = -1.0;
8405  return SCIP_OKAY;
8406  }
8407  }
8408  else
8409  {
8410  side = consdata->lhs;
8411  for( i = 0; i < consdata->nlinvars; i++ )
8412  side -= SCIPgetSolVal(scip, refsol, consdata->linvars[i]) * consdata->lincoefs[i];
8413 
8414  aterm = side - consdata->interiorpointval;
8415 
8416 #ifdef SCIP_DEBUG_GAUGE
8417  if( SCIPisGE(scip, aterm, 0.0) )
8418  {
8419  printf("For current level, there is no interior point. ");
8420  printf("lhs: %g level: %15.20g interiorpointval: %15.20g\n", consdata->lhs, side, consdata->interiorpointval);
8421  if( consdata->nlinvars == 1 )
8422  {
8423  SCIP_VAR* var;
8424 
8425  var = consdata->linvars[0];
8426  printf("var <%s> = %g in [%15.20g, %15.20g] is linpart\n", SCIPvarGetName(var),
8427  SCIPgetSolVal(scip, refsol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
8428  }
8429  }
8430  else
8431  {
8432  printf("For current level, there is interior point. ");
8433  printf("lhs: %g level: %15.20g interiorpointval: %15.20g\n", consdata->lhs, side, consdata->interiorpointval);
8434  }
8435 #endif
8436  if( !SCIPisNegative(scip, aterm) )
8437  {
8438  *gaugeval = -1.0;
8439  return SCIP_OKAY;
8440  }
8441  }
8442 
8443  /* compute bterm = b_gauge^T * refsol - f(interiorpoint) - c_gauge
8444  * compute cterm = f(refsol) - b_gauge^T * refsol + c_gauge */
8445  bterm = -consdata->interiorpointval - consdata->gaugeconst;
8446  cterm = consdata->gaugeconst;
8447  for( i = 0; i < consdata->nquadvars; i++ )
8448  {
8449  SCIP_Real val;
8450 
8451  val = SCIPgetSolVal(scip, refsol, consdata->quadvarterms[i].var);
8452  bterm += consdata->gaugecoefs[i] * val;
8453  cterm -= consdata->gaugecoefs[i] * val;
8454  cterm += (consdata->quadvarterms[i].lincoef + consdata->quadvarterms[i].sqrcoef * val) * val;
8455  }
8456 
8457  for( i = 0; i < consdata->nbilinterms; i++ )
8458  {
8459  SCIP_VAR* var1;
8460  SCIP_VAR* var2;
8461 
8462  var1 = consdata->bilinterms[i].var1;
8463  var2 = consdata->bilinterms[i].var2;
8464  cterm += consdata->bilinterms[i].coef * SCIPgetSolVal(scip, refsol, var1) * SCIPgetSolVal(scip, refsol, var2);
8465  }
8466 
8467  /* now compute gauge */
8468  if( convex && cterm < 0.0 )
8469  {
8470  assert(SCIPisZero(scip, cterm));
8471  cterm = 0.0;
8472  }
8473  else if( !convex && cterm > 0.0 )
8474  {
8475  assert(SCIPisZero(scip, cterm));
8476  cterm = 0.0;
8477  }
8478  assert(bterm*bterm + 4*aterm*cterm >= 0);
8479 
8480  if( convex )
8481  {
8482  *gaugeval = bterm + sqrt(bterm*bterm + 4 * aterm * cterm);
8483  *gaugeval = *gaugeval / (2 * aterm);
8484  }
8485  else
8486  {
8487  *gaugeval = bterm - sqrt(bterm*bterm + 4 * aterm * cterm);
8488  *gaugeval = *gaugeval / (2 * aterm);
8489  }
8490  assert(!SCIPisNegative(scip, *gaugeval));
8491  *success = TRUE;
8492 
8493 #ifdef SCIP_DEBUG_GAUGE
8494  printf("Gauge's aterm = %g, bterm = %g, cterm = %g\n", aterm, bterm, cterm);
8495 #endif
8496  return SCIP_OKAY;
8497 }
8498 
8499 /** compute projection of refsol onto feasible region of cons; stores the projection in ref
8500  *
8501  * This method solves
8502  * \f[
8503  * \min \{ ||x - \bar x||^2 : x^T A x + 2 b^T x \le c \}
8504  * \f]
8505  * where \f$ \bar x \f$ is refsol.
8506  * Note that \f$ \bar x \f$ is not feasible, so the optimal solution actually satisfies
8507  * \f[
8508  * \min \{ ||x - \bar x||^2 : x^T A x + 2 b^T x = c \}
8509  * \f]
8510  * Using the eigendecomposition \f$ A = P D P^T \f$, the change of variables \f$ y = P^T x
8511  * \f$ and the optimality conditions, this reduces to finding \f$ \rho \f$ such that
8512  * \f[
8513  * y(\rho) = (I + \rho D)^{-1} (\bar y - \rho \bar b)
8514  * \f]
8515  * makes the constraint active. In the previous formula, \f$ \bar y = P^T \bar x\f$ and \f$ \bar b = P^T b \f$. If \f$
8516  * D \neq 0 \f$, the function
8517  * \f[
8518  * \varphi(\rho) := y(\rho)^T D y(\rho) + 2 \bar b^T y(\rho) - c
8519  * \f]
8520  * is strictly convex. So this method actually computes the unique 0 of this function using Newton's method.
8521  */
8522 static
8524  SCIP* scip, /**< SCIP data structure */
8525  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8526  SCIP_CONS* cons, /**< constraint */
8527  SCIP_SOL* refsol, /**< the given point to project, or NULL if LP solution should be used */
8528  SCIP_Real* ref /**< array to store reference point */
8529  )
8530 {
8531  SCIP_CONSDATA* consdata;
8532  SCIP_Real* pt; /* stores P^T */
8533  SCIP_Real* bp;
8534  SCIP_Real* D;
8535  SCIP_Real* y0_;
8536  SCIP_Real* yrho;
8537  SCIP_Real* yrhoprime;
8538  SCIP_Real c;
8539  SCIP_Real c1;
8540  SCIP_Real c2;
8541  SCIP_Real rho;
8542  SCIP_Real phirho;
8543  SCIP_Real phirhoprime;
8544  SCIP_Bool isconcave;
8545  int iter;
8546  int i;
8547  int j;
8548  int n;
8549 
8550  assert(scip != NULL);
8551  assert(conshdlr != NULL);
8552  assert(cons != NULL);
8553 
8554  consdata = SCIPconsGetData(cons);
8555  assert(consdata != NULL);
8556  assert(consdata->isedavailable);
8557 
8558  SCIPdebugMessage("computing projection\n");
8559 
8560  /* get the data we need */
8561  pt = consdata->eigenvectors;
8562  D = consdata->eigenvalues;
8563  n = consdata->nquadvars;
8564  bp = consdata->bp;
8565  c = consdata->rhs;
8566  c1 = 0;
8567  c2 = 0;
8568  for( i = 0; i < consdata->nlinvars; i++ )
8569  {
8570  c1 += consdata->lincoefs[i] * SCIPgetSolVal(scip, refsol, consdata->linvars[i]);
8571  c2 -= consdata->lincoefs[i] * consdata->lincoefs[i];
8572  }
8573  c2 /= 2.0;
8574 
8575  /* determine if convex or concave */
8576  isconcave = consdata->isconcave;
8577  assert((isconcave && !SCIPisInfinity(scip, -consdata->lhs)) || !SCIPisInfinity(scip, consdata->rhs));
8578 
8579  SCIP_CALL( SCIPallocClearBufferArray(scip, &y0_, n) );
8580  SCIP_CALL( SCIPallocBufferArray(scip, &yrho, n) );
8581  SCIP_CALL( SCIPallocBufferArray(scip, &yrhoprime, n) );
8582 
8583  /* change data if function is concave */
8584  if( isconcave )
8585  {
8586  c = -consdata->lhs;
8587  c1 = - c1;
8588  for( i = 0; i < n; i++ )
8589  {
8590  D[i] = -D[i];
8591  bp[i] = -bp[i];
8592  }
8593  }
8594 
8595  /* change coordinates: compute y(0) = x_0' * P */
8596  for( i = 0; i < n; i++ )
8597  for( j = 0; j < n; j++ )
8598  y0_[i] += SCIPgetSolVal(scip, refsol, consdata->quadvarterms[j].var) * pt[i*n + j];
8599 
8600 #ifdef DEBUG_PROJ
8601  /* debug output */
8602  printf("\nP^T:\n");
8603  for( i = 0; i < n; i++ )
8604  {
8605  for( j = 0; j < n; j++ )
8606  printf("%g ", pt[i*n + j]);
8607  printf("\n");
8608  }
8609  printf("x_0: ");
8610  for( i = 0; i < n; i++ )
8611  printf("%g ", SCIPgetSolVal(scip, refsol, consdata->quadvarterms[i].var));
8612  printf("\n");
8613  printf("P^T x_0: ");
8614  for( i = 0; i < n; i++ )
8615  printf("%g ", y0_[i]);
8616  printf("\n");
8617  printf("P^T b: ");
8618  for( i = 0; i < n; i++ )
8619  printf("%g ", bp[i]);
8620  printf("\n");
8621  printf("<d,linvars> = %g\n", c1);
8622  printf("-norm(d)^2/2 = %g\n", c2);
8623 #endif
8624 
8625  /* perform newton's method: rho^+ = rho - phi(rho)/phi'(rho) */
8626  rho = 0.0;
8627  phirho = c;
8628  phirhoprime = 1.0;
8629  for( iter = 0; iter < 9; iter++ )
8630  {
8631  assert(phirhoprime != 0.0);
8632  rho = rho - (phirho - c)/ phirhoprime;
8633 
8634  /* compute phi(rho) and phi'(rho):
8635  * note that formulas were deduced for constraints of the form x' A x + 2 b x, so we use b/2 in the formulas:
8636  * c1 = <lin_coefs, sol_lin_vars>
8637  * c2 = - norm(lin_coefs)^2/2
8638  * y(rho) = (I + rho * D)^-1 * (y(0) - rho * bp/2)
8639  * y'(rho) = -(I + rho * D)^-2 * (D y(0) + bp/2)
8640  * phi(rho) = <y(rho), D * y(rho) + pb> + c1 + c2*rho
8641  * phi'(rho) = <y'(rho), 2 * D * y(rho) + pb> + c2
8642  */
8643  phirho = 0.0;
8644  phirhoprime = 0.0;
8645  for( i = 0; i < n; i++ )
8646  {
8647  assert(1.0 + rho * D[i] != 0.0);
8648  yrho[i] = (y0_[i] - rho * bp[i]/2.0) / (1.0 + rho * D[i]);
8649  yrhoprime[i] = -(D[i] * y0_[i] + bp[i]/2.0) / ( (1.0 + rho * D[i])*(1.0 + rho * D[i]) );
8650  phirho += yrho[i] * (yrho[i] * D[i] + bp[i]);
8651  phirhoprime += yrhoprime[i] * (2 * D[i] * yrho[i] + bp[i]);
8652  }
8653  phirho += c2 * rho + c1;
8654  phirhoprime += c2;
8655 #ifdef DEBUG_PROJ
8656  printf("iteration %d: rho = %g, phirho = %g, phirho' = %g\n", iter, rho, phirho, phirhoprime);
8657 #endif
8658  }
8659 
8660  /* come back to the original coordinates: new ref point is P*yrho */
8661  for( i = 0; i < n; i++ )
8662  {
8663  ref[i] = 0.0;
8664 
8665  for( j = 0; j < n; j++ )
8666  ref[i] += pt[j*n + i] * yrho[j];
8667  }
8668 
8669  /* change data back if function is concave */
8670  if( isconcave )
8671  {
8672  for( i = 0; i < n; i++ )
8673  {
8674  D[i] = -D[i];
8675  bp[i] = -bp[i];
8676  }
8677  }
8678 
8679 #ifdef SCIP_DISABLED_CODE
8680  /* project onto bounds; this is important for some cut generation methods such as generateCutLTI */
8681  for( j = 0; j < consdata->nquadvars; ++j )
8682  {
8683  SCIP_Real lb;
8684  SCIP_Real ub;
8685  SCIP_VAR* var;
8686 
8687  var = consdata->quadvarterms[j].var;
8688  lb = SCIPvarGetLbLocal(var);
8689  ub = SCIPvarGetUbLocal(var);
8690  /* do not like variables at infinity */
8691  assert(!SCIPisInfinity(scip, lb));
8692  assert(!SCIPisInfinity(scip, -ub));
8693 
8694  ref[j] = MIN(ub, MAX(lb, ref[j])); /* project value into bounds */
8695  }
8696 #endif
8697 
8698 #ifdef DEBUG_PROJ
8699  printf("modified reference point by a projection:\n");
8700  for( j = 0; j < consdata->nquadvars; ++j )
8701  {
8702  printf("%s = %g\n", SCIPvarGetName(consdata->quadvarterms[j].var), ref[j]);
8703  }
8704 #endif
8705 
8706  SCIPfreeBufferArray(scip, &y0_);
8707  SCIPfreeBufferArray(scip, &yrho);
8708  SCIPfreeBufferArray(scip, &yrhoprime);
8709 
8710  return SCIP_OKAY;
8711 }
8712 
8713 /** compute reference point suggested by gauge function */
8714 static
8716  SCIP* scip, /**< SCIP data structure */
8717  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8718  SCIP_CONS* cons, /**< constraint */
8719  SCIP_SOL* refsol, /**< reference point where to compute gauge, or NULL if LP solution should be used */
8720  SCIP_Real* ref, /**< array to store reference point */
8721  SCIP_Bool* success /**< buffer to store whether we succeeded computing reference point */
8722  )
8723 {
8724  SCIP_CONSDATA* consdata;
8725  SCIP_Real gaugeval;
8726  SCIP_Real intpoint;
8727  SCIP_Real lb;
8728  SCIP_Real ub;
8729  SCIP_VAR* var;
8730  int j;
8731 
8732  assert(scip != NULL);
8733  assert(conshdlr != NULL);
8734  assert(cons != NULL);
8735 
8736  consdata = SCIPconsGetData(cons);
8737  assert(consdata != NULL);
8738  assert(consdata->isgaugeavailable);
8739 
8740  SCIPdebugMsg(scip, "evaluating gauge\n");
8741  SCIP_CALL( evaluateGauge(scip, conshdlr, cons, refsol, &gaugeval, success) );
8742 
8743  if( !(*success) )
8744  {
8745 #ifdef SCIP_DEBUG_GAUGE
8746  printf("Couldn't evaluate gauge!\n");
8747 #endif
8748  return SCIP_OKAY;
8749  }
8750 
8751 #ifdef SCIP_DEBUG_GAUGE
8752  {
8753  SCIP_Real level;
8754 
8755  level = consdata->rhs;
8756  for( j = 0; j < consdata->nlinvars; j++ )
8757  level -= SCIPgetSolVal(scip, refsol, consdata->linvars[j]) * consdata->lincoefs[j];
8758 
8759  printf("Summary:\n");
8760  printf("For cons <%s>: gauge at level %g evaluated at (refsol - intpoint) is %.10f\n",
8761  SCIPconsGetName(cons), level, gaugeval);
8762  printf("refsol - intpoint:\n");
8763 
8764  for( j = 0; j < consdata->nquadvars; ++j )
8765  {
8766  SCIP_VAR* vvar;
8767  vvar = consdata->quadvarterms[j].var;
8768  printf("%s: % 20.15g - %g = %g\n", SCIPvarGetName(vvar), SCIPgetSolVal(scip, refsol, vvar),
8769  consdata->interiorpoint[j], SCIPgetSolVal(scip, refsol, vvar) - consdata->interiorpoint[j]);
8770  }
8771  if( SCIPisFeasLE(scip, gaugeval, 1.0) )
8772  printf("refsol is in the closure of the region (gaugeval <= 1), don't modify reference point\n");
8773  }
8774 #endif
8775 
8776  /* scale gauge value so that final point is close to the boundary, but not on the boundary (weakens the cut) */
8777  gaugeval *= GAUGESCALE;
8778 
8779  /* if the point is not sufficiently violated, we don't modify it */
8780  if( SCIPisFeasLE(scip, gaugeval, 1.0) )
8781  {
8782  *success = FALSE;
8783  return SCIP_OKAY;
8784  }
8785 
8786  /* set reference to (refsol - interior point)/gaugeval + interior point and project onto bounds this is important for
8787  * some cut generation methods such as generateCutLTI
8788  * @todo remove the projection onto the bounds; generateCutLTI shouldn't be called for convex constraints
8789  */
8790  for( j = 0; j < consdata->nquadvars; ++j )
8791  {
8792  var = consdata->quadvarterms[j].var;
8793  lb = SCIPvarGetLbLocal(var);
8794  ub = SCIPvarGetUbLocal(var);
8795  /* do not like variables at infinity */
8796  assert(!SCIPisInfinity(scip, lb));
8797  assert(!SCIPisInfinity(scip, -ub));
8798 
8799  intpoint = consdata->interiorpoint[j];
8800  ref[j] = (SCIPgetSolVal(scip, refsol, var) - intpoint) / gaugeval + intpoint;
8801  ref[j] = MIN(ub, MAX(lb, ref[j])); /* project value into bounds */
8802  }
8803 
8804 #ifdef SCIP_DEBUG_GAUGE
8805  printf("successful application of guage: %g\n", gaugeval);
8806  printf("modified reference point:\n");
8807  for( j = 0; j < consdata->nquadvars; ++j )
8808  {
8809  printf("%s = % 20.15g\n", SCIPvarGetName(consdata->quadvarterms[j].var), ref[j]);
8810  }
8811 #endif
8812 
8813  return SCIP_OKAY;
8814 }
8815 
8816 /** generates a cut based on linearization (if convex) or McCormick (if nonconvex) in a solution
8817  * @note mode indicates whether we should modify the point we want to cutoff (sol) via gauge or projection,
8818  * or if just normal linearization should be use, or the default way (whatever is specified via settings)
8819  */
8820 static
8822  SCIP* scip, /**< SCIP data structure */
8823  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8824  SCIP_CONS* cons, /**< constraint */
8825  SCIP_SOL* sol, /**< solution where to generate cut, or NULL if LP solution should be used */
8826  SCIP_SOL* refsol, /**< reference point where to generate cut, or NULL if sol should be used */
8827  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
8828  SCIP_ROW** row, /**< storage for cut */
8829  SCIP_Real* efficacy, /**< buffer to store efficacy of row in reference solution, or NULL if not of interest */
8830  SCIP_Bool checkcurvmultivar, /**< are we allowed to check the curvature of a multivariate quadratic function, if not done yet */
8831  SCIP_Real minefficacy, /**< minimal required efficacy */
8832  char mode /**< mode of execution 'g'auge, 'p'rojection, 'l'inearization gradient, 'd'efault */
8833  )
8834 {
8835  SCIP_CONSHDLRDATA* conshdlrdata;
8836  SCIP_CONSDATA* consdata;
8837  SCIP_VAR* var;
8838  SCIP_Real lb;
8839  SCIP_Real ub;
8840  SCIP_Real* ref;
8841  SCIP_Bool success;
8842  int j;
8843 
8844  assert(scip != NULL);
8845  assert(conshdlr != NULL);
8846  assert(cons != NULL);
8847 
8848  consdata = SCIPconsGetData(cons);
8849  assert(consdata != NULL);
8850 
8851  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8852  assert(conshdlrdata != NULL);
8853 
8854  if( refsol == NULL )
8855  refsol = sol;
8856 
8857  /* get reference point */
8858  SCIP_CALL( SCIPallocBufferArray(scip, &ref, consdata->nquadvars) );
8859  success = FALSE;
8860 
8861  if( mode == 'd')
8862  {
8863  if( (consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) ||
8864  (consdata->isconcave && violside == SCIP_SIDETYPE_LEFT) )
8865  {
8866  if( conshdlrdata->gaugecuts && consdata->isgaugeavailable )
8867  {
8868  SCIP_CALL( computeReferencePointGauge(scip, conshdlr, cons, refsol, ref, &success) );
8869  }
8870  else if( conshdlrdata->projectedcuts && consdata->isedavailable )
8871  {
8872  SCIPdebugMessage("use the projection of refsol onto the region defined by the constraint as reference point\n");
8873  SCIP_CALL( computeReferencePointProjection(scip, conshdlr, cons, refsol, ref) );
8874  success = TRUE;
8875  }
8876  }
8877 
8878  if( success )
8879  {
8880  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
8881 
8882  /* if cut fails, try again without modifying reference point */
8883  if( *row == NULL || (efficacy != NULL && !SCIPisGT(scip, *efficacy, minefficacy)) || !SCIPisCutApplicable(scip, *row) ) /*lint !e644 */
8884  {
8885  SCIPdebugMsg(scip, "%s cut fail, try without modifying\n", conshdlrdata->gaugecuts ? "gauge" : "projected");
8886  success = FALSE;
8887  }
8888  }
8889 
8890  /* note that this is not the same as calling this method with mode 'l', 'l' assume convex/concave function */
8891  if( !success )
8892  {
8893  for( j = 0; j < consdata->nquadvars; ++j )
8894  {
8895  var = consdata->quadvarterms[j].var;
8896  lb = SCIPvarGetLbLocal(var);
8897  ub = SCIPvarGetUbLocal(var);
8898  /* do not like variables at infinity */
8899  assert(!SCIPisInfinity(scip, lb));
8900  assert(!SCIPisInfinity(scip, -ub));
8901 
8902  ref[j] = SCIPgetSolVal(scip, refsol, var);
8903  ref[j] = MIN(ub, MAX(lb, ref[j])); /* project value into bounds */
8904  }
8905 
8906  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
8907  }
8908  }
8909  /* gauge cut */
8910  if( mode == 'g' )
8911  {
8912  assert((consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) || (consdata->isconcave && violside == SCIP_SIDETYPE_LEFT));
8913  if( conshdlrdata->gaugecuts && consdata->isgaugeavailable )
8914  {
8915  SCIP_CALL( computeReferencePointGauge(scip, conshdlr, cons, refsol, ref, &success) );
8916  }
8917  if( success )
8918  {
8919  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
8920  }
8921  }
8922  /* projection cut */
8923  if( mode == 'p' )
8924  {
8925  assert((consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) || (consdata->isconcave && violside == SCIP_SIDETYPE_LEFT));
8926  if( conshdlrdata->projectedcuts && consdata->isedavailable )
8927  {
8928  SCIP_CALL( computeReferencePointProjection(scip, conshdlr, cons, refsol, ref) );
8929  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
8930  }
8931  }
8932  /* gradient linearization cut at refsol */
8933  if( mode == 'l' )
8934  {
8935  assert((consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) || (consdata->isconcave && violside == SCIP_SIDETYPE_LEFT));
8936  for( j = 0; j < consdata->nquadvars; ++j )
8937  {
8938  var = consdata->quadvarterms[j].var;
8939  lb = SCIPvarGetLbLocal(var);
8940  ub = SCIPvarGetUbLocal(var);
8941  /* do not like variables at infinity */
8942  assert(!SCIPisInfinity(scip, lb));
8943  assert(!SCIPisInfinity(scip, -ub));
8944 
8945  ref[j] = SCIPgetSolVal(scip, refsol, var);
8946  ref[j] = MIN(ub, MAX(lb, ref[j])); /* project value into bounds */
8947  }
8948  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
8949  }
8950 
8951  SCIPfreeBufferArray(scip, &ref);
8952 
8953  return SCIP_OKAY;
8954 }
8955 
8956 /** tries to find a cut that intersects with an unbounded ray of the LP
8957  *
8958  * For convex functions, we do this by linearizing in the feasible solution of the LPI.
8959  * For nonconvex functions, we just call generateCutSol with the unbounded solution as reference point.
8960  */
8961 static
8963  SCIP* scip, /**< SCIP data structure */
8964  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8965  SCIP_CONS* cons, /**< constraint */
8966  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
8967  SCIP_ROW** row, /**< storage for cut */
8968  SCIP_Real* rowrayprod, /**< buffer to store product of ray with row coefficients, or NULL if not of interest */
8969  SCIP_Bool checkcurvmultivar /**< are we allowed to check the curvature of a multivariate quadratic function, if not done yet */
8970  )
8971 {
8972  SCIP_CONSDATA* consdata;
8973  SCIP_BILINTERM* bilinterm;
8974  SCIP_VAR* var;
8975  SCIP_Real* ref;
8976  SCIP_Real matrixrayprod;
8977  SCIP_Real linrayprod;
8978  SCIP_Real quadrayprod;
8979  SCIP_Real rayval;
8980  int i;
8981  int j;
8982 
8983  assert(scip != NULL);
8984  assert(conshdlr != NULL);
8985  assert(cons != NULL);
8986  assert(row != NULL);
8988 
8989  consdata = SCIPconsGetData(cons);
8990  assert(consdata != NULL);
8991 
8992  *row = NULL;
8993 
8994  if( !SCIPhasPrimalRay(scip) )
8995  {
8996  SCIPdebugMsg(scip, "do not have primal ray, thus cannot resolve unboundedness\n");
8997  return SCIP_OKAY;
8998  }
8999 
9000  SCIP_CALL( checkCurvature(scip, cons, checkcurvmultivar) );
9001  if( (!consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) ||
9002  (!consdata->isconcave && violside == SCIP_SIDETYPE_LEFT) )
9003  {
9004  /* if not convex, just call generateCut and hope it's getting something useful */
9005  SCIP_CALL( generateCutSol(scip, conshdlr, cons, NULL, NULL, violside, row, NULL, FALSE, -SCIPinfinity(scip), 'd') );
9006 
9007  /* compute product of cut coefficients with ray, if required */
9008  if( *row != NULL && rowrayprod != NULL )
9009  {
9010  *rowrayprod = 0.0;
9011  for( i = 0; i < SCIProwGetNNonz(*row); ++i )
9012  {
9013  assert(SCIProwGetCols(*row)[i] != NULL);
9014  var = SCIPcolGetVar(SCIProwGetCols(*row)[i]);
9015  assert(var != NULL);
9016 
9017  *rowrayprod += SCIProwGetVals(*row)[i] * SCIPgetPrimalRayVal(scip, var);
9018  }
9019  }
9020 
9021  return SCIP_OKAY;
9022  }
9023 
9024  /* we seek for a linearization of the quadratic function such that it intersects with the unbounded ray
9025  * that is, we need a reference point ref such that for the gradient g of xAx+bx in ref, we have
9026  * <g, ray> > 0.0 if rhs is finite and <g, ray> < 0.0 if lhs is finite
9027  * Since g = 2*A*ref + b, we have <g, ray> = <2*A*ref + b, ray> = <ref, 2*A*ray> + <b,ray>
9028  * initially, for finite rhs, we set ref_i = 1.0 if (A*ray)_i > 0.0 and ref_i = -1.0 if (A*ray)_i < 0.0 (for finite lhs analog)
9029  * <ref, 2*A*ray> + <b,ray> is sufficiently larger 0.0, we call generateCut for this point, otherwise, we scale up ref
9030  */
9031 
9032  quadrayprod = 0.0; /* <ref, 2*A*ray> */
9033  linrayprod = 0.0; /* <b, ray> */
9034  SCIP_CALL( SCIPallocBufferArray(scip, &ref, consdata->nquadvars) );
9035  for( i = 0; i < consdata->nquadvars; ++i )
9036  {
9037  var = consdata->quadvarterms[i].var;
9038  rayval = SCIPgetPrimalRayVal(scip, var);
9039 
9040  /* compute i-th entry of (2*A*ray) */
9041  matrixrayprod = 2.0 * consdata->quadvarterms[i].sqrcoef * rayval;
9042  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
9043  {
9044  bilinterm = &consdata->bilinterms[consdata->quadvarterms[i].adjbilin[j]];
9045  matrixrayprod += bilinterm->coef * SCIPgetPrimalRayVal(scip, bilinterm->var1 == var ? bilinterm->var2 : bilinterm->var1);
9046  }
9047 
9048  if( SCIPisPositive(scip, matrixrayprod) )
9049  ref[i] = (violside == SCIP_SIDETYPE_RIGHT ? 1.0 : -1.0);
9050  else if( SCIPisNegative(scip, matrixrayprod) )
9051  ref[i] = (violside == SCIP_SIDETYPE_RIGHT ? -1.0 : 1.0);
9052  else
9053  ref[i] = 0.0;
9054 
9055  quadrayprod += matrixrayprod * ref[i];
9056  linrayprod += consdata->quadvarterms[i].lincoef * rayval;
9057  }
9058  assert((violside == SCIP_SIDETYPE_RIGHT && quadrayprod >= 0.0) || (violside == SCIP_SIDETYPE_LEFT && quadrayprod <= 0.0));
9059 
9060  if( SCIPisZero(scip, quadrayprod) )
9061  {
9062  SCIPdebugMsg(scip, "ray is zero along cons <%s>\n", SCIPconsGetName(cons));
9063  SCIPfreeBufferArray(scip, &ref);
9064  return SCIP_OKAY;
9065  }
9066 
9067  /* add linear part to linrayprod */
9068  for( i = 0; i < consdata->nlinvars; ++i )
9069  linrayprod += consdata->lincoefs[i] * SCIPgetPrimalRayVal(scip, consdata->linvars[i]);
9070 
9071  SCIPdebugMsg(scip, "initially have <b,ray> = %g and <ref, 2*A*ref> = %g\n", linrayprod, quadrayprod);
9072 
9073  /* we scale the refpoint up, such that <ref, 2*A*ray> >= -2*<b, ray> (rhs finite) or <ref, 2*A*ray> <= -2*<b, ray> (lhs finite), if <b,ray> is not zero
9074  * if <b,ray> is zero, then we scale refpoint up if |<ref, 2*A*ray>| < 1.0
9075  */
9076  if( (!SCIPisZero(scip, linrayprod) && violside == SCIP_SIDETYPE_RIGHT && quadrayprod < -2*linrayprod) ||
9077  ( !SCIPisZero(scip, linrayprod) && violside == SCIP_SIDETYPE_LEFT && quadrayprod > -2*linrayprod) ||
9078  (SCIPisZero(scip, linrayprod) && REALABS(quadrayprod) < 1.0) )
9079  {
9080  SCIP_Real scale;
9081 
9082  if( !SCIPisZero(scip, linrayprod) )
9083  scale = 2*REALABS(linrayprod/quadrayprod); /*lint !e795 */
9084  else
9085  scale = 1.0/REALABS(quadrayprod);
9086 
9087  SCIPdebugMsg(scip, "scale refpoint by %g\n", scale);
9088  for( i = 0; i < consdata->nquadvars; ++i )
9089  ref[i] *= scale;
9090  quadrayprod *= scale;
9091  }
9092 
9093  if( rowrayprod != NULL )
9094  *rowrayprod = quadrayprod + linrayprod;
9095 
9096  SCIPdebugMsg(scip, "calling generateCut, expecting ray product %g\n", quadrayprod + linrayprod);
9097  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, NULL, violside, row, NULL, FALSE, -SCIPinfinity(scip)) );
9098 
9099  SCIPfreeBufferArray(scip, &ref);
9100 
9101  return SCIP_OKAY;
9102 }
9103 
9104 /** processes a cut for constraint cons, i.e., checks numerics and possibly adds cut to sepastore */
9105 static
9107  SCIP* scip, /**< SCIP data structure */
9108  SCIP_ROW** row, /**< cut to process */
9109  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
9110  SCIP_CONS* cons, /**< constraint */
9111  SCIP_Real efficacy, /**< efficacy of row in reference solution */
9112  SCIP_Real minefficacy, /**< minimal efficacy */
9113  SCIP_Bool inenforcement, /**< whether we are in constraint enforcement */
9114  SCIP_Real* bestefficacy, /**< buffer to store best efficacy of a cut that was added to the LP, if found; or NULL if not of interest */
9115  SCIP_RESULT* result /**< result of separation */
9116  )
9117 {
9118  SCIP_CONSDATA* consdata;
9119  SCIP_CONSHDLRDATA* conshdlrdata;
9120 
9121  assert(scip != NULL);
9122  assert(row != NULL);
9123  assert(conshdlr != NULL);
9124  assert(result != NULL);
9125  assert(cons != NULL);
9126 
9127  /* no cut to process */
9128  if( *row == NULL )
9129  return SCIP_OKAY;
9130 
9131  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9132  assert(conshdlrdata != NULL);
9133 
9134  consdata = SCIPconsGetData(cons);
9135  assert(consdata != NULL);
9136 
9137  if( SCIPisGT(scip, efficacy, minefficacy) && SCIPisCutApplicable(scip, *row) ) /*lint !e644 */
9138  {
9139  SCIP_Bool infeasible;
9140 
9141  /* cut cuts off solution */
9142  SCIP_CALL( SCIPaddRow(scip, *row, FALSE /* forcecut */, &infeasible) );
9143  if( infeasible )
9144  {
9145  SCIPdebugMessage("cut for constraint <%s> is infeasible -> cutoff.\n", SCIPconsGetName(cons));
9146  *result = SCIP_CUTOFF;
9147  }
9148  else
9149  {
9150  SCIPdebugMessage("add cut with efficacy %g for constraint <%s> violated by %g\n", efficacy,
9151  SCIPconsGetName(cons), consdata->lhsviol+consdata->rhsviol);
9152  *result = SCIP_SEPARATED;
9153  }
9154  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9155 
9156  /* mark row as not removable from LP for current node, if in enforcement */
9157  if( inenforcement && !conshdlrdata->enfocutsremovable )
9158  SCIPmarkRowNotRemovableLocal(scip, *row);
9159  }
9160  if( bestefficacy != NULL && efficacy > *bestefficacy )
9161  *bestefficacy = efficacy;
9162 
9163  SCIP_CALL( SCIPreleaseRow (scip, row) );
9164  return SCIP_OKAY;
9165 }
9166 
9167 /** tries to separate solution or LP solution by a linear cut
9168  *
9169  * assumes that constraint violations have been computed
9170  */
9171 static
9173  SCIP* scip, /**< SCIP data structure */
9174  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
9175  SCIP_CONS** conss, /**< constraints */
9176  int nconss, /**< number of constraints */
9177  int nusefulconss, /**< number of constraints that seem to be useful */
9178  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
9179  SCIP_Real minefficacy, /**< minimal efficacy of a cut if it should be added to the LP */
9180  SCIP_Bool inenforcement, /**< whether we are in constraint enforcement */
9181  SCIP_RESULT* result, /**< result of separation */
9182  SCIP_Real* bestefficacy /**< buffer to store best efficacy of a cut that was added to the LP, if found; or NULL if not of interest */
9183  )
9184 {
9185  SCIP_CONSHDLRDATA* conshdlrdata;
9186  SCIP_CONSDATA* consdata;
9187  SCIP_Real efficacy;
9188  SCIP_SIDETYPE violside;
9189  int c;
9190  SCIP_ROW* row;
9191 
9192  assert(scip != NULL);
9193  assert(conshdlr != NULL);
9194  assert(conss != NULL || nconss == 0);
9195  assert(nusefulconss <= nconss);
9196  assert(result != NULL);
9197 
9198  *result = SCIP_FEASIBLE;
9199 
9200  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9201  assert(conshdlrdata != NULL);
9202 
9203  if( bestefficacy != NULL )
9204  *bestefficacy = 0.0;
9205 
9206  row = NULL;
9207  /* loop over both sides of each constraint */
9208  for( c = 0, violside = SCIP_SIDETYPE_LEFT; c < nconss; c = (violside == SCIP_SIDETYPE_LEFT ? c : c+1), violside = (violside == SCIP_SIDETYPE_LEFT ? SCIP_SIDETYPE_RIGHT : SCIP_SIDETYPE_LEFT) )
9209  {
9210  assert(conss != NULL);
9211  consdata = SCIPconsGetData(conss[c]);
9212  assert(consdata != NULL);
9213 
9214  /* if side not violated, then go on */
9215  if( !SCIPisGT(scip, violside == SCIP_SIDETYPE_LEFT ? consdata->lhsviol : consdata->rhsviol, SCIPfeastol(scip)) )
9216  continue;
9217 
9218  /* we are not feasible anymore */
9219  if( *result == SCIP_FEASIBLE )
9220  *result = SCIP_DIDNOTFIND;
9221 
9222  /* generate cut */
9223  if( sol == NULL && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY )
9224  {
9225  /* if the LP is unbounded, then we need a cut that cuts into the direction of a hopefully existing primal ray
9226  * that is, assume a ray r is given such that p + t*r is feasible for the LP for all t >= t_0 and some p
9227  * given a cut lhs <= <c,x> <= rhs, we check whether it imposes an upper bound on t and thus bounds the ray
9228  * this is given if rhs < infinity and <c,r> > 0, since we then enforce <c,p+t*r> = <c,p> + t<c,r> <= rhs, i.e., t <= (rhs - <c,p>)/<c,r>
9229  * similar, lhs > -infinity and <c,r> < 0 is good
9230  */
9231  SCIP_Real rayprod;
9232 
9233  rayprod = 0.0; /* for compiler */
9234  SCIP_CALL( generateCutUnboundedLP(scip, conshdlr, conss[c], violside, &row, &rayprod, conshdlrdata->checkcurvature) );
9235 
9236  if( row != NULL )
9237  {
9238  if( !SCIPisInfinity(scip, SCIProwGetRhs(row)) && SCIPisPositive(scip, rayprod) )
9239  efficacy = rayprod;
9240  else if( !SCIPisInfinity(scip, -SCIProwGetLhs(row)) && SCIPisNegative(scip, rayprod) )
9241  efficacy = -rayprod;
9242  else
9243  efficacy = 0.0;
9244 
9245  SCIP_CALL( processCut(scip, &row, conshdlr, conss[c], efficacy, minefficacy, inenforcement, bestefficacy, result) );
9246  }
9247  continue;
9248  }
9249  else
9250  {
9251  SCIP_CALL( generateCutSol(scip, conshdlr, conss[c], sol, NULL, violside, &row, &efficacy,
9252  conshdlrdata->checkcurvature, minefficacy, 'd') );
9253 
9254  SCIP_CALL( processCut(scip, &row, conshdlr, conss[c], efficacy, minefficacy, inenforcement, bestefficacy, result) );
9255  }
9256 
9257  if( *result == SCIP_CUTOFF )
9258  break;
9259 
9260  /* enforce only useful constraints
9261  * others are only checked and enforced if we are still feasible or have not found a separating cut yet
9262  */
9263  if( c >= nusefulconss && *result == SCIP_SEPARATED )
9264  break;
9265  }
9266 
9267  return SCIP_OKAY;
9268 }
9269 
9270 /** adds linearizations cuts for convex constraints w.r.t. a given reference point to cutpool and sepastore
9271  *
9272  * - If separatedlpsol is not NULL, then a cut that separates the LP solution is added to the sepastore and is forced to enter the LP.
9273  * - If separatedlpsol is not NULL, but cut does not separate the LP solution, then it is added to the cutpool only.
9274  * - If separatedlpsol is NULL, then cut is added to cutpool only.
9275  */
9276 static
9278  SCIP* scip, /**< SCIP data structure */
9279  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
9280  SCIP_CONS** conss, /**< constraints */
9281  int nconss, /**< number of constraints */
9282  SCIP_SOL* ref, /**< reference point where to linearize, or NULL for LP solution */
9283  SCIP_Bool* separatedlpsol, /**< buffer to store whether a cut that separates the current LP solution was found and added to LP,
9284  * or NULL if adding to cutpool only */
9285  SCIP_Real minefficacy /**< minimal efficacy of a cut when checking for separation of LP solution */
9286  )
9287 {
9288  SCIP_CONSHDLRDATA* conshdlrdata;
9289  SCIP_CONSDATA* consdata;
9290  SCIP_Bool addedtolp;
9291  SCIP_ROW* row;
9292  int c;
9293 
9294  assert(scip != NULL);
9295  assert(conshdlr != NULL);
9296  assert(conss != NULL || nconss == 0);
9297 
9298  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9299  assert(conshdlrdata != NULL);
9300 
9301  if( separatedlpsol != NULL )
9302  *separatedlpsol = FALSE;
9303 
9304  for( c = 0; c < nconss; ++c )
9305  {
9306  assert(conss[c] != NULL); /*lint !e613 */
9307 
9308  if( SCIPconsIsLocal(conss[c]) || !SCIPconsIsEnabled(conss[c]) ) /*lint !e613 */
9309  continue;
9310 
9311  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
9312 
9313  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
9314  assert(consdata != NULL);
9315 
9316  if( consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs) )
9317  {
9318  SCIP_CALL( generateCutSol(scip, conshdlr, conss[c], NULL, ref, SCIP_SIDETYPE_RIGHT, &row, NULL,
9319  conshdlrdata->checkcurvature, -SCIPinfinity(scip), 'l') ); /*lint !e613 */
9320  }
9321  else if( consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs) )
9322  {
9323  SCIP_CALL( generateCutSol(scip, conshdlr, conss[c], NULL, ref, SCIP_SIDETYPE_LEFT, &row, NULL,
9324  conshdlrdata->checkcurvature, -SCIPinfinity(scip), 'l') ); /*lint !e613 */
9325  }
9326  else
9327  continue;
9328 
9329  if( row == NULL )
9330  continue;
9331 
9332  addedtolp = FALSE;
9333 
9334  /* if caller wants, then check if cut separates LP solution and add to sepastore if so */
9335  if( separatedlpsol != NULL )
9336  {
9337  SCIP_Real efficacy;
9338 
9339  efficacy = -SCIPgetRowLPFeasibility(scip, row);
9340  if( efficacy >= minefficacy )
9341  {
9342  SCIP_Bool infeasible;
9343 
9344  *separatedlpsol = TRUE;
9345  addedtolp = TRUE;
9346  SCIP_CALL( SCIPaddRow(scip, row, TRUE, &infeasible) );
9347  assert( ! infeasible );
9348  SCIPdebugMsg(scip, "added linearization cut <%s> to LP, efficacy = %g\n", SCIProwGetName(row), efficacy);
9349  }
9350  }
9351 
9352  if( !SCIProwIsLocal(row) && !addedtolp )
9353  {
9354  SCIP_CALL( SCIPaddPoolCut(scip, row) );
9355  SCIPdebugMsg(scip, "added linearization cut <%s> to cutpool\n", SCIProwGetName(row));
9356  }
9357 
9358  SCIP_CALL( SCIPreleaseRow(scip, &row) );
9359  }
9360 
9361  return SCIP_OKAY;
9362 }
9363 
9364 /** processes the event that a new primal solution has been found */
9365 static
9366 SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
9368  SCIP_CONSHDLRDATA* conshdlrdata;
9369  SCIP_CONSHDLR* conshdlr;
9370  SCIP_CONS** conss;
9371  int nconss;
9372  SCIP_SOL* sol;
9373 
9374  assert(scip != NULL);
9375  assert(event != NULL);
9376  assert(eventdata != NULL);
9377  assert(eventhdlr != NULL);
9378 
9379  assert((SCIPeventGetType(event) & SCIP_EVENTTYPE_SOLFOUND) != 0);
9380 
9381  conshdlr = (SCIP_CONSHDLR*)eventdata;
9382 
9383  nconss = SCIPconshdlrGetNConss(conshdlr);
9384 
9385  if( nconss == 0 )
9386  return SCIP_OKAY;
9387 
9388  sol = SCIPeventGetSol(event);
9389  assert(sol != NULL);
9390 
9391  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9392  assert(conshdlrdata != NULL);
9393 
9394  /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
9395  * the reason for ignoring trysol solutions is that they may come from an NLP solve in sepalp, where we already added linearizations,
9396  * or are from the tree, but postprocessed via proposeFeasibleSolution
9397  */
9398  if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
9399  return SCIP_OKAY;
9400 
9401  conss = SCIPconshdlrGetConss(conshdlr);
9402  assert(conss != NULL);
9403 
9404  SCIPdebugMsg(scip, "caught new sol event %" SCIP_EVENTTYPE_FORMAT " from heur <%s>; have %d conss\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)), nconss);
9405 
9406  SCIP_CALL( addLinearizationCuts(scip, conshdlr, conss, nconss, sol, NULL, 0.0) );
9407 
9408  return SCIP_OKAY;
9409 }
9410 
9411 /** registers branching candidates according to convexification gap rule
9412  *
9413  * That is, computes for every nonconvex term the gap between the terms value in the LP solution and the value of the underestimator
9414  * as it would be (and maybe has been) constructed by the separation routines of this constraint handler. Then it registers all
9415  * variables occurring in each term with the computed gap. If variables appear in more than one term, they are registered several times.
9416  */
9417 static
9419  SCIP* scip, /**< SCIP data structure */
9420  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9421  SCIP_CONS** conss, /**< constraints to check */
9422  int nconss, /**< number of constraints to check */
9423  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
9424  int* nnotify /**< counter for number of notifications performed */
9425  )
9426 {
9427  SCIP_CONSHDLRDATA* conshdlrdata;
9428  SCIP_CONSDATA* consdata;
9429  int c;
9430  int j;
9431  SCIP_Bool xbinary;
9432  SCIP_Bool ybinary;
9433  SCIP_Bool xunbounded;
9434  SCIP_Bool yunbounded;
9435  SCIP_VAR* x;
9436  SCIP_VAR* y;
9437  SCIP_Real xlb;
9438  SCIP_Real xub;
9439  SCIP_Real xval;
9440  SCIP_Real ylb;
9441  SCIP_Real yub;
9442  SCIP_Real yval;
9443  SCIP_Real gap;
9444  SCIP_Real coef_;
9445 
9446  assert(scip != NULL);
9447  assert(conshdlr != NULL);
9448  assert(conss != NULL || nconss == 0);
9449 
9450  *nnotify = 0;
9451  yval = SCIP_INVALID;
9452  xval = SCIP_INVALID;
9453 
9454  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9455  assert(conshdlr != NULL);
9456 
9457  for( c = 0; c < nconss; ++c )
9458  {
9459  assert(conss != NULL);
9460  consdata = SCIPconsGetData(conss[c]);
9461  assert(consdata != NULL);
9462 
9463  if( !consdata->nquadvars )
9464  continue;
9465 
9466  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || consdata->isconcave) &&
9467  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || consdata->isconvex ) )
9468  continue;
9469  SCIPdebugMsg(scip, "cons <%s> violation: %g %g convex: %u %u\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->isconvex, consdata->isconcave);
9470 
9471  /* square terms */
9472  for( j = 0; j < consdata->nquadvars; ++j )
9473  {
9474  x = consdata->quadvarterms[j].var;
9475  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && consdata->quadvarterms[j].sqrcoef < 0) ||
9476  ( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && consdata->quadvarterms[j].sqrcoef > 0) )
9477  {
9478  xlb = SCIPvarGetLbLocal(x);
9479  xub = SCIPvarGetUbLocal(x);
9480  if( SCIPisRelEQ(scip, xlb, xub) )
9481  {
9482  SCIPdebugMsg(scip, "ignore fixed variable <%s>[%g, %g], diff %g\n", SCIPvarGetName(x), xlb, xub, xub-xlb);
9483  continue;
9484  }
9485 
9486  xval = SCIPgetSolVal(scip, sol, x);
9487 
9488  /* if variable is at bounds, then no need to branch, since secant is exact there */
9489  if( SCIPisLE(scip, xval, xlb) || SCIPisGE(scip, xval, xub) )
9490  continue;
9491 
9492  if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) )
9493  gap = SCIPinfinity(scip);
9494  else
9495  gap = (xval-xlb)*(xub-xval)/(1+2*ABS(xval));
9496  assert(!SCIPisFeasNegative(scip, gap));
9497  SCIP_CALL( SCIPaddExternBranchCand(scip, x, MAX(gap, 0.0), SCIP_INVALID) );
9498  ++*nnotify;
9499  }
9500  }
9501 
9502  /* bilinear terms */
9503  for( j = 0; j < consdata->nbilinterms; ++j )
9504  {
9505  /* if any of the variables if fixed, then it actually behaves like a linear term, so we don't need to branch on it */
9506  x = consdata->bilinterms[j].var1;
9507  xlb = SCIPvarGetLbLocal(x);
9508  xub = SCIPvarGetUbLocal(x);
9509  if( SCIPisRelEQ(scip, xlb, xub) )
9510  continue;
9511 
9512  y = consdata->bilinterms[j].var2;
9513  ylb = SCIPvarGetLbLocal(y);
9514  yub = SCIPvarGetUbLocal(y);
9515  if( SCIPisRelEQ(scip, ylb, yub) )
9516  continue;
9517 
9518  xunbounded = SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub);
9519  yunbounded = SCIPisInfinity(scip, -ylb) || SCIPisInfinity(scip, yub);
9520 
9521  /* compute gap, if both variable are bounded */
9522  gap = SCIPinfinity(scip);
9523  if( !xunbounded && !yunbounded )
9524  {
9525  xval = SCIPgetSolVal(scip, sol, x);
9526  yval = SCIPgetSolVal(scip, sol, y);
9527 
9528  /* if both variables are at one of its bounds, then no need to branch, since McCormick is exact there */
9529  if( (SCIPisLE(scip, xval, xlb) || SCIPisGE(scip, xval, xub)) &&
9530  ( SCIPisLE(scip, yval, ylb) || SCIPisGE(scip, yval, yub)) )
9531  continue;
9532 
9533  xval = MAX(xlb, MIN(xval, xub));
9534  yval = MAX(ylb, MIN(yval, yub));
9535 
9536  coef_ = SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) ? -consdata->bilinterms[j].coef : consdata->bilinterms[j].coef;
9537  if( coef_ > 0.0 )
9538  {
9539  if( (xub-xlb)*yval + (yub-ylb)*xval <= xub*yub - xlb*ylb )
9540  gap = (xval*yval - xlb*yval - ylb*xval + xlb*ylb) / (1+sqrt(xval*xval + yval*yval));
9541  else
9542  gap = (xval*yval - xval*yub - yval*xub + xub*yub) / (1+sqrt(xval*xval + yval*yval));
9543  }
9544  else
9545  { /* coef_ < 0 */
9546  if( (xub-xlb)*yval - (yub-ylb)*xval <= xub*ylb - xlb*yub )
9547  gap = -(xval*yval - xval*ylb - yval*xub + xub*ylb) / (1+sqrt(xval*xval + yval*yval));
9548  else
9549  gap = -(xval*yval - xval*yub - yval*xlb + xlb*yub) / (1+sqrt(xval*xval + yval*yval));
9550  }
9551 
9552  assert(!SCIPisNegative(scip, gap / MAX3(MAX(REALABS(xlb), REALABS(xub)), MAX(REALABS(ylb), REALABS(yub)), 1.0))); /*lint !e666*/
9553  if( gap < 0.0 )
9554  gap = 0.0;
9555 
9556  /* use tighter relaxation when using linear inequalities to adjust the branching scores for bilinear terms */
9557  if( consdata->bilintermsidx != NULL && conshdlrdata->usebilinineqbranch )
9558  {
9559  BILINESTIMATOR* bilinestimator;
9560  int bilinidx;
9561 
9562  assert(conshdlrdata->bilinestimators != NULL);
9563 
9564  bilinidx = consdata->bilintermsidx[j];
9565  assert(bilinidx >= 0 && bilinidx < conshdlrdata->nbilinterms);
9566 
9567  bilinestimator = &conshdlrdata->bilinestimators[bilinidx];
9568  assert(bilinestimator != NULL);
9569  assert(bilinestimator->x == x);
9570  assert(bilinestimator->y == y);
9571 
9572  if( SCIPisGT(scip, bilinestimator->lastimprfac, 0.0) )
9573  gap *= MAX(0.0, 1.0 - bilinestimator->lastimprfac);
9574  }
9575  }
9576 
9577  /* if one of the variables is binary or integral with domain width 1, then branching on this makes the term linear, so prefer this */
9578  xbinary = SCIPvarIsBinary(x) || (SCIPvarIsIntegral(x) && xub - xlb < 1.5);
9579  ybinary = SCIPvarIsBinary(y) || (SCIPvarIsIntegral(y) && yub - ylb < 1.5);
9580  if( xbinary )
9581  {
9583  ++*nnotify;
9584  }
9585  if( ybinary )
9586  {
9588  ++*nnotify;
9589  }
9590  if( xbinary || ybinary )
9591  continue;
9592 
9593  /* if one of the variables is unbounded, then branch on it first */
9594  if( xunbounded )
9595  {
9597  ++*nnotify;
9598  }
9599  if( yunbounded )
9600  {
9602  ++*nnotify;
9603  }
9604  if( xunbounded || yunbounded )
9605  continue;
9606 
9607  /* if both variables are integral, prefer the one with the smaller domain, so variable gets fixed soon
9608  * does not seem to work well on tln instances, so disable for now and may look at it later again
9609  */
9610 #ifdef BRANCHTOLINEARITY
9611  if( SCIPvarIsIntegral(x) && SCIPvarIsIntegral(y) )
9612  {
9613  if( SCIPisLT(scip, xub-xlb, yub-ylb) )
9614  {
9616  ++*nnotify;
9617  continue;
9618  }
9619  if( SCIPisGT(scip, xub-xlb, yub-ylb) )
9620  {
9622  ++*nnotify;
9623  continue;
9624  }
9625  }
9626 #endif
9627 
9628  /* in the regular case, suggest those variables which are not at its bounds for branching
9629  * this is, because after branching both variables will be one the bounds, and McCormick will be exact then */
9630  if( !SCIPisLE(scip, xval, xlb) && !SCIPisGE(scip, xval, xub) )
9631  {
9633  ++*nnotify;
9634  }
9635  if( !SCIPisLE(scip, yval, ylb) && !SCIPisGE(scip, yval, yub) )
9636  {
9638  ++*nnotify;
9639  }
9640  }
9641  }
9642 
9643  SCIPdebugMsg(scip, "registered %d branching candidates\n", *nnotify);
9644 
9645  return SCIP_OKAY;
9646 }
9647 
9648 /** registers branching candidates according to constraint violation rule
9649  *
9650  * That is, registers all variables appearing in nonconvex terms^1 with a score that is the violation of the constraint.
9651  * This is the same rule as is applied in cons_nonlinear and other nonlinear constraint handlers.
9652  *
9653  * 1) We mean all quadratic variables that appear either in a nonconvex square term or in a bilinear term, if the constraint
9654  * itself is nonconvex. (and this under the assumption that the rhs is violated; for violated lhs, swap terms)
9655  */
9656 static
9658  SCIP* scip, /**< SCIP data structure */
9659  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9660  SCIP_CONS** conss, /**< constraints to check */
9661  int nconss, /**< number of constraints to check */
9662  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
9663  int* nnotify /**< counter for number of notifications performed */
9664  )
9665 {
9666  SCIP_CONSDATA* consdata;
9667  SCIP_QUADVARTERM* quadvarterm;
9668  int c;
9669  int j;
9670  SCIP_VAR* x;
9671  SCIP_Real xlb;
9672  SCIP_Real xub;
9673  SCIP_Real xval;
9674 
9675  assert(scip != NULL);
9676  assert(conshdlr != NULL);
9677  assert(conss != NULL || nconss == 0);
9678 
9679  *nnotify = 0;
9680 
9681  for( c = 0; c < nconss; ++c )
9682  {
9683  assert(conss != NULL);
9684  consdata = SCIPconsGetData(conss[c]);
9685  assert(consdata != NULL);
9686 
9687  if( !consdata->nquadvars )
9688  continue;
9689 
9690  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || consdata->isconcave) &&
9691  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || consdata->isconvex ) )
9692  continue;
9693  SCIPdebugMsg(scip, "cons %s violation: %g %g convex: %u %u\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->isconvex, consdata->isconcave);
9694 
9695  for( j = 0; j < consdata->nquadvars; ++j )
9696  {
9697  quadvarterm = &consdata->quadvarterms[j];
9698  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef < 0) ||
9699  (SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef > 0) ||
9700  quadvarterm->nadjbilin > 0 )
9701  {
9702  x = quadvarterm->var;
9703  xlb = SCIPvarGetLbLocal(x);
9704  xub = SCIPvarGetUbLocal(x);
9705 
9706  if( quadvarterm->nadjbilin == 0 )
9707  {
9708  xval = SCIPgetSolVal(scip, sol, x);
9709 
9710  /* if variable is at bounds and only in a nonconvex square term, then no need to branch, since secant is exact there */
9711  if( SCIPisLE(scip, xval, xlb) || SCIPisGE(scip, xval, xub) )
9712  continue;
9713  }
9714 
9715  if( SCIPisRelEQ(scip, xlb, xub) )
9716  {
9717  SCIPdebugMsg(scip, "ignore fixed variable <%s>[%g, %g], diff %g\n", SCIPvarGetName(x), xlb, xub, xub-xlb);
9718  continue;
9719  }
9720 
9721  SCIP_CALL( SCIPaddExternBranchCand(scip, x, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
9722  ++*nnotify;
9723  }
9724  }
9725  }
9726 
9727  SCIPdebugMsg(scip, "registered %d branching candidates\n", *nnotify);
9728 
9729  return SCIP_OKAY;
9730 }
9731 
9732 /** registers branching candidates according to centrality rule
9733  *
9734  * That is, registers all variables appearing in nonconvex terms^1 with a score that is given by the distance of the
9735  * variable value from its bounds. This rule should not make sense, as the distance to the bounds is also (often) considered
9736  * by the branching rule later on.
9737  *
9738  * 1) We mean all quadratic variables that appear either in a nonconvex square term or in a bilinear term, if the constraint
9739  * itself is nonconvex. (and this under the assumption that the rhs is violated; for violated lhs, swap terms)
9740  */
9741 static
9743  SCIP* scip, /**< SCIP data structure */
9744  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9745  SCIP_CONS** conss, /**< constraints to check */
9746  int nconss, /**< number of constraints to check */
9747  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
9748  int* nnotify /**< counter for number of notifications performed */
9749  )
9750 {
9751  SCIP_CONSDATA* consdata;
9752  SCIP_QUADVARTERM* quadvarterm;
9753  int c;
9754  int j;
9755  SCIP_VAR* x;
9756  SCIP_Real xlb;
9757  SCIP_Real xub;
9758  SCIP_Real xval;
9759  SCIP_Real score;
9760 
9761  assert(scip != NULL);
9762  assert(conshdlr != NULL);
9763  assert(conss != NULL || nconss == 0);
9764 
9765  *nnotify = 0;
9766 
9767  for( c = 0; c < nconss; ++c )
9768  {
9769  assert(conss != NULL);
9770  consdata = SCIPconsGetData(conss[c]);
9771  assert(consdata != NULL);
9772 
9773  if( !consdata->nquadvars )
9774  continue;
9775 
9776  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || consdata->isconcave) &&
9777  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || consdata->isconvex ) )
9778  continue;
9779  SCIPdebugMsg(scip, "cons %s violation: %g %g convex: %u %u\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->isconvex, consdata->isconcave);
9780 
9781  for( j = 0; j < consdata->nquadvars; ++j )
9782  {
9783  quadvarterm = &consdata->quadvarterms[j];
9784  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef < 0) ||
9785  (SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef > 0) ||
9786  quadvarterm->nadjbilin > 0 )
9787  {
9788  x = quadvarterm->var;
9789  xlb = SCIPvarGetLbLocal(x);
9790  xub = SCIPvarGetUbLocal(x);
9791 
9792  if( SCIPisRelEQ(scip, xlb, xub) )
9793  {
9794  SCIPdebugMsg(scip, "ignore fixed variable <%s>[%g, %g], diff %g\n", SCIPvarGetName(x), xlb, xub, xub-xlb);
9795  continue;
9796  }
9797 
9798  xval = SCIPgetSolVal(scip, sol, x);
9799  xval = MAX(xlb, MIN(xub, xval));
9800 
9801  /* compute relative difference of xval to each of its bounds
9802  * and scale such that if xval were in the middle, we get a score of 1
9803  * and if xval is on one its bounds, the score is 0
9804  */
9805  if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) )
9806  {
9807  if( (!SCIPisInfinity(scip, -xlb) && SCIPisEQ(scip, xval, xlb)) || (!SCIPisInfinity(scip, xub) && SCIPisEQ(scip, xval, xub)) )
9808  score = 0.0;
9809  else
9810  score = 1.0;
9811  }
9812  else
9813  {
9814  score = 4.0 * (xval - xlb) * (xub - xval) / ((xub - xlb) * (xub - xlb));
9815  }
9816 
9817  SCIP_CALL( SCIPaddExternBranchCand(scip, x, score, SCIP_INVALID) );
9818  ++*nnotify;
9819  }
9820  }
9821  }
9822 
9823  SCIPdebugMsg(scip, "registered %d branching candidates\n", *nnotify);
9824 
9825  return SCIP_OKAY;
9826 }
9827 
9828 /** registers branching candidates */
9829 static
9831  SCIP* scip, /**< SCIP data structure */
9832  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9833  SCIP_CONS** conss, /**< constraints to check */
9834  int nconss, /**< number of constraints to check */
9835  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
9836  int* nnotify /**< counter for number of notifications performed */
9837  )
9838 {
9839  SCIP_CONSHDLRDATA* conshdlrdata;
9840 
9841  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9842  assert(conshdlrdata != NULL);
9843 
9844  switch( conshdlrdata->branchscoring )
9845  {
9846  case 'g' :
9847  SCIP_CALL( registerBranchingCandidatesGap(scip, conshdlr, conss, nconss, sol, nnotify) );
9848  break;
9849 
9850  case 'v' :
9851  SCIP_CALL( registerBranchingCandidatesViolation(scip, conshdlr, conss, nconss, sol, nnotify) );
9852  break;
9853 
9854  case 'c' :
9855  SCIP_CALL( registerBranchingCandidatesCentrality(scip, conshdlr, conss, nconss, sol, nnotify) );
9856  break;
9857 
9858  default :
9859  SCIPerrorMessage("invalid branchscoring selection");
9860  SCIPABORT();
9861  return SCIP_ERROR; /*lint !e527*/
9862  }
9863 
9864  return SCIP_OKAY;
9865 }
9866 
9867 
9868 /** registers a quadratic variable from a violated constraint as branching candidate that has a large absolute value in the (LP) relaxation */
9869 static
9871  SCIP* scip, /**< SCIP data structure */
9872  SCIP_CONS** conss, /**< constraints */
9873  int nconss, /**< number of constraints */
9874  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
9875  SCIP_VAR** brvar /**< buffer to store branching variable */
9876  )
9877 {
9878  SCIP_CONSDATA* consdata;
9879  SCIP_Real val;
9880  SCIP_Real brvarval;
9881  int i;
9882  int c;
9883 
9884  assert(scip != NULL);
9885  assert(conss != NULL || nconss == 0);
9886 
9887  *brvar = NULL;
9888  brvarval = -1.0;
9889 
9890  for( c = 0; c < nconss; ++c )
9891  {
9892  assert(conss != NULL);
9893  consdata = SCIPconsGetData(conss[c]);
9894  assert(consdata != NULL);
9895 
9896  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
9897  continue;
9898 
9899  for( i = 0; i < consdata->nquadvars; ++i )
9900  {
9901  /* do not propose fixed variables */
9902  if( SCIPisRelEQ(scip, SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
9903  continue;
9904  val = SCIPgetSolVal(scip, sol, consdata->quadvarterms[i].var);
9905  if( ABS(val) > brvarval )
9906  {
9907  brvarval = ABS(val);
9908  *brvar = consdata->quadvarterms[i].var;
9909  }
9910  }
9911  }
9912 
9913  if( *brvar != NULL )
9914  {
9915  SCIP_CALL( SCIPaddExternBranchCand(scip, *brvar, brvarval, SCIP_INVALID) );
9916  }
9917 
9918  return SCIP_OKAY;
9919 }
9920 
9921 /** replaces violated quadratic constraints where all quadratic variables are fixed by linear constraints */
9922 static
9924  SCIP* scip, /**< SCIP data structure */
9925  SCIP_CONS** conss, /**< constraints */
9926  int nconss, /**< number of constraints */
9927  SCIP_Bool* addedcons, /**< buffer to store whether a linear constraint was added */
9928  SCIP_Bool* reduceddom, /**< whether a domain has been reduced */
9929  SCIP_Bool* infeasible /**< whether we detected infeasibility */
9930  )
9931 {
9932  SCIP_CONS* cons;
9933  SCIP_CONSDATA* consdata;
9934  SCIP_RESULT checkresult;
9935  SCIP_VAR* var;
9936  SCIP_Bool tightened;
9937  SCIP_Real constant;
9938  SCIP_Real val1;
9939  SCIP_Real val2;
9940  int i;
9941  int c;
9942 
9943  assert(scip != NULL);
9944  assert(conss != NULL || nconss == 0);
9945  assert(addedcons != NULL);
9946  assert(reduceddom != NULL);
9947  assert(infeasible != NULL);
9948 
9949  *addedcons = FALSE;
9950  *reduceddom = FALSE;
9951  *infeasible = FALSE;
9952 
9953  for( c = 0; c < nconss; ++c )
9954  {
9955  assert(conss != NULL);
9956  consdata = SCIPconsGetData(conss[c]);
9957  assert(consdata != NULL);
9958 
9959  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
9960  continue;
9961 
9962  constant = 0.0;
9963 
9964  for( i = 0; i < consdata->nquadvars; ++i )
9965  {
9966  var = consdata->quadvarterms[i].var;
9967 
9968  /* variables should be fixed if constraint is violated */
9969  assert(SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)));
9970 
9971  val1 = (SCIPvarGetUbLocal(var) + SCIPvarGetLbLocal(var)) / 2.0;
9972  constant += (consdata->quadvarterms[i].lincoef + consdata->quadvarterms[i].sqrcoef * val1) * val1;
9973 
9974  SCIPdebugMessage("<%s>: [%.20g, %.20g]\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
9975 
9976  /* if variable is not fixed w.r.t. absolute eps yet, then try to fix it
9977  * (SCIPfixVar() doesn't allow for small tightenings, so tighten lower and upper bound separately)
9978  */
9979  if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
9980  {
9981  SCIP_CALL( SCIPtightenVarLb(scip, var, val1, TRUE, infeasible, &tightened) );
9982  if( *infeasible )
9983  {
9984  SCIPdebugMsg(scip, "Fixing almost fixed variable <%s> lead to infeasibility.\n", SCIPvarGetName(var));
9985  return SCIP_OKAY;
9986  }
9987  if( tightened )
9988  {
9989  SCIPdebugMsg(scip, "Tightened lower bound of almost fixed variable <%s>.\n", SCIPvarGetName(var));
9990  *reduceddom = TRUE;
9991  }
9992 
9993  SCIP_CALL( SCIPtightenVarUb(scip, var, val1, TRUE, infeasible, &tightened) );
9994  if( *infeasible )
9995  {
9996  SCIPdebugMsg(scip, "Fixing almost fixed variable <%s> lead to infeasibility.\n", SCIPvarGetName(var));
9997  return SCIP_OKAY;
9998  }
9999  if( tightened )
10000  {
10001  SCIPdebugMsg(scip, "Tightened upper bound of almost fixed variable <%s>.\n", SCIPvarGetName(var));
10002  *reduceddom = TRUE;
10003  }
10004  }
10005  }
10006 
10007  /* if some quadratic variable was fixed now, then restart node (next enfo round) */
10008  if( *reduceddom )
10009  return SCIP_OKAY;
10010 
10011  for( i = 0; i < consdata->nbilinterms; ++i )
10012  {
10013  val1 = (SCIPvarGetUbLocal(consdata->bilinterms[i].var1) + SCIPvarGetLbLocal(consdata->bilinterms[i].var1)) / 2.0;
10014  val2 = (SCIPvarGetUbLocal(consdata->bilinterms[i].var2) + SCIPvarGetLbLocal(consdata->bilinterms[i].var2)) / 2.0;
10015  constant += consdata->bilinterms[i].coef * val1 * val2;
10016  }
10017 
10018  /* check if we have a bound change */
10019  if ( consdata->nlinvars == 1 )
10020  {
10021  SCIP_Real coef;
10022  SCIP_Real lhs;
10023  SCIP_Real rhs;
10024 
10025  coef = *consdata->lincoefs;
10026  var = *consdata->linvars;
10027 
10028  assert( ! SCIPisZero(scip, coef) );
10029 
10030  /* compute lhs/rhs, divide already by |coef| */
10031  if ( SCIPisInfinity(scip, -consdata->lhs) )
10032  lhs = -SCIPinfinity(scip);
10033  else
10034  lhs = (consdata->lhs - constant) / REALABS(coef);
10035 
10036  if ( SCIPisInfinity(scip, consdata->rhs) )
10037  rhs = SCIPinfinity(scip);
10038  else
10039  rhs = (consdata->rhs - constant) / REALABS(coef);
10040 
10041  SCIPdebugMsg(scip, "Linear constraint with one variable: %.20g <= %g <%s> <= %.20g\n", lhs, coef > 0.0 ? 1.0 : -1.0, SCIPvarGetName(var), rhs);
10042 
10043  SCIPdebugMessage("<%s>: [%.20g, %.20g]\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
10044 
10045  if ( coef < 0.0 )
10046  {
10047  /* swap lhs and rhs, with negated sign */
10048  SCIP_Real h;
10049  h = rhs;
10050  rhs = -lhs;
10051  lhs = -h;
10052  }
10053  SCIPdebugMsg(scip, "Linear constraint is a bound: %.20g <= <%s> <= %.20g\n", lhs, SCIPvarGetName(var), rhs);
10054 
10055  if( SCIPisInfinity(scip, -rhs) || SCIPisInfinity(scip, lhs) )
10056  {
10057  SCIPdebugMsg(scip, "node will marked as infeasible since lb/ub of %s is +/-infinity\n",
10058  SCIPvarGetName(var));
10059 
10060  *infeasible = TRUE;
10061  return SCIP_OKAY;
10062  }
10063 
10064  if ( ! SCIPisInfinity(scip, -lhs) )
10065  {
10066  SCIP_CALL( SCIPtightenVarLb(scip, var, lhs, TRUE, infeasible, &tightened) );
10067  if ( *infeasible )
10068  {
10069  SCIPdebugMsg(scip, "Lower bound leads to infeasibility.\n");
10070  return SCIP_OKAY;
10071  }
10072  if ( tightened )
10073  {
10074  SCIPdebugMsg(scip, "Lower bound changed.\n");
10075  *reduceddom = TRUE;
10076  return SCIP_OKAY;
10077  }
10078  }
10079 
10080  if ( ! SCIPisInfinity(scip, rhs) )
10081  {
10082  SCIP_CALL( SCIPtightenVarUb(scip, var, rhs, TRUE, infeasible, &tightened) );
10083  if ( *infeasible )
10084  {
10085  SCIPdebugMsg(scip, "Upper bound leads to infeasibility.\n");
10086  return SCIP_OKAY;
10087  }
10088  if ( tightened )
10089  {
10090  SCIPdebugMsg(scip, "Upper bound changed.\n");
10091  *reduceddom = TRUE;
10092  return SCIP_OKAY;
10093  }
10094  }
10095  }
10096  else
10097  {
10098  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, SCIPconsGetName(conss[c]),
10099  consdata->nlinvars, consdata->linvars, consdata->lincoefs,
10100  (SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : (consdata->lhs - constant)),
10101  (SCIPisInfinity(scip, consdata->rhs) ? SCIPinfinity(scip) : (consdata->rhs - constant)),
10102  SCIPconsIsInitial(conss[c]), SCIPconsIsSeparated(conss[c]), SCIPconsIsEnforced(conss[c]),
10103  SCIPconsIsChecked(conss[c]), SCIPconsIsPropagated(conss[c]), TRUE,
10104  SCIPconsIsModifiable(conss[c]), SCIPconsIsDynamic(conss[c]), SCIPconsIsRemovable(conss[c]),
10105  SCIPconsIsStickingAtNode(conss[c])) );
10106 
10107  SCIPdebugMsg(scip, "replace quadratic constraint <%s> by linear constraint after all quadratic vars have been fixed\n", SCIPconsGetName(conss[c]) );
10108  SCIPdebugPrintCons(scip, cons, NULL);
10109 
10110  SCIP_CALL( SCIPcheckCons(scip, cons, NULL, FALSE, FALSE, FALSE, &checkresult) );
10111 
10112  if( checkresult != SCIP_INFEASIBLE && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
10113  {
10114  SCIPdebugMsg(scip, "linear constraint is feasible and LP optimal, thus do not add\n");
10115  }
10116  else
10117  {
10118  SCIP_CALL( SCIPaddConsLocal(scip, cons, NULL) );
10119  *addedcons = TRUE;
10120  }
10121  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
10122  }
10123  SCIP_CALL( SCIPdelConsLocal(scip, conss[c]) );
10124  }
10125 
10126  return SCIP_OKAY;
10127 }
10128 
10129 /** tightens a lower bound on a variable and checks the result */
10130 static
10132  SCIP* scip, /**< SCIP data structure */
10133  SCIP_CONS* cons, /**< constraint where we currently propagate */
10134  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
10135  SCIP_VAR* var, /**< variable which domain we might reduce */
10136  SCIP_Real bnd, /**< new lower bound for variable */
10137  SCIP_RESULT* result, /**< result to update if there was a tightening or cutoff */
10138  int* nchgbds /**< counter to increase if a bound was tightened */
10139  )
10140 {
10141  SCIP_Bool infeas;
10142  SCIP_Bool tightened;
10143 
10144  assert(scip != NULL);
10145  assert(cons != NULL);
10146  assert(intervalinfty > 0.0);
10147  assert(bnd > -intervalinfty);
10148  assert(var != NULL);
10149  assert(result != NULL);
10150  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
10151  assert(nchgbds != NULL);
10152 
10153  /* new bound is no improvement */
10154  if( SCIPisHugeValue(scip, -bnd) || SCIPisLE(scip, bnd, SCIPvarGetLbLocal(var)) )
10155  return SCIP_OKAY;
10156 
10157  if( SCIPisInfinity(scip, bnd) )
10158  { /* domain will be outside [-infty, +infty] -> declare node infeasible */
10159  *result = SCIP_CUTOFF;
10160  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10161  return SCIP_OKAY;
10162  }
10163 
10164  /* new lower bound is very low (between -intervalinfty and -SCIPinfinity()) */
10165  if( SCIPisInfinity(scip, -bnd) )
10166  return SCIP_OKAY;
10167 
10168  bnd = SCIPadjustedVarLb(scip, var, bnd);
10169  SCIP_CALL( SCIPtightenVarLb(scip, var, bnd, FALSE, &infeas, &tightened) );
10170  if( infeas )
10171  {
10172  SCIPdebugMsg(scip, "%s found constraint <%s> infeasible due to tightened lower bound %g for variable <%s>\n",
10173  SCIPinProbing(scip) ? "in probing" : "", SCIPconsGetName(cons), bnd, SCIPvarGetName(var));
10174  *result = SCIP_CUTOFF;
10175  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10176  return SCIP_OKAY;
10177  }
10178  if( tightened )
10179  {
10180  SCIPdebugMsg(scip, "%s tightened lower bound of variable <%s> in constraint <%s> to %g\n",
10181  SCIPinProbing(scip) ? "in probing" : "", SCIPvarGetName(var), SCIPconsGetName(cons), bnd);
10182  ++*nchgbds;
10183  *result = SCIP_REDUCEDDOM;
10184  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10185  }
10186 
10187  return SCIP_OKAY;
10188 }
10189 
10190 /** tightens an upper bound on a variable and checks the result */
10191 static
10193  SCIP* scip, /**< SCIP data structure */
10194  SCIP_CONS* cons, /**< constraint where we currently propagate */
10195  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
10196  SCIP_VAR* var, /**< variable which domain we might reduce */
10197  SCIP_Real bnd, /**< new upper bound for variable */
10198  SCIP_RESULT* result, /**< result to update if there was a tightening or cutoff */
10199  int* nchgbds /**< counter to increase if a bound was tightened */
10200  )
10201 {
10202  SCIP_Bool infeas;
10203  SCIP_Bool tightened;
10204 
10205  assert(scip != NULL);
10206  assert(cons != NULL);
10207  assert(intervalinfty > 0.0);
10208  assert(bnd < intervalinfty);
10209  assert(var != NULL);
10210  assert(result != NULL);
10211  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
10212  assert(nchgbds != NULL);
10213 
10214  /* new bound is no improvement */
10215  if( SCIPisHugeValue(scip, bnd) || SCIPisGE(scip, bnd, SCIPvarGetUbLocal(var)) )
10216  return SCIP_OKAY;
10217 
10218  if( SCIPisInfinity(scip, -bnd) )
10219  { /* domain will be outside [-infty, +infty] -> declare node infeasible */
10220  *result = SCIP_CUTOFF;
10221  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10222  return SCIP_OKAY;
10223  }
10224 
10225  /* new upper bound is very high (between SCIPinfinity() and intervalinfty) */
10226  if( SCIPisInfinity(scip, bnd) )
10227  return SCIP_OKAY;
10228 
10229  bnd = SCIPadjustedVarUb(scip, var, bnd);
10230  SCIP_CALL( SCIPtightenVarUb(scip, var, bnd, FALSE, &infeas, &tightened) );
10231  if( infeas )
10232  {
10233  SCIPdebugMsg(scip, "%s found constraint <%s> infeasible due to tightened upper bound %g for variable <%s>\n",
10234  SCIPinProbing(scip) ? "in probing" : "", SCIPconsGetName(cons), bnd, SCIPvarGetName(var));
10235  *result = SCIP_CUTOFF;
10236  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10237  return SCIP_OKAY;
10238  }
10239  if( tightened )
10240  {
10241  SCIPdebugMsg(scip, "%s tightened upper bound of variable <%s> in constraint <%s> to %g\n",
10242  SCIPinProbing(scip) ? "in probing" : "", SCIPvarGetName(var), SCIPconsGetName(cons), bnd);
10243  ++*nchgbds;
10244  *result = SCIP_REDUCEDDOM;
10245  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10246  }
10247 
10248  return SCIP_OKAY;
10249 }
10250 
10251 /** solves a quadratic equation \f$ a x^2 + b x \in rhs \f$ (with b an interval) and reduces bounds on x or deduces infeasibility if possible */
10252 static
10254  SCIP* scip, /**< SCIP data structure */
10255  SCIP_CONS* cons, /**< constraint where we currently propagate */
10256  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
10257  SCIP_VAR* var, /**< variable which bounds with might tighten */
10258  SCIP_Real a, /**< coefficient in square term */
10259  SCIP_INTERVAL b, /**< coefficient in linear term */
10260  SCIP_INTERVAL rhs, /**< right hand side of quadratic equation */
10261  SCIP_RESULT* result, /**< result of propagation */
10262  int* nchgbds /**< buffer where to add number of tightened bounds */
10263  )
10264 {
10265  SCIP_INTERVAL newrange;
10266 
10267  assert(scip != NULL);
10268  assert(cons != NULL);
10269  assert(var != NULL);
10270  assert(result != NULL);
10271  assert(nchgbds != NULL);
10272 
10273  /* compute solution of a*x^2 + b*x \in rhs */
10274  if( a == 0.0 && SCIPintervalGetInf(b) == 0.0 && SCIPintervalGetSup(b) == 0.0 )
10275  {
10276  /* relatively easy case: 0.0 \in rhs, thus check if infeasible or just redundant */
10277  if( SCIPintervalGetInf(rhs) > 0.0 || SCIPintervalGetSup(rhs) < 0.0 )
10278  {
10279  SCIPdebugMsg(scip, "found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(var));
10280  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10281  *result = SCIP_CUTOFF;
10282  }
10283  return SCIP_OKAY;
10284  }
10285  else if( SCIPvarGetLbLocal(var) >= 0.0 )
10286  {
10287  SCIP_INTERVAL a_;
10288 
10289  /* need only positive solutions */
10290  SCIPintervalSet(&a_, a);
10291  SCIPintervalSolveUnivariateQuadExpressionPositive(intervalinfty, &newrange, a_, b, rhs);
10292  }
10293  else if( SCIPvarGetUbLocal(var) <= 0.0 )
10294  {
10295  /* need only negative solutions */
10296  SCIP_INTERVAL a_;
10297  SCIP_INTERVAL tmp;
10298  SCIPintervalSet(&a_, a);
10300  SCIPintervalSolveUnivariateQuadExpressionPositive(intervalinfty, &tmp, a_, tmp, rhs);
10301  if( SCIPintervalIsEmpty(intervalinfty, tmp) )
10302  {
10303  SCIPdebugMsg(scip, "found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(var));
10304  *result = SCIP_CUTOFF;
10305  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10306  return SCIP_OKAY;
10307  }
10309  }
10310  else
10311  {
10312  /* need both positive and negative solution */
10313  SCIP_INTERVAL a_;
10314  SCIPintervalSet(&a_, a);
10315  SCIPintervalSolveUnivariateQuadExpression(intervalinfty, &newrange, a_, b, rhs);
10316  }
10317 
10318  /* SCIPdebugMsg(scip, "%g x^2 + [%g, %g] x in [%g, %g] -> [%g, %g]\n", a, b.inf, b.sup, rhs.inf, rhs.sup, newrange.inf, newrange.sup); */
10319 
10320  if( SCIPisInfinity(scip, SCIPintervalGetInf(newrange)) || SCIPisInfinity(scip, -SCIPintervalGetSup(newrange)) )
10321  {
10322  /* domain outside [-infty, +infty] -> declare node infeasible */
10323  SCIPdebugMsg(scip, "found <%s> infeasible because propagated domain of quadratic variable <%s> is outside of (-infty, +infty)\n",
10324  SCIPconsGetName(cons), SCIPvarGetName(var));
10325  *result = SCIP_CUTOFF;
10326  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10327  return SCIP_OKAY;
10328  }
10329 
10330  if( SCIPintervalIsEmpty(intervalinfty, newrange) )
10331  {
10332  SCIPdebugMsg(scip, "found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(var));
10333  *result = SCIP_CUTOFF;
10334  return SCIP_OKAY;
10335  }
10336 
10337  if( !SCIPisInfinity(scip, -SCIPintervalGetInf(newrange)) )
10338  {
10339  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, SCIPintervalGetInf(newrange), result, nchgbds) );
10340  if( *result == SCIP_CUTOFF )
10341  return SCIP_OKAY;
10342  }
10343 
10344  if( !SCIPisInfinity(scip, SCIPintervalGetSup(newrange)) )
10345  {
10346  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, SCIPintervalGetSup(newrange), result, nchgbds) );
10347  if( *result == SCIP_CUTOFF )
10348  return SCIP_OKAY;
10349  }
10350 
10351  return SCIP_OKAY;
10352 }
10353 
10354 /* The new version below computes potentially tighter bounds, but also always adds a small safety area since it is not implemented roundingsafe.
10355  * This may be a reason why it gives worse results on one of two instances.
10356  * Further, I have only very few instances where one can expect a difference.
10357  */
10358 #ifndef PROPBILINNEW
10359 /** tries to deduce domain reductions for x in xsqrcoef x^2 + xlincoef x + ysqrcoef y^2 + ylincoef y + bilincoef x y \\in rhs
10360  *
10361  * @note Domain reductions for y are not deduced.
10362  */
10363 static
10365  SCIP* scip, /**< SCIP data structure */
10366  SCIP_CONS* cons, /**< the constraint, where the bilinear term belongs to */
10367  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
10368  SCIP_VAR* x, /**< first variable */
10369  SCIP_Real xsqrcoef, /**< square coefficient of x */
10370  SCIP_Real xlincoef, /**< linear coefficient of x */
10371  SCIP_VAR* y, /**< second variable */
10372  SCIP_Real ysqrcoef, /**< square coefficient of y */
10373  SCIP_Real ylincoef, /**< linear coefficient of y */
10374  SCIP_Real bilincoef, /**< bilinear coefficient of x*y */
10375  SCIP_INTERVAL rhs, /**< right hand side of quadratic equation */
10376  SCIP_RESULT* result, /**< pointer to store result of domain propagation */
10377  int* nchgbds /**< counter to increment if domain reductions are found */
10378  )
10379 {
10380  SCIP_INTERVAL myrhs;
10381  SCIP_INTERVAL varbnds;
10382  SCIP_INTERVAL lincoef;
10383 
10384  assert(scip != NULL);
10385  assert(cons != NULL);
10386  assert(x != NULL);
10387  assert(y != NULL);
10388  assert(x != y);
10389  assert(result != NULL);
10390  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
10391  assert(nchgbds != NULL);
10392  assert(bilincoef != 0.0);
10393 
10394  if( SCIPintervalIsEntire(intervalinfty, rhs) )
10395  return SCIP_OKAY;
10396 
10397  /* try to find domain reductions for x */
10398  SCIPintervalSetBounds(&varbnds, MIN(SCIPvarGetLbLocal(y), SCIPvarGetUbLocal(y)), MAX(SCIPvarGetLbLocal(y), SCIPvarGetUbLocal(y))); /*lint !e666 */
10399 
10400  /* put ysqrcoef*y^2 + ylincoef * y into rhs */
10401  if( SCIPintervalGetSup(rhs) >= intervalinfty )
10402  {
10403  /* if rhs is unbounded by above, it is sufficient to get an upper bound on ysqrcoef*y^2 + ylincoef * y */
10404  SCIP_ROUNDMODE roundmode;
10405  SCIP_Real tmp;
10406 
10407  SCIPintervalSet(&lincoef, ylincoef);
10408  tmp = SCIPintervalQuadUpperBound(intervalinfty, ysqrcoef, lincoef, varbnds);
10409  roundmode = SCIPintervalGetRoundingMode();
10411  SCIPintervalSetBounds(&myrhs, SCIPintervalGetInf(rhs) - tmp, intervalinfty);
10412  SCIPintervalSetRoundingMode(roundmode);
10413  }
10414  else if( SCIPintervalGetInf(rhs) <= -intervalinfty )
10415  {
10416  /* if rhs is unbounded by below, it is sufficient to get a lower bound on ysqrcoef*y^2 + ylincoef * y */
10417  SCIP_ROUNDMODE roundmode;
10418  SCIP_Real tmp;
10419 
10420  SCIPintervalSet(&lincoef, -ylincoef);
10421  tmp = -SCIPintervalQuadUpperBound(intervalinfty, -ysqrcoef, lincoef, varbnds);
10422  roundmode = SCIPintervalGetRoundingMode();
10424  SCIPintervalSetBounds(&myrhs, -intervalinfty, SCIPintervalGetSup(rhs) - tmp);
10425  SCIPintervalSetRoundingMode(roundmode);
10426  }
10427  else
10428  {
10429  /* if rhs is bounded, we need both bounds on ysqrcoef*y^2 + ylincoef * y */
10430  SCIP_INTERVAL tmp;
10431 
10432  SCIPintervalSet(&lincoef, ylincoef);
10433  SCIPintervalQuad(intervalinfty, &tmp, ysqrcoef, lincoef, varbnds);
10434  SCIPintervalSub(intervalinfty, &myrhs, rhs, tmp);
10435  }
10436 
10437  /* create equation xsqrcoef * x^2 + (xlincoef + bilincoef * [ylb, yub]) * x \in myrhs */
10438  SCIPintervalMulScalar(intervalinfty, &lincoef, varbnds, bilincoef);
10439  SCIPintervalAddScalar(intervalinfty, &lincoef, lincoef, xlincoef);
10440 
10441  /* propagate bounds on x */
10442  SCIP_CALL( propagateBoundsQuadVar(scip, cons, intervalinfty, x, xsqrcoef, lincoef, myrhs, result, nchgbds) );
10443 
10444  return SCIP_OKAY;
10445 }
10446 #else
10447 /** tries to deduce domain reductions for x in xsqrcoef x^2 + xlincoef x + ysqrcoef y^2 + ylincoef y + bilincoef x y \\in rhs
10448  *
10449  * @note Domain reductions for y are not deduced.
10450  */
10451 static
10453  SCIP* scip, /**< SCIP data structure */
10454  SCIP_CONS* cons, /**< the constraint, where the bilinear term belongs to */
10455  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
10456  SCIP_VAR* x, /**< first variable */
10457  SCIP_Real xsqrcoef, /**< square coefficient of x */
10458  SCIP_Real xlincoef, /**< linear coefficient of x */
10459  SCIP_VAR* y, /**< second variable */
10460  SCIP_Real ysqrcoef, /**< square coefficient of y */
10461  SCIP_Real ylincoef, /**< linear coefficient of y */
10462  SCIP_Real bilincoef, /**< bilinear coefficient of x*y */
10463  SCIP_INTERVAL rhs, /**< right hand side of quadratic equation */
10464  SCIP_RESULT* result, /**< pointer to store result of domain propagation */
10465  int* nchgbds /**< counter to increment if domain reductions are found */
10466  )
10467 {
10468  SCIP_INTERVAL xbnds;
10469  SCIP_INTERVAL ybnds;
10470 
10471  assert(scip != NULL);
10472  assert(cons != NULL);
10473  assert(x != NULL);
10474  assert(y != NULL);
10475  assert(x != y);
10476  assert(result != NULL);
10477  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
10478  assert(nchgbds != NULL);
10479  assert(bilincoef != 0.0);
10480 
10481  if( SCIPintervalIsEntire(intervalinfty, rhs) )
10482  return SCIP_OKAY;
10483 
10484  SCIPintervalSetBounds(&xbnds,
10485  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(x), SCIPvarGetUbLocal(x))), /*lint !e666*/
10486  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(x), SCIPvarGetUbLocal(x)))); /*lint !e666*/
10487  SCIPintervalSetBounds(&ybnds,
10488  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(y), SCIPvarGetUbLocal(y))), /*lint !e666*/
10489  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(y), SCIPvarGetUbLocal(y)))); /*lint !e666*/
10490 
10491  /* try to find domain reductions for x */
10492  SCIPintervalSolveBivariateQuadExpressionAllScalar(intervalinfty, &xbnds, xsqrcoef, ysqrcoef, bilincoef, xlincoef, ylincoef, rhs, xbnds, ybnds);
10493 
10494  if( SCIPintervalIsEmpty(intervalinfty, xbnds) )
10495  {
10496  SCIPdebugMsg(scip, "found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(x));
10497  *result = SCIP_CUTOFF;
10498  return SCIP_OKAY;
10499  }
10500 
10501  if( !SCIPisInfinity(scip, -SCIPintervalGetInf(xbnds)) )
10502  {
10503  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, x, SCIPintervalGetInf(xbnds), result, nchgbds) );
10504  if( *result == SCIP_CUTOFF )
10505  return SCIP_OKAY;
10506  }
10507 
10508  if( !SCIPisInfinity(scip, SCIPintervalGetSup(xbnds)) )
10509  {
10510  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, x, SCIPintervalGetSup(xbnds), result, nchgbds) );
10511  if( *result == SCIP_CUTOFF )
10512  return SCIP_OKAY;
10513  }
10514 
10515  return SCIP_OKAY;
10516 }
10517 #endif
10518 
10519 /** computes the minimal and maximal activity for the quadratic part in a constraint data
10520  *
10521  * Only sums up terms that contribute finite values.
10522  * Gives the number of terms that contribute infinite values.
10523  * Only computes those activities where the corresponding side of the constraint is finite.
10524  */
10525 static
10527  SCIP* scip, /**< SCIP data structure */
10528  SCIP_CONSDATA* consdata, /**< constraint data */
10529  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
10530  SCIP_Real* minquadactivity, /**< minimal activity of quadratic variable terms where only terms with finite minimal activity contribute */
10531  SCIP_Real* maxquadactivity, /**< maximal activity of quadratic variable terms where only terms with finite maximal activity contribute */
10532  int* minactivityinf, /**< number of quadratic variables that contribute -infinity to minimal activity */
10533  int* maxactivityinf, /**< number of quadratic variables that contribute +infinity to maximal activity */
10534  SCIP_INTERVAL* quadactcontr /**< contribution of each quadratic variables to quadactivity */
10535  )
10536 { /*lint --e{666}*/
10537  SCIP_ROUNDMODE prevroundmode;
10538  int i;
10539  int j;
10540  int k;
10541  SCIP_INTERVAL tmp;
10542  SCIP_Real bnd;
10543  SCIP_INTERVAL xrng;
10544  SCIP_INTERVAL lincoef;
10545 
10546  assert(scip != NULL);
10547  assert(consdata != NULL);
10548  assert(minquadactivity != NULL);
10549  assert(maxquadactivity != NULL);
10550  assert(minactivityinf != NULL);
10551  assert(maxactivityinf != NULL);
10552  assert(quadactcontr != NULL);
10553 
10554  /* if lhs is -infinite, then we do not compute a maximal activity, so we set it to infinity
10555  * if rhs is infinite, then we do not compute a minimal activity, so we set it to -infinity
10556  */
10557  *minquadactivity = SCIPisInfinity(scip, consdata->rhs) ? -intervalinfty : 0.0;
10558  *maxquadactivity = SCIPisInfinity(scip, -consdata->lhs) ? intervalinfty : 0.0;
10559 
10560  *minactivityinf = 0;
10561  *maxactivityinf = 0;
10562 
10563  if( consdata->nquadvars == 0 )
10564  {
10565  SCIPintervalSet(&consdata->quadactivitybounds, 0.0);
10566  return;
10567  }
10568 
10569  for( i = 0; i < consdata->nquadvars; ++i )
10570  {
10571  /* there should be no quadratic variables fixed at -/+ infinity due to our locks */
10572  assert(!SCIPisInfinity(scip, SCIPvarGetLbLocal(consdata->quadvarterms[i].var)));
10573  assert(!SCIPisInfinity(scip, -SCIPvarGetUbLocal(consdata->quadvarterms[i].var)));
10574 
10575  SCIPintervalSetBounds(&quadactcontr[i], -intervalinfty, intervalinfty);
10576 
10577  SCIPintervalSetBounds(&xrng,
10578  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var))),
10579  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var))));
10580 
10581  SCIPintervalSet(&lincoef, consdata->quadvarterms[i].lincoef);
10582  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
10583  {
10584  k = consdata->quadvarterms[i].adjbilin[j];
10585  if( consdata->bilinterms[k].var1 != consdata->quadvarterms[i].var )
10586  continue; /* handle this term later */
10587 
10588  SCIPintervalSetBounds(&tmp,
10589  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
10590  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
10591  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
10592  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
10593  }
10594 
10595  if( !SCIPisInfinity(scip, -consdata->lhs) )
10596  {
10597  /* compute maximal activity only if there is a finite left hand side */
10598  bnd = SCIPintervalQuadUpperBound(intervalinfty, consdata->quadvarterms[i].sqrcoef, lincoef, xrng);
10599  if( bnd >= intervalinfty )
10600  {
10601  ++*maxactivityinf;
10602  }
10603  else if( SCIPisInfinity(scip, -bnd) )
10604  {
10605  /* if maximal activity is below value for -infinity, let's take -1e10 as upper bound on maximal activity
10606  * @todo Something better?
10607  */
10608  bnd = -sqrt(SCIPinfinity(scip));
10609  *maxquadactivity += bnd;
10610  quadactcontr[i].sup = bnd;
10611  }
10612  else
10613  {
10614  prevroundmode = SCIPintervalGetRoundingMode();
10616  *maxquadactivity += bnd;
10617  SCIPintervalSetRoundingMode(prevroundmode);
10618  quadactcontr[i].sup = bnd;
10619  }
10620  }
10621 
10622  if( !SCIPisInfinity(scip, consdata->rhs) )
10623  {
10624  /* compute minimal activity only if there is a finite right hand side */
10625  SCIPintervalSetBounds(&lincoef, -SCIPintervalGetSup(lincoef), -SCIPintervalGetInf(lincoef));
10626  bnd = -SCIPintervalQuadUpperBound(intervalinfty, -consdata->quadvarterms[i].sqrcoef, lincoef, xrng);
10627 
10628  if( bnd <= -intervalinfty )
10629  {
10630  ++*minactivityinf;
10631  }
10632  else if( SCIPisInfinity(scip, bnd) )
10633  {
10634  /* if minimal activity is above value for infinity, let's take 1e10 as lower bound on minimal activity
10635  * @todo Something better?
10636  */
10637  bnd = sqrt(SCIPinfinity(scip));
10638  *minquadactivity += bnd;
10639  quadactcontr[i].inf = bnd;
10640  }
10641  else
10642  {
10643  prevroundmode = SCIPintervalGetRoundingMode();
10645  *minquadactivity += bnd;
10646  SCIPintervalSetRoundingMode(prevroundmode);
10647  quadactcontr[i].inf = bnd;
10648  }
10649  }
10650 
10651  }
10652 
10653  SCIPintervalSetBounds(&consdata->quadactivitybounds,
10654  (*minactivityinf > 0 ? -intervalinfty : *minquadactivity),
10655  (*maxactivityinf > 0 ? intervalinfty : *maxquadactivity));
10656  assert(!SCIPintervalIsEmpty(intervalinfty, consdata->quadactivitybounds));
10657 }
10658 
10659 /** propagates bounds on a quadratic constraint */
10660 static
10662  SCIP* scip, /**< SCIP data structure */
10663  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
10664  SCIP_CONS* cons, /**< constraint to process */
10665  SCIP_RESULT* result, /**< pointer to store the result of the propagation call */
10666  int* nchgbds, /**< buffer where to add the the number of changed bounds */
10667  SCIP_Bool* redundant /**< buffer where to store whether constraint has been found to be redundant */
10668  )
10669 { /*lint --e{666}*/
10670  SCIP_CONSDATA* consdata;
10671  SCIP_INTERVAL consbounds; /* lower and upper bounds of constraint */
10672  SCIP_INTERVAL consactivity; /* activity of linear plus quadratic part */
10673  SCIP_Real intervalinfty; /* infinity used for interval computation */
10674  SCIP_Real minquadactivity; /* lower bound on finite activities of quadratic part */
10675  SCIP_Real maxquadactivity; /* upper bound on finite activities of quadratic part */
10676  int quadminactinf; /* number of quadratic variables that contribute -infinity to minimal activity of quadratic term */
10677  int quadmaxactinf; /* number of quadratic variables that contribute +infinity to maximal activity of quadratic term */
10678  SCIP_INTERVAL* quadactcontr; /* contribution of each quadratic variable term to quadactivity */
10679 
10680  SCIP_VAR* var;
10681  SCIP_INTERVAL rhs; /* right hand side of quadratic equation */
10682  SCIP_INTERVAL tmp;
10683  SCIP_ROUNDMODE roundmode;
10684  SCIP_Real bnd;
10685  int i;
10686 
10687  assert(scip != NULL);
10688  assert(conshdlr != NULL);
10689  assert(cons != NULL);
10690  assert(result != NULL);
10691  assert(nchgbds != NULL);
10692  assert(redundant != NULL);
10693 
10694  consdata = SCIPconsGetData(cons);
10695  assert(consdata != NULL);
10696 
10697  *result = SCIP_DIDNOTRUN;
10698  *redundant = FALSE;
10699 
10700  *result = SCIP_DIDNOTFIND;
10701 
10702  intervalinfty = 1000 * SCIPinfinity(scip) * SCIPinfinity(scip);
10703 
10704  quadactcontr = NULL;
10705  quadminactinf = -1;
10706  quadmaxactinf = -1;
10707 
10708  SCIPdebugMsg(scip, "start domain propagation for constraint <%s>\n", SCIPconsGetName(cons));
10709 
10710  /* make sure we have activity of linear term and that they are consistent */
10711  consdataUpdateLinearActivity(scip, consdata, intervalinfty);
10712  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
10713  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
10714  assert(consdata->minlinactivityinf >= 0);
10715  assert(consdata->maxlinactivityinf >= 0);
10716 
10717  /* sort quadratic variable terms, in case we need to search for terms occuring in bilinear terms later
10718  * we sort here already, since we rely on a constant variable order during this method
10719  */
10720  if( consdata->nbilinterms > 0 )
10721  {
10722  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
10723  }
10724 
10725  /* compute activity of quad term part, if not up to date
10726  * in that case, we also collect the contribution of each quad var term for later */
10727  if( SCIPintervalIsEmpty(intervalinfty, consdata->quadactivitybounds) )
10728  {
10729  SCIP_CALL( SCIPallocBufferArray(scip, &quadactcontr, consdata->nquadvars) );
10730  propagateBoundsGetQuadActivity(scip, consdata, intervalinfty, &minquadactivity, &maxquadactivity, &quadminactinf, &quadmaxactinf, quadactcontr);
10731  assert(!SCIPintervalIsEmpty(intervalinfty, consdata->quadactivitybounds));
10732  }
10733 
10734  SCIPdebugMsg(scip, "linear activity: [%g, %g] quadratic activity: [%g, %g]\n",
10735  (consdata->minlinactivityinf > 0 ? -intervalinfty : consdata->minlinactivity),
10736  (consdata->maxlinactivityinf > 0 ? intervalinfty : consdata->maxlinactivity),
10737  consdata->quadactivitybounds.inf, consdata->quadactivitybounds.sup);
10738 
10739  /* extend constraint bounds by epsilon to avoid some numerical difficulties */
10740  SCIPintervalSetBounds(&consbounds,
10741  -infty2infty(SCIPinfinity(scip), intervalinfty, -consdata->lhs+SCIPepsilon(scip)),
10742  +infty2infty(SCIPinfinity(scip), intervalinfty, consdata->rhs+SCIPepsilon(scip)));
10743 
10744  /* check redundancy and infeasibility */
10745  SCIPintervalSetBounds(&consactivity, consdata->minlinactivityinf > 0 ? -intervalinfty : consdata->minlinactivity,
10746  consdata->maxlinactivityinf > 0 ? intervalinfty : consdata->maxlinactivity);
10747  SCIPintervalAdd(intervalinfty, &consactivity, consactivity, consdata->quadactivitybounds);
10748  if( SCIPintervalIsSubsetEQ(intervalinfty, consactivity, consbounds) )
10749  {
10750  SCIPdebugMsg(scip, "found constraint <%s> to be redundant: sides: [%g, %g], activity: [%g, %g]\n",
10751  SCIPconsGetName(cons), consdata->lhs, consdata->rhs, SCIPintervalGetInf(consactivity), SCIPintervalGetSup(consactivity));
10752  *redundant = TRUE;
10753  goto CLEANUP;
10754  }
10755 
10756  /* was SCIPintervalAreDisjoint(consbounds, consactivity), but that would allow violations up to eps only
10757  * we need to decide feasibility w.r.t. feastol (but still want to propagate w.r.t. eps)
10758  */
10759  if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisGT(scip, consdata->lhs-SCIPfeastol(scip), SCIPintervalGetSup(consactivity))) ||
10760  (!SCIPisInfinity(scip, consdata->rhs) && SCIPisLT(scip, consdata->rhs+SCIPfeastol(scip), SCIPintervalGetInf(consactivity))) )
10761  {
10762  SCIPdebugMsg(scip, "found constraint <%s> to be infeasible; sides: [%g, %g], activity: [%g, %g], infeas: %g\n",
10763  SCIPconsGetName(cons), consdata->lhs, consdata->rhs, SCIPintervalGetInf(consactivity), SCIPintervalGetSup(consactivity),
10764  MAX(consdata->lhs - SCIPintervalGetSup(consactivity), SCIPintervalGetInf(consactivity) - consdata->rhs));
10765  *result = SCIP_CUTOFF;
10766  goto CLEANUP;
10767  }
10768 
10769  /* propagate linear part \in rhs = consbounds - quadactivity (use the one from consdata, since that includes infinities) */
10770  SCIPintervalSub(intervalinfty, &rhs, consbounds, consdata->quadactivitybounds);
10771  if( !SCIPintervalIsEntire(intervalinfty, rhs) )
10772  {
10773  SCIP_Real coef;
10774 
10775  for( i = 0; i < consdata->nlinvars; ++i )
10776  {
10777  coef = consdata->lincoefs[i];
10778  var = consdata->linvars[i];
10779 
10780  /* skip fixed variables
10781  * @todo is that a good or a bad idea?
10782  * we can't expect much more tightening, but may detect infeasiblity, but shouldn't the check on the constraints activity detect that?
10783  */
10784  if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
10785  continue;
10786 
10787  /* due to large variable bounds and large coefficients, it might happen that the activity of the linear part
10788  * exceeds +/-SCIPinfinity() after updating the activities in consdataUpdateLinearActivity{Lb,Ub}Change; in
10789  * order to detect this case we need to check whether the value of consdata->{min,max}linactivity is infinite
10790  * (see #1433)
10791  */
10792  if( coef > 0.0 )
10793  {
10794  if( SCIPintervalGetSup(rhs) < intervalinfty )
10795  {
10796  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
10797  /* try to tighten the upper bound on var x */
10798  if( consdata->minlinactivityinf == 0 && !SCIPisInfinity(scip, -consdata->minlinactivity) )
10799  {
10800  assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
10801  /* tighten upper bound on x to (rhs.sup - (minlinactivity - coef * xlb)) / coef */
10802  roundmode = SCIPintervalGetRoundingMode();
10804  bnd = SCIPintervalGetSup(rhs);
10805  bnd -= consdata->minlinactivity;
10806  bnd += coef * SCIPvarGetLbLocal(var);
10807  bnd /= coef;
10808  SCIPintervalSetRoundingMode(roundmode);
10809  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10810  if( *result == SCIP_CUTOFF )
10811  break;
10812  }
10813  else if( consdata->minlinactivityinf == 1 && SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
10814  {
10815  /* x was the variable that made the minimal linear activity equal -infinity, so
10816  * we tighten upper bound on x to just (rhs.sup - minlinactivity) / coef */
10817  roundmode = SCIPintervalGetRoundingMode();
10819  bnd = SCIPintervalGetSup(rhs);
10820  bnd -= consdata->minlinactivity;
10821  bnd /= coef;
10822  SCIPintervalSetRoundingMode(roundmode);
10823  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10824  if( *result == SCIP_CUTOFF )
10825  break;
10826  }
10827  /* otherwise the minimal activity is -infinity and x is not solely responsible for this */
10828  }
10829 
10830  if( SCIPintervalGetInf(rhs) > -intervalinfty )
10831  {
10832  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
10833  /* try to tighten the lower bound on var x */
10834  if( consdata->maxlinactivityinf == 0 && !SCIPisInfinity(scip, consdata->maxlinactivity) )
10835  {
10836  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
10837  /* tighten lower bound on x to (rhs.inf - (maxlinactivity - coef * xub)) / coef */
10838  roundmode = SCIPintervalGetRoundingMode();
10840  bnd = SCIPintervalGetInf(rhs);
10841  bnd -= consdata->maxlinactivity;
10842  bnd += coef * SCIPvarGetUbLocal(var);
10843  bnd /= coef;
10844  SCIPintervalSetRoundingMode(roundmode);
10845  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10846  if( *result == SCIP_CUTOFF )
10847  break;
10848  }
10849  else if( consdata->maxlinactivityinf == 1 && SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
10850  {
10851  /* x was the variable that made the maximal linear activity equal infinity, so
10852  * we tighten upper bound on x to just (rhs.inf - maxlinactivity) / coef */
10853  roundmode = SCIPintervalGetRoundingMode();
10855  bnd = SCIPintervalGetInf(rhs);
10856  bnd -= consdata->maxlinactivity;
10857  bnd /= coef;
10858  SCIPintervalSetRoundingMode(roundmode);
10859  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10860  if( *result == SCIP_CUTOFF )
10861  break;
10862  }
10863  /* otherwise the maximal activity is +infinity and x is not solely responsible for this */
10864  }
10865  }
10866  else
10867  {
10868  assert(coef < 0.0 );
10869  if( SCIPintervalGetInf(rhs) > -intervalinfty )
10870  {
10871  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
10872  /* try to tighten the upper bound on var x */
10873  if( consdata->maxlinactivityinf == 0 && !SCIPisInfinity(scip, consdata->maxlinactivity) )
10874  {
10875  assert(!SCIPisInfinity(scip, SCIPvarGetLbLocal(var)));
10876  /* compute upper bound on x to (maxlinactivity - coef * xlb) - rhs.inf / (-coef) */
10877  roundmode = SCIPintervalGetRoundingMode();
10879  bnd = consdata->maxlinactivity;
10880  bnd += (-coef) * SCIPvarGetLbLocal(var);
10881  bnd -= SCIPintervalGetInf(rhs);
10882  bnd /= (-coef);
10883  SCIPintervalSetRoundingMode(roundmode);
10884  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10885  if( *result == SCIP_CUTOFF )
10886  break;
10887  }
10888  else if( consdata->maxlinactivityinf == 1 && SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
10889  {
10890  /* x was the variable that made the maximal linear activity equal infinity, so
10891  * we tighten upper bound on x to just (maxlinactivity - rhs.inf) / (-coef) */
10892  roundmode = SCIPintervalGetRoundingMode();
10894  bnd = consdata->maxlinactivity;
10895  bnd -= SCIPintervalGetInf(rhs);
10896  bnd /= (-coef);
10897  SCIPintervalSetRoundingMode(roundmode);
10898  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10899  if( *result == SCIP_CUTOFF )
10900  break;
10901  }
10902  /* otherwise the maximal activity is infinity and x is not solely responsible for this */
10903  }
10904 
10905  if( SCIPintervalGetSup(rhs) < intervalinfty )
10906  {
10907  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
10908  /* try to tighten the lower bound on var x */
10909  if( consdata->minlinactivityinf == 0 && !SCIPisInfinity(scip, -consdata->minlinactivity) )
10910  {
10911  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
10912  /* compute lower bound on x to (minlinactivity - coef * xub) - rhs.sup / (-coef) */
10913  roundmode = SCIPintervalGetRoundingMode();
10915  bnd = consdata->minlinactivity;
10916  bnd += (-coef) * SCIPvarGetUbLocal(var);
10917  bnd -= SCIPintervalGetSup(rhs);
10918  bnd /= (-coef);
10919  SCIPintervalSetRoundingMode(roundmode);
10920  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10921  if( *result == SCIP_CUTOFF )
10922  break;
10923  }
10924  else if( consdata->minlinactivityinf == 1 && SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
10925  {
10926  /* x was the variable that made the maximal linear activity equal -infinity, so
10927  * we tighten lower bound on x to just (minlinactivity - rhs.sup) / (-coef) */
10928  roundmode = SCIPintervalGetRoundingMode();
10930  bnd = consdata->minlinactivity;
10931  bnd -= SCIPintervalGetSup(rhs);
10932  bnd /= (-coef);
10933  SCIPintervalSetRoundingMode(roundmode);
10934  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10935  if( *result == SCIP_CUTOFF )
10936  break;
10937  }
10938  /* otherwise the minimal activity is -infinity and x is not solely responsible for this */
10939  }
10940  }
10941  }
10942  if( *result == SCIP_CUTOFF )
10943  goto CLEANUP;
10944  }
10945 
10946  /* propagate quadratic part \in rhs = consbounds - linactivity */
10947  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
10948  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
10949  consdataUpdateLinearActivity(scip, consdata, intervalinfty); /* make sure, activities of linear part did not become invalid by above bound changes, if any */
10950  assert(consdata->minlinactivityinf > 0 || consdata->maxlinactivityinf > 0 || consdata->minlinactivity <= consdata->maxlinactivity);
10951  SCIPintervalSetBounds(&tmp,
10952  (consdata->minlinactivityinf > 0 ? -intervalinfty : consdata->minlinactivity),
10953  (consdata->maxlinactivityinf > 0 ? intervalinfty : consdata->maxlinactivity));
10954  SCIPintervalSub(intervalinfty, &rhs, consbounds, tmp);
10955  if( !SCIPintervalIsEntire(intervalinfty, rhs) )
10956  {
10957  if( consdata->nquadvars == 1 )
10958  {
10959  /* quadratic part is just a*x^2+b*x -> a common case that we treat directly */
10960  SCIP_INTERVAL lincoef; /* linear coefficient of quadratic equation */
10961 
10962  assert(consdata->nbilinterms == 0);
10963 
10964  var = consdata->quadvarterms[0].var;
10965  SCIPintervalSet(&lincoef, consdata->quadvarterms[0].lincoef);
10966 
10967  /* propagate a*x^2 + b*x \in rhs */
10968  SCIP_CALL( propagateBoundsQuadVar(scip, cons, intervalinfty, var, consdata->quadvarterms[0].sqrcoef, lincoef, rhs, result, nchgbds) );
10969  }
10970  else if( consdata->nbilinterms == 1 && consdata->nquadvars == 2 )
10971  {
10972  /* quadratic part is just ax*x^2+bx*x + ay*y^2+by*y + c*xy -> a common case that we treat directly */
10973  assert(consdata->bilinterms[0].var1 == consdata->quadvarterms[0].var || consdata->bilinterms[0].var1 == consdata->quadvarterms[1].var);
10974  assert(consdata->bilinterms[0].var2 == consdata->quadvarterms[0].var || consdata->bilinterms[0].var2 == consdata->quadvarterms[1].var);
10975 
10976  /* find domain reductions for x from a_x x^2 + b_x x + a_y y^2 + b_y y + c x y \in rhs */
10977  SCIP_CALL( propagateBoundsBilinearTerm(scip, cons, intervalinfty,
10978  consdata->quadvarterms[0].var, consdata->quadvarterms[0].sqrcoef, consdata->quadvarterms[0].lincoef,
10979  consdata->quadvarterms[1].var, consdata->quadvarterms[1].sqrcoef, consdata->quadvarterms[1].lincoef,
10980  consdata->bilinterms[0].coef,
10981  rhs, result, nchgbds) );
10982  if( *result != SCIP_CUTOFF )
10983  {
10984  /* find domain reductions for y from a_x x^2 + b_x x + a_y y^2 + b_y y + c x y \in rhs */
10985  SCIP_CALL( propagateBoundsBilinearTerm(scip, cons, intervalinfty,
10986  consdata->quadvarterms[1].var, consdata->quadvarterms[1].sqrcoef, consdata->quadvarterms[1].lincoef,
10987  consdata->quadvarterms[0].var, consdata->quadvarterms[0].sqrcoef, consdata->quadvarterms[0].lincoef,
10988  consdata->bilinterms[0].coef,
10989  rhs, result, nchgbds) );
10990  }
10991  }
10992  else
10993  {
10994  /* general case */
10995 
10996  /* compute "advanced" information on quad var term activities, if not up-to-date */
10997  if( quadminactinf == -1 )
10998  {
10999  assert(quadactcontr == NULL);
11000  SCIP_CALL( SCIPallocBufferArray(scip, &quadactcontr, consdata->nquadvars) );
11001  propagateBoundsGetQuadActivity(scip, consdata, intervalinfty, &minquadactivity, &maxquadactivity, &quadminactinf, &quadmaxactinf, quadactcontr);
11002  }
11003  assert(quadactcontr != NULL);
11004  assert(quadminactinf >= 0);
11005  assert(quadmaxactinf >= 0);
11006 
11007  /* if the quad activities are not hopelessly unbounded on useful sides, try to deduce domain reductions on quad vars */
11008  if( (SCIPintervalGetSup(rhs) < intervalinfty && quadminactinf <= 1) ||
11009  ( SCIPintervalGetInf(rhs) > -intervalinfty && quadmaxactinf <= 1) )
11010  {
11011  SCIP_INTERVAL lincoef;
11012  SCIP_INTERVAL rhs2;
11013  int j;
11014  int k;
11015 
11016  for( i = 0; i < consdata->nquadvars; ++i )
11017  {
11018  var = consdata->quadvarterms[i].var;
11019 
11020  /* skip fixed variables
11021  * @todo is that a good or a bad idea?
11022  * we can't expect much more tightening, but may detect infeasiblity, but shouldn't the check on the constraints activity detect that?
11023  */
11024  if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
11025  continue;
11026 
11027  /* compute rhs2 such that we can propagate quadvarterm(x_i) \in rhs2 */
11028 
11029  /* setup rhs2.sup = rhs.sup - (quadactivity.inf - quadactcontr[i].inf), if everything were finite
11030  * if only quadactcontr[i].inf is infinite (i.e., the other i are all finite), we just get rhs2.sup = rhs.sup
11031  * otherwise we get rhs2.sup = infinity */
11032  if( SCIPintervalGetSup(rhs) < intervalinfty )
11033  {
11034  if( quadminactinf == 0 || (quadminactinf == 1 && SCIPintervalGetInf(quadactcontr[i]) <= -intervalinfty) )
11035  {
11036  roundmode = SCIPintervalGetRoundingMode();
11038  rhs2.sup = rhs.sup - minquadactivity; /*lint !e644*/
11039  /* if the residual quad min activity w.r.t. quad var term i is finite and nonzero, so add it to right hand side */
11040  if( quadminactinf == 0 && SCIPintervalGetInf(quadactcontr[i]) != 0.0 )
11041  rhs2.sup += SCIPintervalGetInf(quadactcontr[i]);
11042  SCIPintervalSetRoundingMode(roundmode);
11043  }
11044  else
11045  {
11046  /* there are either >= 2 quad var terms contributing -infinity, or there is one which is not i */
11047  rhs2.sup = intervalinfty;
11048  }
11049  }
11050  else
11051  {
11052  rhs2.sup = intervalinfty;
11053  }
11054 
11055  /* setup rhs2.inf = rhs.inf - (quadactivity.sup - quadactcontr[i].sup), see also above */
11056  if( SCIPintervalGetInf(rhs) > -intervalinfty )
11057  {
11058  if( quadmaxactinf == 0 || (quadmaxactinf == 1 && SCIPintervalGetSup(quadactcontr[i]) >= intervalinfty) )
11059  {
11060  roundmode = SCIPintervalGetRoundingMode();
11062  rhs2.inf = rhs.inf - maxquadactivity; /*lint !e644*/
11063  /* if the residual quad max activity w.r.t. quad var term i is finite and nonzero, so add it to right hand side */
11064  if( quadmaxactinf == 0 && SCIPintervalGetSup(quadactcontr[i]) != 0.0 )
11065  rhs2.inf += SCIPintervalGetSup(quadactcontr[i]);
11066  SCIPintervalSetRoundingMode(roundmode);
11067  }
11068  else
11069  {
11070  /* there are either >= 2 quad var terms contributing infinity, or there is one which is not i */
11071  rhs2.inf = -intervalinfty;
11072  }
11073  }
11074  else
11075  {
11076  rhs2.inf = -intervalinfty;
11077  }
11078  assert(!SCIPintervalIsEmpty(intervalinfty, rhs2));
11079 
11080  /* if rhs2 is entire, then there is nothing we could propagate */
11081  if( SCIPintervalIsEntire(intervalinfty, rhs2) )
11082  continue;
11083 
11084  /* assemble linear coefficient for quad equation a*x^2 + b*x \in rhs2 */
11085  SCIPintervalSet(&lincoef, consdata->quadvarterms[i].lincoef);
11086  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
11087  {
11088  k = consdata->quadvarterms[i].adjbilin[j];
11089 #if 1
11090  if( consdata->bilinterms[k].var1 == var )
11091  {
11092  /* bilinear term k contributes to the activity of quad var term i, so just add bounds to linear coef */
11093  SCIPintervalSetBounds(&tmp,
11094  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
11095  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
11096  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
11097  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
11098  }
11099  else
11100  {
11101  /* bilinear term k does not contribute to the activity of quad var term i
11102  * so bounds on term k are contained in rhs2
11103  * if they are finite, we try to remove them from rhs2 and update lincoef instead
11104  * if the bounds on bilinear term k as added to rhs2 are old due to recent bound tightening, we may not do best possible, but still correct
11105  * HOWEVER: when computing rhs2, we may not just have added the bounds for the bilinear term, but for the associated quadratic term
11106  * for this complete term, we used SCIPintervalQuad to compute the bounds
11107  * since we do not want to repeat a call to SCIPintervalQuad for that quadratic term with bilinear term k removed,
11108  * we only remove the bounds for the bilinear term k from rhs2 if the associated quadratic term consists only of this bilinear term,
11109  * i.e., the quadratic term corresponding to var1 should be only var1*var2, but have no square or linear coefs or other bilinear terms
11110  * (for efficiency reasons, we check here only if there are any other bilinear terms than var1*var2 associated with var1, even if they are not associated with the quad var term for var1)
11111  */
11112  SCIP_INTERVAL me;
11113  SCIP_INTERVAL bilinbounds;
11114  int otherpos;
11115 
11116  assert(consdata->bilinterms[k].var2 == var);
11117 
11118  assert(consdata->quadvarssorted);
11119  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->bilinterms[k].var1, &otherpos) );
11120  assert(otherpos >= 0);
11121  assert(consdata->quadvarterms[otherpos].var == consdata->bilinterms[k].var1);
11122 
11123  if( (consdata->quadvarterms[otherpos].sqrcoef != 0.0) || consdata->quadvarterms[otherpos].lincoef != 0.0 ||
11124  consdata->quadvarterms[otherpos].nadjbilin > 1 )
11125  continue;
11126 
11127  /* set tmp to bounds of other variable and multiply with bilin coef */
11128  SCIPintervalSetBounds(&tmp,
11129  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var1), SCIPvarGetUbLocal(consdata->bilinterms[k].var1))),
11130  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var1), SCIPvarGetUbLocal(consdata->bilinterms[k].var1))));
11131  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
11132 
11133  /* set me to bounds of i'th variable */
11135  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
11136  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
11137 
11138  /* remove me*tmp from rhs2 */
11139 
11140  roundmode = SCIPintervalGetRoundingMode();
11141 
11142  if( rhs2.inf > -intervalinfty )
11143  {
11144  /* need upward rounding for SCIPintervalMulSup */
11146  SCIPintervalMulSup(intervalinfty, &bilinbounds, me, tmp);
11147  /* rhs2.inf += bilinbounds.sup, but we are in upward rounding */
11148  if( bilinbounds.sup < intervalinfty )
11149  rhs2.inf = SCIPintervalNegateReal(SCIPintervalNegateReal(rhs2.inf) - bilinbounds.sup);
11150  }
11151 
11152  if( rhs2.sup < intervalinfty )
11153  {
11154  /* need downward rounding for SCIPintervalMulInf */
11156  SCIPintervalMulInf(intervalinfty, &bilinbounds, me, tmp);
11157  /* rhs2.sup += bilinbounds.inf, but we are in downward rounding */
11158  if( bilinbounds.inf > -intervalinfty )
11159  rhs2.sup = SCIPintervalNegateReal(SCIPintervalNegateReal(rhs2.sup) - bilinbounds.inf);
11160  }
11161 
11162  SCIPintervalSetRoundingMode(roundmode);
11163 
11164  /* add tmp to lincoef */
11165  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
11166  }
11167 #else
11168  if( consdata->bilinterms[k].var1 != var )
11169  continue; /* this term does not contribute to the activity of quad var term i */
11170 
11171  SCIPintervalSetBounds(&tmp,
11172  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
11173  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
11174  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
11175  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
11176 #endif
11177  }
11178 
11179  /* deduce domain reductions for x_i */
11180  SCIP_CALL( propagateBoundsQuadVar(scip, cons, intervalinfty, var, consdata->quadvarterms[i].sqrcoef, lincoef, rhs2, result, nchgbds) );
11181  if( *result == SCIP_CUTOFF )
11182  goto CLEANUP;
11183  }
11184  }
11185  }
11186  }
11187 
11188  CLEANUP:
11189  SCIPfreeBufferArrayNull(scip, &quadactcontr);
11190 
11191  return SCIP_OKAY;
11192 }
11193 
11194 /** calls domain propagation for a set of constraints */
11195 static
11197  SCIP* scip, /**< SCIP data structure */
11198  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11199  SCIP_CONS** conss, /**< constraints to process */
11200  int nconss, /**< number of constraints */
11201  SCIP_RESULT* result, /**< pointer to store the result of the propagation calls */
11202  int* nchgbds /**< buffer where to add the the number of changed bounds */
11203  )
11204 {
11205  SCIP_CONSHDLRDATA* conshdlrdata;
11206  SCIP_RESULT propresult;
11207  SCIP_Bool redundant;
11208  int c;
11209  int roundnr;
11210  SCIP_Bool success;
11211  int maxproprounds;
11212 
11213  assert(scip != NULL);
11214  assert(conshdlr != NULL);
11215  assert(conss != NULL || nconss == 0);
11216  assert(result != NULL);
11217  assert(nchgbds != NULL);
11218 
11220 
11221  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11222  assert(conshdlrdata != NULL);
11223 
11224  *result = SCIP_DIDNOTFIND;
11225  roundnr = 0;
11226  if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING )
11227  maxproprounds = conshdlrdata->maxproproundspresolve;
11228  else
11229  maxproprounds = conshdlrdata->maxproprounds;
11230 
11231  do
11232  {
11233  success = FALSE;
11234  ++roundnr;
11235 
11236  SCIPdebugMsg(scip, "starting domain propagation round %d of %d for %d constraints\n", roundnr, maxproprounds, nconss);
11237 
11238  for( c = 0; c < nconss && *result != SCIP_CUTOFF; ++c )
11239  {
11240  assert(conss != NULL);
11241  if( !SCIPconsIsEnabled(conss[c]) )
11242  continue;
11243 
11244  if( SCIPconsIsMarkedPropagate(conss[c]) )
11245  {
11246  /* unmark constraint for propagation */
11247  SCIP_CALL( SCIPunmarkConsPropagate(scip, conss[c]) );
11248 
11249  SCIP_CALL( propagateBoundsCons(scip, conshdlr, conss[c], &propresult, nchgbds, &redundant) );
11250  if( propresult != SCIP_DIDNOTFIND && propresult != SCIP_DIDNOTRUN )
11251  {
11252  *result = propresult;
11253  success = TRUE;
11254  }
11255  if( redundant )
11256  {
11257  SCIPdebugMsg(scip, "deleting constraint <%s> locally\n", SCIPconsGetName(conss[c]));
11258  SCIP_CALL( SCIPdelConsLocal(scip, conss[c]) );
11259  }
11260  }
11261  }
11262 
11263  }
11264  while( success && *result != SCIP_CUTOFF && roundnr < maxproprounds );
11265 
11266  return SCIP_OKAY;
11267 }
11268 
11269 /** checks for a linear variable that can be increase or decreased without harming feasibility */
11270 static
11272  SCIP* scip, /**< SCIP data structure */
11273  SCIP_CONSDATA* consdata /**< constraint data */
11274  )
11275 {
11276  int i;
11277  int poslock;
11278  int neglock;
11279 
11280  consdata->linvar_maydecrease = -1;
11281  consdata->linvar_mayincrease = -1;
11282 
11283  /* check for a linear variable that can be increase or decreased without harming feasibility */
11284  for( i = 0; i < consdata->nlinvars; ++i )
11285  {
11286  /* compute locks of i'th linear variable */
11287  assert(consdata->lincoefs[i] != 0.0);
11288  if( consdata->lincoefs[i] > 0.0 )
11289  {
11290  poslock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
11291  neglock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
11292  }
11293  else
11294  {
11295  poslock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
11296  neglock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
11297  }
11298 
11299  if( SCIPvarGetNLocksDown(consdata->linvars[i]) - neglock == 0 )
11300  {
11301  /* for a*x + q(y) \in [lhs, rhs], we can decrease x without harming other constraints */
11302  /* if we have already one candidate, then take the one where the loss in the objective function is less */
11303  if( (consdata->linvar_maydecrease < 0) ||
11304  (SCIPvarGetObj(consdata->linvars[consdata->linvar_maydecrease]) / consdata->lincoefs[consdata->linvar_maydecrease] > SCIPvarGetObj(consdata->linvars[i]) / consdata->lincoefs[i]) )
11305  consdata->linvar_maydecrease = i;
11306  }
11307 
11308  if( SCIPvarGetNLocksDown(consdata->linvars[i]) - poslock == 0 )
11309  {
11310  /* for a*x + q(y) \in [lhs, rhs], we can increase x without harm */
11311  /* if we have already one candidate, then take the one where the loss in the objective function is less */
11312  if( (consdata->linvar_mayincrease < 0) ||
11313  (SCIPvarGetObj(consdata->linvars[consdata->linvar_mayincrease]) / consdata->lincoefs[consdata->linvar_mayincrease] > SCIPvarGetObj(consdata->linvars[i]) / consdata->lincoefs[i]) )
11314  consdata->linvar_mayincrease = i;
11315  }
11316  }
11317 
11318 #ifdef SCIP_DEBUG
11319  if( consdata->linvar_mayincrease >= 0 )
11320  {
11321  SCIPdebugMsg(scip, "may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvars[consdata->linvar_mayincrease]));
11322  }
11323  if( consdata->linvar_maydecrease >= 0 )
11324  {
11325  SCIPdebugMsg(scip, "may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvars[consdata->linvar_maydecrease]));
11326  }
11327 #endif
11328 }
11329 
11330 /** Given a solution where every quadratic constraint is either feasible or can be made feasible by
11331  * moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
11332  *
11333  * The method assumes that this is always possible and that not all constraints are feasible already.
11334  */
11335 static
11337  SCIP* scip, /**< SCIP data structure */
11338  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11339  SCIP_CONS** conss, /**< constraints to process */
11340  int nconss, /**< number of constraints */
11341  SCIP_SOL* sol, /**< solution to process */
11342  SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
11343  )
11344 {
11345  SCIP_CONSHDLRDATA* conshdlrdata;
11346  SCIP_CONSDATA* consdata;
11347  SCIP_SOL* newsol;
11348  SCIP_VAR* var;
11349  int c;
11350  SCIP_Real viol;
11351  SCIP_Real delta;
11352  SCIP_Real gap;
11353  SCIP_Bool solviolbounds;
11354 
11355  assert(scip != NULL);
11356  assert(conshdlr != NULL);
11357  assert(conss != NULL || nconss == 0);
11358  assert(success != NULL);
11359 
11360  *success = FALSE;
11361 
11362  /* don't propose new solutions if not in presolve or solving */
11364  return SCIP_OKAY;
11365 
11366  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11367  assert(conshdlrdata != NULL);
11368 
11369  if( sol != NULL )
11370  {
11371  SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
11372  }
11373  else
11374  {
11375  SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
11376  }
11377  SCIP_CALL( SCIPunlinkSol(scip, newsol) );
11378  SCIPdebugMsg(scip, "attempt to make solution from <%s> feasible by shifting linear variable\n",
11379  sol != NULL ? (SCIPsolGetHeur(sol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(sol)) : "tree") : "LP");
11380 
11381  for( c = 0; c < nconss; ++c )
11382  {
11383  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
11384  assert(consdata != NULL);
11385 
11386  /* recompute violation of solution in case solution has changed
11387  * get absolution violation and sign
11388  * @todo do this only if solution has changed
11389  */
11390  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
11391  {
11392  SCIP_CALL( computeViolation(scip, conss[c], newsol, &solviolbounds) ); /*lint !e613*/
11393  assert(!solviolbounds);
11394  viol = consdata->lhs - consdata->activity;
11395  }
11396  else if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
11397  {
11398  SCIP_CALL( computeViolation(scip, conss[c], newsol, &solviolbounds) ); /*lint !e613*/
11399  assert(!solviolbounds);
11400  viol = consdata->rhs - consdata->activity;
11401  }
11402  else
11403  continue; /* constraint is satisfied */
11404 
11405  assert(viol != 0.0);
11406  if( consdata->linvar_mayincrease >= 0 &&
11407  ((viol > 0.0 && consdata->lincoefs[consdata->linvar_mayincrease] > 0.0) || (viol < 0.0 && consdata->lincoefs[consdata->linvar_mayincrease] < 0.0)) )
11408  {
11409  /* have variable where increasing makes the constraint less violated */
11410  var = consdata->linvars[consdata->linvar_mayincrease];
11411  /* compute how much we would like to increase var */
11412  delta = viol / consdata->lincoefs[consdata->linvar_mayincrease];
11413  assert(delta > 0.0);
11414  /* if var has an upper bound, may need to reduce delta */
11415  if( !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
11416  {
11417  gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
11418  delta = MIN(MAX(0.0, gap), delta);
11419  }
11420  if( SCIPisPositive(scip, delta) )
11421  {
11422  /* if variable is integral, round delta up so that it will still have an integer value */
11423  if( SCIPvarIsIntegral(var) )
11424  delta = SCIPceil(scip, delta);
11425 
11426  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
11427  /*lint --e{613} */
11428  SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy lhs-violation %g of cons <%s>\n", SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c]));
11429 
11430  /* adjust constraint violation, if satisfied go on to next constraint */
11431  viol -= consdata->lincoefs[consdata->linvar_mayincrease] * delta;
11432  if( SCIPisZero(scip, viol) )
11433  continue;
11434  }
11435  }
11436 
11437  assert(viol != 0.0);
11438  if( consdata->linvar_maydecrease >= 0 &&
11439  ((viol > 0.0 && consdata->lincoefs[consdata->linvar_maydecrease] < 0.0) || (viol < 0.0 && consdata->lincoefs[consdata->linvar_maydecrease] > 0.0)) )
11440  {
11441  /* have variable where decreasing makes constraint less violated */
11442  var = consdata->linvars[consdata->linvar_maydecrease];
11443  /* compute how much we would like to decrease var */
11444  delta = viol / consdata->lincoefs[consdata->linvar_maydecrease];
11445  assert(delta < 0.0);
11446  /* if var has a lower bound, may need to reduce delta */
11447  if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) )
11448  {
11449  gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
11450  delta = MAX(MIN(0.0, gap), delta);
11451  }
11452  if( SCIPisNegative(scip, delta) )
11453  {
11454  /* if variable is integral, round delta down so that it will still have an integer value */
11455  if( SCIPvarIsIntegral(var) )
11456  delta = SCIPfloor(scip, delta);
11457  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
11458  /*lint --e{613} */
11459  SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy rhs-violation %g of cons <%s>\n", SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c]));
11460 
11461  /* adjust constraint violation, if satisfied go on to next constraint */
11462  viol -= consdata->lincoefs[consdata->linvar_maydecrease] * delta;
11463  if( SCIPisZero(scip, viol) )
11464  continue;
11465  }
11466  }
11467 
11468  /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
11469  break;
11470  }
11471 
11472  /* if we have a solution that should satisfy all quadratic constraints and has a better objective than the current upper bound,
11473  * then pass it to the trysol heuristic
11474  */
11475  if( c == nconss && (SCIPisInfinity(scip, SCIPgetUpperbound(scip)) || SCIPisSumLT(scip, SCIPgetSolTransObj(scip, newsol), SCIPgetUpperbound(scip))) )
11476  {
11477  SCIPdebugMsg(scip, "pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
11478 
11479  assert(conshdlrdata->trysolheur != NULL);
11480  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
11481 
11482  *success = TRUE;
11483  }
11484 
11485  SCIP_CALL( SCIPfreeSol(scip, &newsol) );
11486 
11487  return SCIP_OKAY;
11488 }
11489 
11490 /** helper function to enforce constraints */
11491 static
11493  SCIP* scip, /**< SCIP data structure */
11494  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11495  SCIP_CONS** conss, /**< constraints to process */
11496  int nconss, /**< number of constraints */
11497  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
11498  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
11499  SCIP_Bool solinfeasible, /**< was the solution already declared infeasible by a constraint handler? */
11500  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
11501  )
11502 {
11503  SCIP_CONSHDLRDATA* conshdlrdata;
11504  SCIP_CONSDATA* consdata;
11505  SCIP_CONS* maxviolcon;
11506  SCIP_Real maxviol;
11507  SCIP_RESULT propresult;
11508  SCIP_RESULT separateresult;
11509  int nchgbds;
11510  int nnotify;
11511  SCIP_Real sepaefficacy;
11512  SCIP_Bool solviolbounds;
11513 
11514  assert(scip != NULL);
11515  assert(conshdlr != NULL);
11516  assert(conss != NULL || nconss == 0);
11517  assert(nconss >= 0);
11518  assert(nusefulconss >= 0);
11519  assert(result != NULL);
11520 
11521  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11522  assert(conshdlrdata != NULL);
11523 
11524  SCIP_CALL( computeViolations(scip, conss, nconss, sol, &solviolbounds, &maxviolcon) );
11525 
11526  if( maxviolcon == NULL )
11527  {
11528  *result = SCIP_FEASIBLE;
11529  return SCIP_OKAY;
11530  }
11531 
11532  *result = SCIP_INFEASIBLE;
11533 
11534  if( solviolbounds )
11535  {
11536  /* if LP solution violates variable bounds, then this should be because a row was added that
11537  * introduced this variable newly to the LP, in which case it gets value 0.0; the row should
11538  * have been added to resolve an infeasibility, so solinfeasible should be TRUE
11539  * see also issue #627
11540  */
11541  assert(solinfeasible);
11542  /* however, if solinfeasible is actually not TRUE, then better cut off the node to avoid that SCIP
11543  * stops because infeasible cannot be resolved */
11544  /*lint --e{774} */
11545  if( !solinfeasible )
11546  *result = SCIP_CUTOFF;
11547  return SCIP_OKAY;
11548  }
11549 
11550  consdata = SCIPconsGetData(maxviolcon);
11551  assert(consdata != NULL);
11552  maxviol = consdata->lhsviol + consdata->rhsviol;
11553  assert(SCIPisGT(scip, maxviol, SCIPfeastol(scip)));
11554 
11555  SCIPdebugMsg(scip, "enforcement with max violation %g in cons <%s> for %s solution\n", maxviol, SCIPconsGetName(maxviolcon),
11556  sol == NULL ? "LP" : "relaxation");
11557 
11558  /* if we are above the 100'th enforcement round for this node, something is strange
11559  * (maybe the LP / relaxator does not think that the cuts we add are violated, or we do ECP on a high-dimensional convex function)
11560  * in this case, check if some limit is hit or SCIP should stop for some other reason and terminate enforcement by creating a dummy node
11561  * (in optimized more, returning SCIP_INFEASIBLE in *result would be sufficient, but in debug mode this would give an assert in scip.c)
11562  * the reason to wait for 100 rounds is to avoid calls to SCIPisStopped in normal runs, which may be expensive
11563  * we only increment nenforounds until 101 to avoid an overflow
11564  */
11565  if( conshdlrdata->lastenfonode == SCIPgetCurrentNode(scip) )
11566  {
11567  if( conshdlrdata->nenforounds > 100 )
11568  {
11569  if( SCIPisStopped(scip) )
11570  {
11571  SCIP_NODE* child;
11572 
11573  SCIP_CALL( SCIPcreateChild(scip, &child, 1.0, SCIPnodeGetEstimate(SCIPgetCurrentNode(scip))) );
11574  *result = SCIP_BRANCHED;
11575 
11576  return SCIP_OKAY;
11577  }
11578  }
11579 
11580  ++conshdlrdata->nenforounds;
11581 
11582  /* cut off the current subtree, if a limit on the enforcement rounds should be applied. At this point, feasible
11583  * solutions might get cut off; the enfolplimit parameter should therefore only be set if SCIP is used as a
11584  * heuristic solver and when the returned result (infeasible, optimal, the gap) can be ignored
11585  */
11586  if( conshdlrdata->enfolplimit != -1 && conshdlrdata->nenforounds > conshdlrdata->enfolplimit )
11587  {
11589  "cut off subtree because enforcement limit was reached; this might lead to incorrect results\n");
11590  *result = SCIP_CUTOFF;
11591  return SCIP_OKAY;
11592  }
11593  }
11594  else
11595  {
11596  conshdlrdata->lastenfonode = SCIPgetCurrentNode(scip);
11597  conshdlrdata->nenforounds = 0;
11598  }
11599 
11600  /* run domain propagation */
11601  nchgbds = 0;
11602  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, &propresult, &nchgbds) );
11603  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
11604  {
11605  SCIPdebugMsg(scip, "propagation succeeded (%s)\n", propresult == SCIP_CUTOFF ? "cutoff" : "reduceddom");
11606  *result = propresult;
11607  return SCIP_OKAY;
11608  }
11609 
11610  /* we would like a cut that is efficient enough that it is not redundant in the LP (>lpfeastol)
11611  * however, we also don't want very weak cuts, so try to reach at least feastol (=lpfeastol by default, though)
11612  */
11613  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, SCIPfeastol(scip), TRUE, &separateresult, &sepaefficacy) );
11614  if( separateresult == SCIP_CUTOFF )
11615  {
11616  SCIPdebugMsg(scip, "separation found cutoff\n");
11617  *result = SCIP_CUTOFF;
11618  return SCIP_OKAY;
11619  }
11620  if( separateresult == SCIP_SEPARATED )
11621  {
11622  SCIPdebugMsg(scip, "separation succeeded (bestefficacy = %g, minefficacy = %g)\n", sepaefficacy, SCIPfeastol(scip));
11623  *result = SCIP_SEPARATED;
11624  return SCIP_OKAY;
11625  }
11626 
11627  /* we are not feasible, the whole node is not infeasible, and we cannot find a good cut
11628  * -> collect variables for branching
11629  */
11630 
11631  SCIPdebugMsg(scip, "separation failed (bestefficacy = %g < %g = minefficacy ); max viol: %g\n", sepaefficacy, SCIPfeastol(scip), maxviol);
11632 
11633  /* find branching candidates */
11634  SCIP_CALL( registerBranchingCandidates(scip, conshdlr, conss, nconss, sol, &nnotify) );
11635 
11636  if( nnotify == 0 && !solinfeasible && SCIPfeastol(scip) > SCIPlpfeastol(scip) )
11637  {
11638  /* fallback 1: we also have no branching candidates, so try to find a weak cut */
11639  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, SCIPlpfeastol(scip), TRUE, &separateresult, &sepaefficacy) );
11640  if( separateresult == SCIP_CUTOFF )
11641  {
11642  SCIPdebugMsg(scip, "separation found cutoff\n");
11643  *result = SCIP_CUTOFF;
11644  return SCIP_OKAY;
11645  }
11646  if( separateresult == SCIP_SEPARATED )
11647  {
11648  SCIPdebugMsg(scip, "separation fallback succeeded, efficacy = %g\n", sepaefficacy);
11649  *result = SCIP_SEPARATED;
11650  return SCIP_OKAY;
11651  }
11652  }
11653 
11654  if( nnotify == 0 && !solinfeasible )
11655  {
11656  /* fallback 2: separation probably failed because of numerical difficulties with a convex constraint;
11657  * if noone declared solution infeasible yet and we had not even found a weak cut, try to resolve by branching
11658  */
11659  SCIP_VAR* brvar = NULL;
11660  SCIP_CALL( registerLargeRelaxValueVariableForBranching(scip, conss, nconss, sol, &brvar) );
11661  if( brvar == NULL )
11662  {
11663  /* fallback 3: all quadratic variables seem to be fixed -> replace by linear constraint */
11664  SCIP_Bool addedcons;
11665  SCIP_Bool reduceddom;
11666  SCIP_Bool infeasible;
11667 
11668  SCIP_CALL( replaceByLinearConstraints(scip, conss, nconss, &addedcons, &reduceddom, &infeasible) );
11669  /* if the linear constraints are actually feasible, then adding them and returning SCIP_CONSADDED confuses SCIP
11670  * when it enforces the new constraints again and nothing resolves the infeasibility that we declare here
11671  * thus, we only add them if considered violated, and otherwise claim the solution is feasible (but print a
11672  * warning) */
11673  if ( infeasible )
11674  *result = SCIP_CUTOFF;
11675  else if ( addedcons )
11676  *result = SCIP_CONSADDED;
11677  else if ( reduceddom )
11678  *result = SCIP_REDUCEDDOM;
11679  else
11680  {
11681  *result = SCIP_FEASIBLE;
11682  SCIPwarningMessage(scip, "could not enforce feasibility by separating or branching; declaring solution with viol %g as feasible\n", maxviol);
11683  assert(!SCIPisInfinity(scip, maxviol));
11684  }
11685  return SCIP_OKAY;
11686  }
11687  else
11688  {
11689  SCIPdebugMsg(scip, "Could not find any usual branching variable candidate. Proposed variable <%s> with LP value %g for branching.\n",
11690  SCIPvarGetName(brvar), SCIPgetSolVal(scip, sol, brvar));
11691  nnotify = 1;
11692  }
11693  }
11694 
11695  assert(*result == SCIP_INFEASIBLE && (solinfeasible || nnotify > 0));
11696  return SCIP_OKAY;
11697 }
11698 
11699 /** tries to upgrade a nonlinear constraint into a quadratic constraint */
11700 static
11701 SCIP_DECL_NONLINCONSUPGD(nonlinconsUpgdQuadratic)
11703  SCIP_EXPRGRAPH* exprgraph;
11704  SCIP_EXPRGRAPHNODE* node;
11705  int i;
11706 
11707  assert(nupgdconss != NULL);
11708  assert(upgdconss != NULL);
11709 
11710  *nupgdconss = 0;
11711 
11712  node = SCIPgetExprgraphNodeNonlinear(scip, cons);
11713 
11714  /* no interest in linear constraints */
11715  if( node == NULL )
11716  return SCIP_OKAY;
11717 
11718  /* if a quadratic expression has been simplified, then all children of the node should be variables */
11720  return SCIP_OKAY;
11721 
11722  switch( SCIPexprgraphGetNodeOperator(node) )
11723  {
11724  case SCIP_EXPR_VARIDX:
11725  case SCIP_EXPR_CONST:
11726  case SCIP_EXPR_PLUS:
11727  case SCIP_EXPR_MINUS:
11728  case SCIP_EXPR_SUM:
11729  case SCIP_EXPR_LINEAR:
11730  /* these should not appear as exprgraphnodes after constraint presolving */
11731  return SCIP_OKAY;
11732 
11733  case SCIP_EXPR_DIV:
11734  case SCIP_EXPR_SQRT:
11735  case SCIP_EXPR_REALPOWER:
11736  case SCIP_EXPR_INTPOWER:
11737  case SCIP_EXPR_SIGNPOWER:
11738  case SCIP_EXPR_EXP:
11739  case SCIP_EXPR_LOG:
11740  case SCIP_EXPR_SIN:
11741  case SCIP_EXPR_COS:
11742  case SCIP_EXPR_TAN:
11743  /* case SCIP_EXPR_ERF: */
11744  /* case SCIP_EXPR_ERFI: */
11745  case SCIP_EXPR_MIN:
11746  case SCIP_EXPR_MAX:
11747  case SCIP_EXPR_ABS:
11748  case SCIP_EXPR_SIGN:
11749  case SCIP_EXPR_PRODUCT:
11750  case SCIP_EXPR_POLYNOMIAL:
11751  case SCIP_EXPR_USER:
11752  /* these do not look like an quadratic expression (assuming the expression graph simplifier did run) */
11753  return SCIP_OKAY;
11754 
11755  case SCIP_EXPR_MUL:
11756  case SCIP_EXPR_SQUARE:
11757  case SCIP_EXPR_QUADRATIC:
11758  /* these mean that we have something quadratic */
11759  break;
11760 
11761  case SCIP_EXPR_PARAM:
11762  case SCIP_EXPR_LAST:
11763  default:
11764  SCIPwarningMessage(scip, "unexpected expression operator %d in nonlinear constraint <%s>\n", SCIPexprgraphGetNodeOperator(node), SCIPconsGetName(cons));
11765  return SCIP_OKAY;
11766  }
11767 
11768  /* setup a quadratic constraint */
11769 
11770  if( upgdconsssize < 1 )
11771  {
11772  /* request larger upgdconss array */
11773  *nupgdconss = -1;
11774  return SCIP_OKAY;
11775  }
11776 
11777  *nupgdconss = 1;
11778  SCIP_CALL( SCIPcreateConsQuadratic(scip, &upgdconss[0], SCIPconsGetName(cons),
11780  0, NULL, 0, NULL,
11781  SCIPgetLhsNonlinear(scip, cons), SCIPgetRhsNonlinear(scip, cons),
11785  assert(!SCIPconsIsStickingAtNode(cons));
11786 
11787  exprgraph = SCIPgetExprgraphNonlinear(scip, SCIPconsGetHdlr(cons));
11788 
11789  /* add variables from expression tree as "quadratic" variables to quadratic constraint */
11790  for( i = 0; i < SCIPexprgraphGetNodeNChildren(node); ++i )
11791  {
11792  assert(SCIPexprgraphGetNodeChildren(node)[i] != NULL);
11793  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, upgdconss[0], (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[i]), 0.0, 0.0) );
11794  }
11795 
11796  switch( SCIPexprgraphGetNodeOperator(node) )
11797  {
11798  case SCIP_EXPR_MUL:
11799  /* expression is product of two variables, so add bilinear term to constraint */
11800  assert(SCIPexprgraphGetNodeNChildren(node) == 2);
11801 
11802  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, upgdconss[0],
11805  1.0) );
11806 
11807  break;
11808 
11809  case SCIP_EXPR_SQUARE:
11810  /* expression is square of a variable, so change square coefficient of quadratic variable */
11811  assert(SCIPexprgraphGetNodeNChildren(node) == 1);
11812 
11813  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, upgdconss[0],
11815  1.0) );
11816 
11817  break;
11818 
11819  case SCIP_EXPR_QUADRATIC:
11820  {
11821  /* expression is quadratic */
11822  SCIP_QUADELEM* quadelems;
11823  int nquadelems;
11824  SCIP_Real* lincoefs;
11825 
11827  nquadelems = SCIPexprgraphGetNodeQuadraticNQuadElements(node);
11829 
11831 
11832  if( lincoefs != NULL )
11833  for( i = 0; i < SCIPexprgraphGetNodeNChildren(node); ++i )
11834  if( lincoefs[i] != 0.0 )
11835  {
11836  /* linear term */
11837  SCIP_CALL( SCIPaddQuadVarLinearCoefQuadratic(scip, upgdconss[0],
11839  lincoefs[i]) );
11840  }
11841 
11842  for( i = 0; i < nquadelems; ++i )
11843  {
11844  assert(quadelems[i].idx1 < SCIPexprgraphGetNodeNChildren(node));
11845  assert(quadelems[i].idx2 < SCIPexprgraphGetNodeNChildren(node));
11846 
11847  if( quadelems[i].idx1 == quadelems[i].idx2 )
11848  {
11849  /* square term */
11850  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, upgdconss[0],
11851  (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[quadelems[i].idx1]),
11852  quadelems[i].coef) );
11853  }
11854  else
11855  {
11856  /* bilinear term */
11857  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, upgdconss[0],
11858  (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[quadelems[i].idx1]),
11859  (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[quadelems[i].idx2]),
11860  quadelems[i].coef) );
11861  }
11862  }
11863 
11864  break;
11865  }
11866 
11867  default:
11868  SCIPerrorMessage("you should not be here\n");
11869  return SCIP_ERROR;
11870  } /*lint !e788 */
11871 
11872  return SCIP_OKAY;
11873 }
11874 
11875 /*
11876  * Callback methods of constraint handler
11877  */
11878 
11879 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
11880 static
11881 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyQuadratic)
11882 { /*lint --e{715}*/
11883  assert(scip != NULL);
11884  assert(conshdlr != NULL);
11885  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
11886 
11887  /* call inclusion method of constraint handler */
11889 
11890  *valid = TRUE;
11891 
11892  return SCIP_OKAY;
11893 }
11894 
11895 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
11896 static
11897 SCIP_DECL_CONSFREE(consFreeQuadratic)
11899  SCIP_CONSHDLRDATA* conshdlrdata;
11900  int i;
11901 
11902  assert(scip != NULL);
11903  assert(conshdlr != NULL);
11904 
11905  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11906  assert(conshdlrdata != NULL);
11907 
11908  for( i = 0; i < conshdlrdata->nquadconsupgrades; ++i )
11909  {
11910  assert(conshdlrdata->quadconsupgrades[i] != NULL);
11911  SCIPfreeBlockMemory(scip, &conshdlrdata->quadconsupgrades[i]); /*lint !e866*/
11912  }
11913  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->quadconsupgrades, conshdlrdata->quadconsupgradessize);
11914  SCIPfreeBlockMemory(scip, &conshdlrdata);
11915 
11916  return SCIP_OKAY;
11917 }
11918 
11919 /** initialization method of constraint handler (called after problem was transformed) */
11920 static
11921 SCIP_DECL_CONSINIT(consInitQuadratic)
11922 { /*lint --e{715} */
11923  SCIP_CONSHDLRDATA* conshdlrdata;
11924 
11925  assert(scip != NULL);
11926  assert(conshdlr != NULL);
11927 
11928  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11929  assert(conshdlrdata != NULL);
11930 
11931  conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
11932  conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
11933 
11934  return SCIP_OKAY;
11935 }
11936 
11937 
11938 /** deinitialization method of constraint handler (called before transformed problem is freed) */
11939 static
11940 SCIP_DECL_CONSEXIT(consExitQuadratic)
11941 { /*lint --e{715} */
11942  SCIP_CONSHDLRDATA* conshdlrdata;
11943 
11944  assert(scip != NULL);
11945  assert(conshdlr != NULL);
11946 
11947  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11948  assert(conshdlrdata != NULL);
11949 
11950  conshdlrdata->subnlpheur = NULL;
11951  conshdlrdata->trysolheur = NULL;
11952 
11953  return SCIP_OKAY;
11954 }
11955 
11956 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
11957 #if 0
11958 static
11959 SCIP_DECL_CONSINITPRE(consInitpreQuadratic)
11960 { /*lint --e{715}*/
11961  SCIP_CONSHDLRDATA* conshdlrdata;
11962  SCIP_CONSDATA* consdata;
11963  int c;
11964 
11965  assert(scip != NULL);
11966  assert(conshdlr != NULL);
11967  assert(conss != NULL || nconss == 0);
11968 
11969  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11970  assert(conshdlrdata != NULL);
11971 
11972  return SCIP_OKAY;
11973 }
11974 #endif
11975 
11976 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
11977 static
11978 SCIP_DECL_CONSEXITPRE(consExitpreQuadratic)
11979 { /*lint --e{715}*/
11980  SCIP_CONSDATA* consdata;
11981  int c;
11982 #ifndef NDEBUG
11983  int i;
11984 #endif
11985 
11986  assert(scip != NULL);
11987  assert(conshdlr != NULL);
11988  assert(conss != NULL || nconss == 0);
11989 
11990  for( c = 0; c < nconss; ++c )
11991  {
11992  assert(conss != NULL);
11993  consdata = SCIPconsGetData(conss[c]);
11994  assert(consdata != NULL);
11995 
11996  if( !consdata->isremovedfixings )
11997  {
11998  SCIP_CALL( removeFixedVariables(scip, conss[c]) );
11999  }
12000 
12001  /* make sure we do not have duplicate bilinear terms, quad var terms, or linear vars */
12002  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
12003  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
12004  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
12005 
12006  assert(consdata->isremovedfixings);
12007  assert(consdata->linvarsmerged);
12008  assert(consdata->quadvarsmerged);
12009  assert(consdata->bilinmerged);
12010 
12011 #ifndef NDEBUG
12012  for( i = 0; i < consdata->nlinvars; ++i )
12013  assert(SCIPvarIsActive(consdata->linvars[i]));
12014 
12015  for( i = 0; i < consdata->nquadvars; ++i )
12016  assert(SCIPvarIsActive(consdata->quadvarterms[i].var));
12017 #endif
12018 
12019  /* tell SCIP that we have something nonlinear */
12020  if( SCIPconsIsAdded(conss[c]) && consdata->nquadvars > 0 )
12021  SCIPenableNLP(scip);
12022  }
12023 
12024  return SCIP_OKAY;
12025 }
12026 
12027 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin)
12028  *
12029  * @note Also called from consEnableQuadratic during solving stage.
12030  */
12031 static
12032 SCIP_DECL_CONSINITSOL(consInitsolQuadratic)
12034  SCIP_CONSHDLRDATA* conshdlrdata;
12035  SCIP_CONSDATA* consdata;
12036  int c;
12037  int i;
12038 
12039  assert(scip != NULL);
12040  assert(conshdlr != NULL);
12041  assert(conss != NULL || nconss == 0);
12042 
12043  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12044  assert(conshdlrdata != NULL);
12045 
12046  for( c = 0; c < nconss; ++c )
12047  {
12048  assert(conss != NULL);
12049  consdata = SCIPconsGetData(conss[c]);
12050  assert(consdata != NULL);
12051 
12052  /* check for a linear variable that can be increase or decreased without harming feasibility */
12053  consdataFindUnlockedLinearVar(scip, consdata);
12054 
12055  /* setup lincoefsmin, lincoefsmax */
12056  consdata->lincoefsmin = SCIPinfinity(scip);
12057  consdata->lincoefsmax = 0.0;
12058  for( i = 0; i < consdata->nlinvars; ++i )
12059  {
12060  consdata->lincoefsmin = MIN(consdata->lincoefsmin, REALABS(consdata->lincoefs[i])); /*lint !e666 */
12061  consdata->lincoefsmax = MAX(consdata->lincoefsmax, REALABS(consdata->lincoefs[i])); /*lint !e666 */
12062  }
12063 
12064  /* add nlrow representation to NLP, if NLP had been constructed */
12065  if( SCIPisNLPConstructed(scip) && SCIPconsIsEnabled(conss[c]) )
12066  {
12067  if( consdata->nlrow == NULL )
12068  {
12069  /* compute curvature for the quadratic constraint if not done yet */
12070  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) );
12071 
12072  SCIP_CALL( createNlRow(scip, conss[c]) );
12073  assert(consdata->nlrow != NULL);
12074  }
12075  SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
12076  }
12077 
12078  /* setup sepaquadvars and sepabilinvar2pos */
12079  assert(consdata->sepaquadvars == NULL);
12080  assert(consdata->sepabilinvar2pos == NULL);
12081  if( consdata->nquadvars > 0 )
12082  {
12083  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->sepaquadvars, consdata->nquadvars) );
12084  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->sepabilinvar2pos, consdata->nbilinterms) );
12085 
12086  /* make sure, quadratic variable terms are sorted */
12087  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
12088 
12089  for( i = 0; i < consdata->nquadvars; ++i )
12090  consdata->sepaquadvars[i] = consdata->quadvarterms[i].var;
12091 
12092  for( i = 0; i < consdata->nbilinterms; ++i )
12093  {
12094  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->bilinterms[i].var2, &consdata->sepabilinvar2pos[i]) );
12095  }
12096  }
12097 
12098  if( conshdlrdata->checkfactorable )
12099  {
12100  /* check if constraint function is factorable, i.e., can be written as product of two linear functions */
12101  SCIP_CALL( checkFactorable(scip, conss[c]) );
12102  }
12103 
12104  /* compute gauge function using interior points per constraint, only when there are quadratic variables */
12105  if( conshdlrdata->gaugecuts && SCIPgetSubscipDepth(scip) == 0 && consdata->nquadvars > 0 )
12106  {
12107  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
12108  if( (consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
12109  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)) )
12110  {
12111  SCIP_CALL( computeGauge(scip, conshdlr, conss[c]) );
12112  }
12113  }
12114 
12115  /* compute eigendecomposition for convex quadratics */
12116  if( conshdlrdata->projectedcuts && SCIPgetSubscipDepth(scip) == 0 && consdata->nquadvars > 0 )
12117  {
12118  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
12119  if( (consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
12120  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)) )
12121  {
12122  SCIP_CALL( computeED(scip, conshdlr, conss[c]) );
12123  }
12124  }
12125 
12126  /* mark constraint for propagation */
12127  SCIP_CALL( SCIPmarkConsPropagate(scip, conss[c]) );
12128  consdata->ispropagated = FALSE;
12129  }
12130 
12131  if( SCIPgetStage(scip) != SCIP_STAGE_INITSOLVE )
12132  {
12133  /* if called from consEnableQuadratic, then don't do below */
12134  return SCIP_OKAY;
12135  }
12136 
12137  conshdlrdata->newsoleventfilterpos = -1;
12138  if( nconss != 0 && conshdlrdata->linearizeheursol )
12139  {
12140  SCIP_EVENTHDLR* eventhdlr;
12141 
12142  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
12143  assert(eventhdlr != NULL);
12144 
12145  /* @todo Should we catch every new solution or only new *best* solutions */
12146  SCIP_CALL( SCIPcatchEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
12147  }
12148 
12149  if( nconss != 0 && !SCIPisIpoptAvailableIpopt() && !SCIPisInRestart(scip) )
12150  {
12151  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Quadratic constraint handler does not have LAPACK for eigenvalue computation. Will assume that matrices (with size > 2x2) are indefinite.\n");
12152  }
12153 
12154  /* reset flags and counters */
12155  conshdlrdata->sepanlp = FALSE;
12156  conshdlrdata->lastenfonode = NULL;
12157  conshdlrdata->nenforounds = 0;
12158 
12159  return SCIP_OKAY;
12160 }
12161 
12162 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed)
12163  *
12164  * @note Also called from consDisableQuadratic during solving stage.
12165  */
12166 static
12167 SCIP_DECL_CONSEXITSOL(consExitsolQuadratic)
12168 { /*lint --e{715}*/
12169  SCIP_CONSHDLRDATA* conshdlrdata;
12170  SCIP_CONSDATA* consdata;
12171  int c;
12172 
12173  assert(scip != NULL);
12174  assert(conshdlr != NULL);
12175  assert(conss != NULL || nconss == 0);
12176 
12177  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12178  assert(conshdlrdata != NULL);
12179 
12180  for( c = 0; c < nconss; ++c )
12181  {
12182  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
12183  assert(consdata != NULL);
12184 
12185  /* free nonlinear row representation */
12186  if( consdata->nlrow != NULL )
12187  {
12188  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
12189  }
12190 
12191  assert(!SCIPconsIsEnabled(conss[c]) || consdata->sepaquadvars != NULL || consdata->nquadvars == 0); /*lint !e613 */
12192  assert(!SCIPconsIsEnabled(conss[c]) || consdata->sepabilinvar2pos != NULL || consdata->nquadvars == 0); /*lint !e613 */
12193  SCIPfreeBlockMemoryArrayNull(scip, &consdata->sepaquadvars, consdata->nquadvars);
12194  SCIPfreeBlockMemoryArrayNull(scip, &consdata->sepabilinvar2pos, consdata->nbilinterms);
12195 
12196  SCIPfreeBlockMemoryArrayNull(scip, &consdata->factorleft, consdata->nquadvars + 1);
12197  SCIPfreeBlockMemoryArrayNull(scip, &consdata->factorright, consdata->nquadvars + 1);
12198 
12199  SCIPfreeBlockMemoryArrayNull(scip, &consdata->interiorpoint, consdata->nquadvars);
12200  SCIPfreeBlockMemoryArrayNull(scip, &consdata->gaugecoefs, consdata->nquadvars);
12201  SCIPfreeBlockMemoryArrayNull(scip, &consdata->eigenvalues, consdata->nquadvars);
12202  SCIPfreeBlockMemoryArrayNull(scip, &consdata->eigenvectors, (int)(consdata->nquadvars*consdata->nquadvars));
12203  SCIPfreeBlockMemoryArrayNull(scip, &consdata->bp, consdata->nquadvars);
12204  }
12205 
12206  if( SCIPgetStage(scip) != SCIP_STAGE_EXITSOLVE )
12207  {
12208  /* if called from consDisableQuadratic, then don't do below */
12209  return SCIP_OKAY;
12210  }
12211 
12212  if( conshdlrdata->newsoleventfilterpos >= 0 )
12213  {
12214  SCIP_EVENTHDLR* eventhdlr;
12215 
12216  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
12217  assert(eventhdlr != NULL);
12218 
12219  SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
12220  conshdlrdata->newsoleventfilterpos = -1;
12221  }
12222 
12223  /* free all stored bilinear terms in the constraint handler and constraint data; note that we might not want to
12224  * recollect all bilinear terms and therefore keep them even if consDisableQuadratic is called
12225  */
12226  SCIP_CALL( freeAllBilinearTerms(scip, conshdlrdata, conss, nconss) );
12227 
12228  return SCIP_OKAY;
12229 }
12230 
12231 /** frees specific constraint data */
12232 static
12233 SCIP_DECL_CONSDELETE(consDeleteQuadratic)
12235  assert(scip != NULL);
12236  assert(conshdlr != NULL);
12237  assert(cons != NULL);
12238  assert(consdata != NULL);
12239  assert(SCIPconsGetData(cons) == *consdata);
12240 
12241  SCIP_CALL( consdataFree(scip, consdata) );
12242 
12243  assert(*consdata == NULL);
12244 
12245  return SCIP_OKAY;
12246 }
12247 
12248 /** transforms constraint data into data belonging to the transformed problem */
12249 static
12250 SCIP_DECL_CONSTRANS(consTransQuadratic)
12251 {
12252  SCIP_CONSDATA* sourcedata;
12253  SCIP_CONSDATA* targetdata;
12254  int i;
12255 
12256  sourcedata = SCIPconsGetData(sourcecons);
12257  assert(sourcedata != NULL);
12258 
12259  SCIP_CALL( consdataCreate(scip, &targetdata,
12260  sourcedata->lhs, sourcedata->rhs,
12261  sourcedata->nlinvars, sourcedata->linvars, sourcedata->lincoefs,
12262  sourcedata->nquadvars, sourcedata->quadvarterms,
12263  sourcedata->nbilinterms, sourcedata->bilinterms,
12264  FALSE) );
12265 
12266  for( i = 0; i < targetdata->nlinvars; ++i )
12267  {
12268  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->linvars[i], &targetdata->linvars[i]) );
12269  SCIP_CALL( SCIPcaptureVar(scip, targetdata->linvars[i]) );
12270  }
12271 
12272  for( i = 0; i < targetdata->nquadvars; ++i )
12273  {
12274  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->quadvarterms[i].var, &targetdata->quadvarterms[i].var) );
12275  SCIP_CALL( SCIPcaptureVar(scip, targetdata->quadvarterms[i].var) );
12276  }
12277 
12278  for( i = 0; i < targetdata->nbilinterms; ++i )
12279  {
12280  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->bilinterms[i].var1, &targetdata->bilinterms[i].var1) );
12281  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->bilinterms[i].var2, &targetdata->bilinterms[i].var2) );
12282 
12283  if( SCIPvarCompare(targetdata->bilinterms[i].var1, targetdata->bilinterms[i].var2) > 0 )
12284  {
12285  SCIP_VAR* tmp;
12286  tmp = targetdata->bilinterms[i].var2;
12287  targetdata->bilinterms[i].var2 = targetdata->bilinterms[i].var1;
12288  targetdata->bilinterms[i].var1 = tmp;
12289  }
12290  }
12291 
12292  /* create target constraint */
12293  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12294  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12295  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
12296  SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons),
12297  SCIPconsIsStickingAtNode(sourcecons)) );
12298 
12299  SCIPdebugMsg(scip, "created transformed quadratic constraint ");
12300  SCIPdebugPrintCons(scip, *targetcons, NULL);
12301 
12302  return SCIP_OKAY;
12303 }
12304 
12305 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
12306 static
12307 SCIP_DECL_CONSINITLP(consInitlpQuadratic)
12309  SCIP_CONSHDLRDATA* conshdlrdata;
12310  SCIP_CONSDATA* consdata;
12311  SCIP_VAR* var;
12312  SCIP_ROW* row;
12313  SCIP_Real* x;
12314  int c;
12315  int i;
12316 
12317  assert(scip != NULL);
12318  assert(conshdlr != NULL);
12319  assert(conss != NULL || nconss == 0);
12320 
12321  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12322  assert(conshdlrdata != NULL);
12323 
12324  *infeasible = FALSE;
12325 
12326  for( c = 0; c < nconss && !(*infeasible); ++c )
12327  {
12328  assert(conss[c] != NULL); /*lint !e613 */
12329 
12330  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
12331 
12332  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
12333  assert(consdata != NULL);
12334 
12335  row = NULL;
12336 
12337  if( consdata->nquadvars == 0 )
12338  {
12339  /* if we are actually linear, add the constraint as row to the LP */
12340  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(conss[c]), SCIPconsGetName(conss[c]), consdata->lhs, consdata->rhs,
12341  SCIPconsIsLocal(conss[c]), FALSE , TRUE) ); /*lint !e613 */
12342  SCIP_CALL( SCIPaddVarsToRow(scip, row, consdata->nlinvars, consdata->linvars, consdata->lincoefs) );
12343  SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
12344  SCIP_CALL( SCIPreleaseRow (scip, &row) );
12345  continue;
12346  }
12347 
12348  /* alloc memory for reference point */
12349  SCIP_CALL( SCIPallocBufferArray(scip, &x, consdata->nquadvars) );
12350 
12351  /* for convex parts, add linearizations in 5 points */
12352  if( (consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
12353  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)) )
12354  {
12355  SCIP_Real lb;
12356  SCIP_Real ub;
12357  SCIP_Real lambda;
12358  int k;
12359 
12360  for( k = 0; k < 5; ++k )
12361  {
12362  lambda = 0.1 * (k+1); /* lambda = 0.1, 0.2, 0.3, 0.4, 0.5 */
12363  for( i = 0; i < consdata->nquadvars; ++i )
12364  {
12365  var = consdata->quadvarterms[i].var;
12366  lb = SCIPvarGetLbGlobal(var);
12367  ub = SCIPvarGetUbGlobal(var);
12368 
12369  if( ub > -INITLPMAXVARVAL )
12370  lb = MAX(lb, -INITLPMAXVARVAL);
12371  if( lb < INITLPMAXVARVAL )
12372  ub = MIN(ub, INITLPMAXVARVAL);
12373 
12374  /* make bounds finite */
12375  if( SCIPisInfinity(scip, -lb) )
12376  lb = MIN(-10.0, ub - 0.1*REALABS(ub)); /*lint !e666 */
12377  if( SCIPisInfinity(scip, ub) )
12378  ub = MAX( 10.0, lb + 0.1*REALABS(lb)); /*lint !e666 */
12379 
12381  x[i] = lambda * ub + (1.0 - lambda) * lb;
12382  else
12383  x[i] = lambda * lb + (1.0 - lambda) * ub;
12384  }
12385 
12386  SCIP_CALL( generateCut(scip, conshdlr, conss[c], x, NULL, consdata->isconvex ? SCIP_SIDETYPE_RIGHT : SCIP_SIDETYPE_LEFT, &row, NULL,
12387  FALSE, -SCIPinfinity(scip)) ); /*lint !e613 */
12388  if( row != NULL )
12389  {
12390  SCIPdebugMsg(scip, "initlp adds row <%s> for lambda = %g of conss <%s>\n", SCIProwGetName(row), lambda, SCIPconsGetName(conss[c])); /*lint !e613 */
12391  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
12392 
12393  SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
12394  SCIP_CALL( SCIPreleaseRow (scip, &row) );
12395  }
12396  }
12397  }
12398 
12399  /* for concave parts, add underestimator w.r.t. at most 2 reference points */
12400  if( !(*infeasible) && ((! consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs))
12401  || (! consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs))) )
12402  {
12403  SCIP_Bool unbounded;
12404  SCIP_Bool possquare;
12405  SCIP_Bool negsquare;
12406  SCIP_Real lb;
12407  SCIP_Real ub;
12408  SCIP_Real lambda;
12409  int k;
12410 
12411  unbounded = FALSE; /* whether there are unbounded variables */
12412  possquare = FALSE; /* whether there is a positive square term */
12413  negsquare = FALSE; /* whether there is a negative square term */
12414  for( k = 0; k < 2; ++k )
12415  {
12416  /* Set reference point to 0 projected on bounds for unbounded variables or in between lower and upper bound
12417  * for bounded variables in the first round, we set it closer to the best bound for one part of the
12418  * variables, in the second closer to the best bound for the other part of the variables.
12419  * Additionally, we use slightly different weights for each variable.
12420  * The reason for the latter is, that for a bilinear term with bounded variables, there are always two linear underestimators
12421  * if the same weight is used for both variables of a product, then rounding and luck decides which underestimator is chosen
12422  * of course, the possible number of cuts is something in the order of 2^nquadvars, and we choose two of them here.
12423  */
12424  for( i = 0; i < consdata->nquadvars; ++i )
12425  {
12426  var = consdata->quadvarterms[i].var;
12427  lb = SCIPvarGetLbGlobal(var);
12428  ub = SCIPvarGetUbGlobal(var);
12429 
12430  if( SCIPisInfinity(scip, -lb) )
12431  {
12432  if( SCIPisInfinity(scip, ub) )
12433  x[i] = 0.0;
12434  else
12435  x[i] = MIN(0.0, ub);
12436  unbounded = TRUE;
12437  }
12438  else
12439  {
12440  if( SCIPisInfinity(scip, ub) )
12441  {
12442  x[i] = MAX(0.0, lb);
12443  unbounded = TRUE;
12444  }
12445  else
12446  {
12447  lambda = 0.4 + 0.2 * ((i+k)%2) + 0.01 * i / (double)consdata->nquadvars;
12448  x[i] = lambda * SCIPvarGetBestBoundLocal(var) + (1.0-lambda) * SCIPvarGetWorstBoundLocal(var);
12449  }
12450  }
12451 
12452  possquare |= consdata->quadvarterms[i].sqrcoef > 0.0; /*lint !e514 */
12453  negsquare |= consdata->quadvarterms[i].sqrcoef < 0.0; /*lint !e514 */
12454  }
12455 
12456  if( !consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs) )
12457  {
12458  SCIP_CALL( generateCut(scip, conshdlr, conss[c], x, NULL, SCIP_SIDETYPE_RIGHT, &row, NULL,
12459  conshdlrdata->checkcurvature, -SCIPinfinity(scip)) ); /*lint !e613 */
12460  if( row != NULL )
12461  {
12462  SCIPdebugMsg(scip, "initlp adds row <%s> for rhs of conss <%s>, round %d\n", SCIProwGetName(row), SCIPconsGetName(conss[c]), k); /*lint !e613 */
12463  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
12464 
12465  SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
12466  SCIP_CALL( SCIPreleaseRow (scip, &row) );
12467  }
12468  }
12469  if( !(*infeasible) && !consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs) )
12470  {
12471  SCIP_CALL( generateCut(scip, conshdlr, conss[c], x, NULL, SCIP_SIDETYPE_LEFT, &row, NULL,
12472  conshdlrdata->checkcurvature, -SCIPinfinity(scip)) ); /*lint !e613 */
12473  if( row != NULL )
12474  {
12475  SCIPdebugMsg(scip, "initlp adds row <%s> for lhs of conss <%s>, round %d\n", SCIProwGetName(row), SCIPconsGetName(conss[c]), k); /*lint !e613 */
12476  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
12477 
12478  SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
12479  SCIP_CALL( SCIPreleaseRow (scip, &row) );
12480  }
12481  }
12482 
12483  /* if there are unbounded variables, then there is typically only at most one possible underestimator, so don't try another round
12484  * similar, if there are no bilinear terms and no linearizations of square terms, then the reference point does not matter, so don't do another round */
12485  if( unbounded ||
12486  (consdata->nbilinterms == 0 && (!possquare || SCIPisInfinity(scip, consdata->rhs))) ||
12487  (consdata->nbilinterms == 0 && (!negsquare || SCIPisInfinity(scip, -consdata->lhs))) )
12488  break;
12489  }
12490  }
12491 
12492  SCIPfreeBufferArray(scip, &x);
12493  }
12494 
12495  /* store all bilinear terms into constraint handler data; this code is not in initsolve because the sub-NLP
12496  * heuristic triggers this callback and should not collect all bilinear terms
12497  */
12498  SCIP_CALL( storeAllBilinearTerms(scip, conshdlrdata, conss, nconss) );
12499 
12500  return SCIP_OKAY;
12501 }
12502 
12503 /** separation method of constraint handler for LP solutions */
12504 static
12505 SCIP_DECL_CONSSEPALP(consSepalpQuadratic)
12506 {
12507  SCIP_CONSHDLRDATA* conshdlrdata;
12508  SCIP_Bool solviolbounds;
12509  SCIP_CONS* maxviolcon;
12510 
12511  assert(scip != NULL);
12512  assert(conshdlr != NULL);
12513  assert(conss != NULL || nconss == 0);
12514  assert(result != NULL);
12515 
12516  *result = SCIP_DIDNOTFIND;
12517 
12518  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12519  assert(conshdlrdata != NULL);
12520 
12521  SCIP_CALL( computeViolations(scip, conss, nconss, NULL, &solviolbounds, &maxviolcon) );
12522 
12523  /* don't try to separate solutions that violate variable bounds */
12524  if( solviolbounds )
12525  return SCIP_OKAY;
12526 
12527  /* if nothing violated, then nothing to separate */
12528  if( maxviolcon == NULL )
12529  return SCIP_OKAY;
12530 
12531  /* at root, check if we want to solve the NLP relaxation and use its solutions as reference point
12532  * if there is something convex, then linearizing in the solution of the NLP relaxation can be very useful
12533  */
12534  if( SCIPgetDepth(scip) == 0 && !conshdlrdata->sepanlp &&
12535  (SCIPgetNContVars(scip) >= conshdlrdata->sepanlpmincont * SCIPgetNVars(scip) ||
12536  (SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY && conshdlrdata->sepanlpmincont <= 1.0)) &&
12537  SCIPisNLPConstructed(scip) && SCIPgetNNlpis(scip) > 0 )
12538  {
12539  SCIP_CONSDATA* consdata;
12540  SCIP_NLPSOLSTAT solstat;
12541  SCIP_Bool solvednlp;
12542  int c;
12543 
12544  solstat = SCIPgetNLPSolstat(scip);
12545  solvednlp = FALSE;
12546  if( solstat == SCIP_NLPSOLSTAT_UNKNOWN )
12547  {
12548  /* NLP is not solved yet, so we might want to do this
12549  * but first check whether there is a violated constraint side which corresponds to a convex function
12550  */
12551  for( c = 0; c < nconss; ++c )
12552  {
12553  assert(conss[c] != NULL); /*lint !e613 */
12554 
12555  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
12556  assert(consdata != NULL);
12557 
12558  /* skip feasible constraints */
12559  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
12560  continue;
12561 
12562  /* make sure curvature has been checked */
12563  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
12564 
12565  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && consdata->isconvex) ||
12566  ( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && consdata->isconcave) )
12567  break;
12568  }
12569 
12570  if( c < nconss )
12571  {
12572  /* try to solve NLP and update solstat */
12573 
12574  /* ensure linear conss are in NLP */
12575  if( conshdlrdata->subnlpheur != NULL )
12576  {
12577  SCIP_CALL( SCIPaddLinearConsToNlpHeurSubNlp(scip, conshdlrdata->subnlpheur, TRUE, TRUE) );
12578  }
12579 
12580  /* set LP solution as starting values, if available */
12582  {
12583  SCIP_CALL( SCIPsetNLPInitialGuessSol(scip, NULL) );
12584  }
12585 
12586  /* SCIP_CALL( SCIPsetNLPIntPar(scip, SCIP_NLPPAR_VERBLEVEL, 1) ); */
12587  SCIP_CALL( SCIPsolveNLP(scip) );
12588 
12589  solstat = SCIPgetNLPSolstat(scip);
12590  SCIPdebugMsg(scip, "solved NLP relax, solution status: %d\n", solstat);
12591 
12592  solvednlp = TRUE;
12593  }
12594  }
12595 
12596  conshdlrdata->sepanlp = TRUE;
12597 
12598  if( solstat == SCIP_NLPSOLSTAT_GLOBINFEASIBLE )
12599  {
12600  SCIPdebugMsg(scip, "NLP relaxation is globally infeasible, thus can cutoff node\n");
12601  *result = SCIP_CUTOFF;
12602  return SCIP_OKAY;
12603  }
12604 
12605  if( solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
12606  {
12607  /* if we have feasible NLP solution, generate linearization cuts there */
12608  SCIP_Bool lpsolseparated;
12609  SCIP_SOL* nlpsol;
12610 
12611  SCIP_CALL( SCIPcreateNLPSol(scip, &nlpsol, NULL) );
12612  assert(nlpsol != NULL);
12613 
12614  /* if we solved the NLP and solution is integral, then pass it to trysol heuristic */
12615  if( solvednlp && conshdlrdata->trysolheur != NULL )
12616  {
12617  int nfracvars;
12618 
12619  nfracvars = 0;
12620  if( SCIPgetNBinVars(scip) > 0 || SCIPgetNIntVars(scip) > 0 )
12621  {
12622  SCIP_CALL( SCIPgetNLPFracVars(scip, NULL, NULL, NULL, &nfracvars, NULL) );
12623  }
12624 
12625  if( nfracvars == 0 )
12626  {
12627  SCIPdebugMsg(scip, "pass solution with obj. value %g to trysol\n", SCIPgetSolOrigObj(scip, nlpsol));
12628  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, nlpsol) );
12629  }
12630  }
12631 
12632  SCIP_CALL( addLinearizationCuts(scip, conshdlr, conss, nconss, nlpsol, &lpsolseparated, SCIPgetSepaMinEfficacy(scip)) );
12633 
12634  SCIP_CALL( SCIPfreeSol(scip, &nlpsol) );
12635 
12636  /* if a cut that separated the LP solution was added, then return, otherwise continue with usual separation in LP solution */
12637  if( lpsolseparated )
12638  {
12639  SCIPdebugMsg(scip, "linearization cuts separate LP solution\n");
12640  *result = SCIP_SEPARATED;
12641 
12642  return SCIP_OKAY;
12643  }
12644  }
12645  }
12646  /* if we do not want to try solving the NLP, or have no NLP, or have no NLP solver, or solving the NLP failed,
12647  * or separating with NLP solution as reference point failed, then try (again) with LP solution as reference point
12648  */
12649 
12650  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, NULL, SCIPgetSepaMinEfficacy(scip), FALSE, result, NULL) );
12651 
12652  return SCIP_OKAY;
12653 }
12654 
12655 /** separation method of constraint handler for arbitrary primal solutions */
12656 static
12657 SCIP_DECL_CONSSEPASOL(consSepasolQuadratic)
12659  SCIP_Bool solviolbounds;
12660  SCIP_CONS* maxviolcon;
12661 
12662  assert(scip != NULL);
12663  assert(conshdlr != NULL);
12664  assert(conss != NULL || nconss == 0);
12665  assert(sol != NULL);
12666  assert(result != NULL);
12667 
12668  *result = SCIP_DIDNOTFIND;
12669 
12670  SCIP_CALL( computeViolations(scip, conss, nconss, sol, &solviolbounds, &maxviolcon) );
12671 
12672  /* don't separate solution that are outside variable bounds */
12673  if( solviolbounds )
12674  return SCIP_OKAY;
12675 
12676  /* if nothing violated, then nothing to separate */
12677  if( maxviolcon == NULL )
12678  return SCIP_OKAY;
12679 
12680  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, SCIPgetSepaMinEfficacy(scip), FALSE, result, NULL) );
12681 
12682  return SCIP_OKAY;
12683 }
12684 
12685 /** constraint enforcing method of constraint handler for LP solutions */
12686 static
12687 SCIP_DECL_CONSENFOLP(consEnfolpQuadratic)
12688 { /*lint --e{715}*/
12689  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, solinfeasible, result) );
12690 
12691  return SCIP_OKAY;
12692 }
12693 
12694 /** constraint enforcing method of constraint handler for relaxation solutions */
12695 static
12696 SCIP_DECL_CONSENFORELAX(consEnforelaxQuadratic)
12697 { /*lint --e{715}*/
12698  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, solinfeasible, result) );
12699 
12700  return SCIP_OKAY;
12701 }
12702 
12703 /** constraint enforcing method of constraint handler for pseudo solutions */
12704 static
12705 SCIP_DECL_CONSENFOPS(consEnfopsQuadratic)
12706 { /*lint --e{715}*/
12707  SCIP_Bool solviolbounds;
12708  SCIP_CONS* maxviolcon;
12709  SCIP_CONSDATA* consdata;
12710  SCIP_RESULT propresult;
12711  SCIP_VAR* var;
12712  int c;
12713  int i;
12714  int nchgbds;
12715  int nnotify;
12716 
12717  assert(scip != NULL);
12718  assert(conss != NULL || nconss == 0);
12719 
12720  SCIP_CALL( computeViolations(scip, conss, nconss, NULL, &solviolbounds, &maxviolcon) );
12721 
12722  /* pseudo solutions should be within bounds by definition */
12723  assert(!solviolbounds);
12724 
12725  if( maxviolcon == NULL )
12726  {
12727  *result = SCIP_FEASIBLE;
12728  return SCIP_OKAY;
12729  }
12730 
12731  *result = SCIP_INFEASIBLE;
12732 
12733  SCIPdebugMsg(scip, "enfops with max violation in cons <%s>\n", SCIPconsGetName(maxviolcon));
12734 
12735  /* run domain propagation */
12736  nchgbds = 0;
12737  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, &propresult, &nchgbds) );
12738  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
12739  {
12740  *result = propresult;
12741  return SCIP_OKAY;
12742  }
12743 
12744  /* we are not feasible and we cannot proof that the whole node is infeasible
12745  * -> collect all variables in violated constraints for branching
12746  */
12747  nnotify = 0;
12748  for( c = 0; c < nconss; ++c )
12749  {
12750  assert(conss != NULL);
12751  consdata = SCIPconsGetData(conss[c]);
12752  assert(consdata != NULL);
12753 
12754  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
12755  continue;
12756 
12757  for( i = 0; i < consdata->nlinvars; ++i )
12758  {
12759  var = consdata->linvars[i];
12760  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
12761  {
12762  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
12763  ++nnotify;
12764  }
12765  }
12766 
12767  for( i = 0; i < consdata->nquadvars; ++i )
12768  {
12769  var = consdata->quadvarterms[i].var;
12770  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
12771  {
12772  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
12773  ++nnotify;
12774  }
12775  }
12776  }
12777 
12778  if( nnotify == 0 )
12779  {
12780  SCIP_Bool addedcons;
12781  SCIP_Bool reduceddom;
12782  SCIP_Bool infeasible;
12783 
12784  /* if no branching candidate found, then all variables are almost fixed
12785  * calling replaceByLinearConstraints() should lead to fix all almost-fixed quadratic variables, and possibly replace some quad. conss by linear ones
12786  */
12787  SCIP_CALL( replaceByLinearConstraints(scip, conss, nconss, &addedcons, &reduceddom, &infeasible) );
12788  if( addedcons )
12789  {
12790  *result = SCIP_CONSADDED;
12791  return SCIP_OKAY;
12792  }
12793  if( reduceddom )
12794  {
12795  *result = SCIP_REDUCEDDOM;
12796  return SCIP_OKAY;
12797  }
12798  if( infeasible )
12799  {
12800  *result = SCIP_CUTOFF;
12801  return SCIP_OKAY;
12802  }
12803 
12804  SCIPdebugMsg(scip, "All variables in violated constraints fixed (up to epsilon). Cannot find branching candidate. Forcing solution of LP.\n");
12805  *result = SCIP_SOLVELP;
12806  }
12807 
12808  assert(*result == SCIP_SOLVELP || (*result == SCIP_INFEASIBLE && nnotify > 0));
12809  return SCIP_OKAY;
12810 }
12811 
12812 /** domain propagation method of constraint handler */
12813 static
12814 SCIP_DECL_CONSPROP(consPropQuadratic)
12816  int nchgbds;
12817 
12818  assert(scip != NULL);
12819  assert(conshdlr != NULL);
12820  assert(conss != NULL || nconss == 0);
12821  assert(result != NULL);
12822 
12823  nchgbds = 0;
12824  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nmarkedconss, result, &nchgbds) );
12825 
12826  return SCIP_OKAY;
12827 } /*lint !e715 */
12828 
12829 /** presolving method of constraint handler */
12830 static
12831 SCIP_DECL_CONSPRESOL(consPresolQuadratic)
12832 { /*lint --e{715,788}*/
12833  SCIP_CONSHDLRDATA* conshdlrdata;
12834  SCIP_CONSDATA* consdata;
12835  SCIP_RESULT solveresult;
12836  SCIP_Bool redundant;
12837  SCIP_Bool havechange;
12838  SCIP_Bool doreformulations;
12839  int c;
12840  int i;
12841 
12842  assert(scip != NULL);
12843  assert(conshdlr != NULL);
12844  assert(conss != NULL || nconss == 0);
12845  assert(result != NULL);
12846 
12847  *result = SCIP_DIDNOTFIND;
12848 
12849  /* if other presolvers did not find enough changes for another presolving round and we are in exhaustive presolving,
12850  * then try the reformulations (replacing products with binaries, disaggregation, setting default variable bounds)
12851  * otherwise, we wait with these
12852  */
12853  doreformulations = ((presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0) && SCIPisPresolveFinished(scip);
12854  SCIPdebugMsg(scip, "presolving will %swait with reformulation\n", doreformulations ? "not " : "");
12855 
12856  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12857  assert(conshdlrdata != NULL);
12858 
12859  for( c = 0; c < nconss; ++c )
12860  {
12861  assert(conss != NULL);
12862  consdata = SCIPconsGetData(conss[c]);
12863  assert(consdata != NULL);
12864 
12865  SCIPdebugMsg(scip, "process constraint <%s>\n", SCIPconsGetName(conss[c]));
12866  SCIPdebugPrintCons(scip, conss[c], NULL);
12867 
12868  if( !consdata->initialmerge )
12869  {
12870  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
12871  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
12872  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
12873  consdata->initialmerge = TRUE;
12874  }
12875 
12876  havechange = FALSE;
12877 #ifdef CHECKIMPLINBILINEAR
12878  if( consdata->isimpladded && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
12879  {
12880  int nbilinremoved;
12881  SCIP_CALL( presolveApplyImplications(scip, conss[c], &nbilinremoved) );
12882  if( nbilinremoved > 0 )
12883  {
12884  *nchgcoefs += nbilinremoved;
12885  havechange = TRUE;
12886  *result = SCIP_SUCCESS;
12887  }
12888  assert(!consdata->isimpladded);
12889  }
12890 #endif
12891  /* call upgrade methods if the constraint has not been presolved yet or there has been a bound tightening or possibly be a change in variable type
12892  * we want to do this before (multi)aggregated variables are replaced, since that may change structure, e.g., introduce bilinear terms
12893  */
12894  if( !consdata->ispresolved || !consdata->ispropagated || nnewchgvartypes > 0 )
12895  {
12896  SCIP_Bool upgraded;
12897 
12898  SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss, presoltiming) );
12899  if( upgraded )
12900  {
12901  *result = SCIP_SUCCESS;
12902  continue;
12903  }
12904  }
12905 
12906  if( !consdata->isremovedfixings )
12907  {
12908  SCIP_CALL( removeFixedVariables(scip, conss[c]) );
12909  assert(consdata->isremovedfixings);
12910  havechange = TRUE;
12911  }
12912 
12913  /* try to "solve" the constraint, e.g., reduce to a variable aggregation */
12914  SCIP_CALL( presolveSolve(scip, conss[c], &solveresult, &redundant, naggrvars) );
12915  if( solveresult == SCIP_CUTOFF )
12916  {
12917  SCIPdebugMsg(scip, "solving constraint <%s> says problem is infeasible in presolve\n", SCIPconsGetName(conss[c]));
12918  *result = SCIP_CUTOFF;
12919  return SCIP_OKAY;
12920  }
12921  if( redundant )
12922  {
12923  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
12924  ++*ndelconss;
12925  *result = SCIP_SUCCESS;
12926  break;
12927  }
12928  if( solveresult == SCIP_SUCCESS )
12929  {
12930  *result = SCIP_SUCCESS;
12931  havechange = TRUE;
12932  }
12933 
12934  /* @todo divide constraint by gcd of coefficients if all are integral */
12935 
12936  if( doreformulations )
12937  {
12938  int naddconss_old;
12939 
12940  naddconss_old = *naddconss;
12941 
12942  SCIP_CALL( presolveTryAddAND(scip, conshdlr, conss[c], naddconss) );
12943  assert(*naddconss >= naddconss_old);
12944 
12945  if( *naddconss == naddconss_old )
12946  {
12947  /* user not so empathic about AND, or we don't have products of two binaries, so try this more general reformulation */
12948  SCIP_CALL( presolveTryAddLinearReform(scip, conshdlr, conss[c], naddconss) );
12949  assert(*naddconss >= naddconss_old);
12950  }
12951 
12952  if( conshdlrdata->maxdisaggrsize > 1 )
12953  {
12954  /* try disaggregation, if enabled */
12955  SCIP_CALL( presolveDisaggregate(scip, conshdlr, conss[c], naddconss) );
12956  }
12957 
12958  if( *naddconss > naddconss_old )
12959  {
12960  /* if something happened, report success and cleanup constraint */
12961  *result = SCIP_SUCCESS;
12962  havechange = TRUE;
12963  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
12964  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
12965  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
12966  }
12967  }
12968 
12969  if( consdata->nlinvars == 0 && consdata->nquadvars == 0 )
12970  {
12971  /* all variables fixed or removed, constraint function is 0.0 now */
12972  if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasPositive(scip, consdata->lhs)) ||
12973  ( !SCIPisInfinity(scip, consdata->rhs) && SCIPisFeasNegative(scip, consdata->rhs)) )
12974  { /* left hand side positive or right hand side negative */
12975  SCIPdebugMsg(scip, "constraint <%s> is constant and infeasible\n", SCIPconsGetName(conss[c]));
12976  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
12977  ++*ndelconss;
12978  *result = SCIP_CUTOFF;
12979  return SCIP_OKAY;
12980  }
12981 
12982  /* left and right hand side are consistent */
12983  SCIPdebugMsg(scip, "constraint <%s> is constant and feasible, deleting\n", SCIPconsGetName(conss[c]));
12984  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
12985  ++*ndelconss;
12986  *result = SCIP_SUCCESS;
12987  continue;
12988  }
12989 
12990  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 && !consdata->ispropagated )
12991  {
12992  /* try domain propagation if there were bound changes or constraint has changed (in which case, processVarEvents may have set ispropagated to false) */
12993  SCIP_RESULT propresult;
12994  int roundnr;
12995 
12996  roundnr = 0;
12997  do
12998  {
12999  ++roundnr;
13000 
13001  SCIPdebugMsg(scip, "starting domain propagation round %d of %d\n", roundnr, conshdlrdata->maxproproundspresolve);
13002 
13003  if( !consdata->ispropagated )
13004  {
13005  consdata->ispropagated = TRUE;
13006 
13007  SCIP_CALL( propagateBoundsCons(scip, conshdlr, conss[c], &propresult, nchgbds, &redundant) );
13008 
13009  if( propresult == SCIP_CUTOFF )
13010  {
13011  SCIPdebugMsg(scip, "propagation on constraint <%s> says problem is infeasible in presolve\n",
13012  SCIPconsGetName(conss[c]));
13013  *result = SCIP_CUTOFF;
13014  return SCIP_OKAY;
13015  }
13016 
13017  /* delete constraint if found redundant by bound tightening */
13018  if( redundant )
13019  {
13020  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
13021  ++*ndelconss;
13022  *result = SCIP_SUCCESS;
13023  break;
13024  }
13025 
13026  if( propresult == SCIP_REDUCEDDOM )
13027  {
13028  *result = SCIP_SUCCESS;
13029  havechange = TRUE;
13030  }
13031  }
13032  }
13033  while( !consdata->ispropagated && roundnr < conshdlrdata->maxproproundspresolve );
13034 
13035  if( redundant )
13036  continue;
13037  }
13038 
13039  /* check if we have a single linear continuous variable that we can make implicit integer */
13040  if( (nnewchgvartypes != 0 || havechange || !consdata->ispresolved)
13041  && (SCIPisEQ(scip, consdata->lhs, consdata->rhs) && SCIPisIntegral(scip, consdata->lhs)) )
13042  {
13043  int ncontvar;
13044  SCIP_VAR* candidate;
13045  SCIP_Bool fail;
13046 
13047  fail = FALSE;
13048  candidate = NULL;
13049  ncontvar = 0;
13050 
13051  for( i = 0; !fail && i < consdata->nlinvars; ++i )
13052  {
13053  if( !SCIPisIntegral(scip, consdata->lincoefs[i]) )
13054  {
13055  fail = TRUE;
13056  }
13057  else if( SCIPvarGetType(consdata->linvars[i]) == SCIP_VARTYPE_CONTINUOUS )
13058  {
13059  if( ncontvar > 0 ) /* now at 2nd continuous variable */
13060  fail = TRUE;
13061  else if( SCIPisEQ(scip, ABS(consdata->lincoefs[i]), 1.0) )
13062  candidate = consdata->linvars[i];
13063  ++ncontvar;
13064  }
13065  }
13066  for( i = 0; !fail && i < consdata->nquadvars; ++i )
13067  fail = SCIPvarGetType(consdata->quadvarterms[i].var) == SCIP_VARTYPE_CONTINUOUS ||
13068  !SCIPisIntegral(scip, consdata->quadvarterms[i].lincoef) ||
13069  !SCIPisIntegral(scip, consdata->quadvarterms[i].sqrcoef);
13070  for( i = 0; !fail && i < consdata->nbilinterms; ++i )
13071  fail = !SCIPisIntegral(scip, consdata->bilinterms[i].coef);
13072 
13073  if( !fail && candidate != NULL )
13074  {
13075  SCIP_Bool infeasible;
13076 
13077  SCIPdebugMsg(scip, "make variable <%s> implicit integer due to constraint <%s>\n", SCIPvarGetName(candidate), SCIPconsGetName(conss[c]));
13078 
13079  SCIP_CALL( SCIPchgVarType(scip, candidate, SCIP_VARTYPE_IMPLINT, &infeasible) );
13080  if( infeasible )
13081  {
13082  SCIPdebugMsg(scip, "infeasible upgrade of variable <%s> to integral type, domain is empty\n", SCIPvarGetName(candidate));
13083  *result = SCIP_CUTOFF;
13084 
13085  return SCIP_OKAY;
13086  }
13087 
13088  ++(*nchgvartypes);
13089  *result = SCIP_SUCCESS;
13090  havechange = TRUE;
13091  }
13092  }
13093 
13094  /* call upgrade methods again if constraint has been changed */
13095  if( havechange )
13096  {
13097  SCIP_Bool upgraded;
13098 
13099  SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss, presoltiming) );
13100  if( upgraded )
13101  {
13102  *result = SCIP_SUCCESS;
13103  continue;
13104  }
13105  }
13106 
13107  /* fix quadratic variables with proper square coefficients contained in a single quadratic constraint to their
13108  * upper or lower bounds
13109  */
13110  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 && conshdlrdata->checkquadvarlocks != 'd'
13111  && SCIPisPresolveFinished(scip) )
13112  {
13113  SCIP_CONS* cons;
13114  SCIP_VAR* vars[2];
13115  SCIP_BOUNDTYPE boundtypes[2];
13116  SCIP_Real bounds[2];
13117  char name[SCIP_MAXSTRLEN];
13118 
13119  /* merge variables in order to get correct locks for quadratic variables */
13120  if( !consdata->initialmerge )
13121  {
13122  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
13123  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
13124  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
13125  consdata->initialmerge = TRUE;
13126  }
13127 
13128  for( i = 0; i < consdata->nquadvars; ++i )
13129  {
13130  if( hasQuadvarHpProperty(scip, consdata, i) )
13131  {
13132  SCIP_VAR* var;
13133 
13134  var = consdata->quadvarterms[i].var;
13135  assert(var != NULL);
13136 
13137  /* try to change the variable type to binary */
13138  if( conshdlrdata->checkquadvarlocks == 't' && SCIPisEQ(scip, SCIPvarGetLbGlobal(var), 0.0) && SCIPisEQ(scip, SCIPvarGetUbGlobal(var), 1.0) )
13139  {
13140  SCIP_Bool infeasible;
13141 
13142  assert(SCIPvarGetType(var) != SCIP_VARTYPE_BINARY);
13143  SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, &infeasible) );
13144 
13145  if( infeasible )
13146  {
13147  SCIPdebugMsg(scip, "detect infeasibility after changing variable <%s> to binary type\n", SCIPvarGetName(var));
13148  *result = SCIP_CUTOFF;
13149  return SCIP_OKAY;
13150  }
13151  }
13152  /* add bound disjunction constraint if bounds of variable are finite */
13153  else if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
13154  {
13155  vars[0] = var;
13156  vars[1] = var;
13157  boundtypes[0] = SCIP_BOUNDTYPE_LOWER;
13158  boundtypes[1] = SCIP_BOUNDTYPE_UPPER;
13159  bounds[0] = SCIPvarGetUbGlobal(var);
13160  bounds[1] = SCIPvarGetLbGlobal(var);
13161 
13162  SCIPdebugMsg(scip, "add bound disjunction constraint for %s\n", SCIPvarGetName(var));
13163 
13164  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "quadvarbnddisj_%s", SCIPvarGetName(var));
13165  SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &cons, name, 2, vars, boundtypes, bounds, TRUE, TRUE,
13166  TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
13167 
13168  SCIP_CALL( SCIPaddCons(scip, cons) );
13169  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
13170  }
13171 
13172  *result = SCIP_SUCCESS;
13173  }
13174  }
13175  }
13176 
13177  consdata->ispresolved = TRUE;
13178  }
13179 
13180  return SCIP_OKAY;
13181 }
13182 
13183 /** variable rounding lock method of constraint handler */
13184 static
13185 SCIP_DECL_CONSLOCK(consLockQuadratic)
13186 { /*lint --e{715}*/
13187  SCIP_CONSDATA* consdata;
13188  SCIP_Bool haslb;
13189  SCIP_Bool hasub;
13190  int i;
13191 
13192  assert(scip != NULL);
13193  assert(cons != NULL);
13194 
13195  consdata = SCIPconsGetData(cons);
13196  assert(consdata != NULL);
13197 
13198  haslb = !SCIPisInfinity(scip, -consdata->lhs);
13199  hasub = !SCIPisInfinity(scip, consdata->rhs);
13200 
13201  for( i = 0; i < consdata->nlinvars; ++i )
13202  {
13203  if( consdata->lincoefs[i] > 0 )
13204  {
13205  if( haslb )
13206  {
13207  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlockspos, nlocksneg) );
13208  }
13209  if( hasub )
13210  {
13211  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlocksneg, nlockspos) );
13212  }
13213  }
13214  else
13215  {
13216  if( haslb )
13217  {
13218  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlocksneg, nlockspos) );
13219  }
13220  if( hasub )
13221  {
13222  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlockspos, nlocksneg) );
13223  }
13224  }
13225  }
13226 
13227  for( i = 0; i < consdata->nquadvars; ++i )
13228  {
13229  /* @todo try to be more clever, but variable locks that depend on the bounds of other variables are not trival to maintain */
13230  SCIP_CALL( SCIPaddVarLocks(scip, consdata->quadvarterms[i].var, nlockspos+nlocksneg, nlockspos+nlocksneg) );
13231  }
13232 
13233  return SCIP_OKAY;
13234 }
13235 
13236 /** constraint enabling notification method of constraint handler */
13237 static
13238 SCIP_DECL_CONSENABLE(consEnableQuadratic)
13240  SCIP_CONSHDLRDATA* conshdlrdata;
13241 
13242  assert(scip != NULL);
13243  assert(conshdlr != NULL);
13244  assert(cons != NULL);
13245  assert(SCIPconsIsTransformed(cons));
13246  assert(SCIPconsIsActive(cons));
13247 
13248  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13249  assert(conshdlrdata != NULL);
13250 
13251  SCIPdebugMsg(scip, "enable cons <%s>\n", SCIPconsGetName(cons));
13252 
13253  if( SCIPgetStage(scip) >= SCIP_STAGE_EXITPRESOLVE )
13254  {
13255  /* merge duplicate bilinear terms, move quad terms that are linear to linear vars */
13256  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
13257  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, cons) );
13258  SCIP_CALL( mergeAndCleanLinearVars(scip, cons) );
13259  }
13260 
13261  /* catch variable events */
13262  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
13263 
13264  /* initialize solving data */
13265  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
13266  {
13267  SCIP_CALL( consInitsolQuadratic(scip, conshdlr, &cons, 1) );
13268  }
13269 
13270  return SCIP_OKAY;
13271 }
13272 
13273 /** constraint disabling notification method of constraint handler */
13274 static
13275 SCIP_DECL_CONSDISABLE(consDisableQuadratic)
13276 { /*lint --e{715}*/
13277  SCIP_CONSHDLRDATA* conshdlrdata;
13278 
13279  assert(scip != NULL);
13280  assert(conshdlr != NULL);
13281  assert(cons != NULL);
13282  assert(SCIPconsIsTransformed(cons));
13283 
13284  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13285  assert(conshdlrdata != NULL);
13286 
13287  SCIPdebugMsg(scip, "disable cons <%s>\n", SCIPconsGetName(cons));
13288 
13289  /* free solving data */
13290  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
13291  {
13292  SCIP_CALL( consExitsolQuadratic(scip, conshdlr, &cons, 1, FALSE) );
13293  }
13294 
13295  /* drop variable events */
13296  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
13297 
13298  return SCIP_OKAY;
13299 }
13300 
13301 /** constraint display method of constraint handler */
13302 static
13303 SCIP_DECL_CONSPRINT(consPrintQuadratic)
13304 { /*lint --e{715}*/
13305  SCIP_CONSDATA* consdata;
13306 
13307  assert(scip != NULL);
13308  assert(cons != NULL);
13309 
13310  consdata = SCIPconsGetData(cons);
13311  assert(consdata != NULL);
13312 
13313  /* print left hand side for ranged rows */
13314  if( !SCIPisInfinity(scip, -consdata->lhs)
13315  && !SCIPisInfinity(scip, consdata->rhs)
13316  && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
13317  SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
13318 
13319  /* print coefficients and variables */
13320  if( consdata->nlinvars == 0 && consdata->nquadvars == 0 )
13321  {
13322  SCIPinfoMessage(scip, file, "0 ");
13323  }
13324  else
13325  {
13326  SCIP_VAR*** monomialvars;
13327  SCIP_Real** monomialexps;
13328  SCIP_Real* monomialcoefs;
13329  int* monomialnvars;
13330  int nmonomials;
13331  int monomialssize;
13332  int j;
13333 
13334  monomialssize = consdata->nlinvars + 2 * consdata->nquadvars + consdata->nbilinterms;
13335  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars, monomialssize) );
13336  SCIP_CALL( SCIPallocBufferArray(scip, &monomialexps, monomialssize) );
13337  SCIP_CALL( SCIPallocBufferArray(scip, &monomialcoefs, monomialssize) );
13338  SCIP_CALL( SCIPallocBufferArray(scip, &monomialnvars, monomialssize) );
13339 
13340  nmonomials = 0;
13341  for( j = 0; j < consdata->nlinvars; ++j )
13342  {
13343  assert(nmonomials < monomialssize);
13344 
13345  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 1) ); /*lint !e866 */
13346 
13347  monomialvars[nmonomials][0] = consdata->linvars[j];
13348  monomialexps[nmonomials] = NULL;
13349  monomialcoefs[nmonomials] = consdata->lincoefs[j];
13350  monomialnvars[nmonomials] = 1;
13351  ++nmonomials;
13352  }
13353 
13354  for( j = 0; j < consdata->nquadvars; ++j )
13355  {
13356  if( consdata->quadvarterms[j].lincoef != 0.0 )
13357  {
13358  assert(nmonomials < monomialssize);
13359 
13360  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 1) ); /*lint !e866 */
13361 
13362  monomialvars[nmonomials][0] = consdata->quadvarterms[j].var;
13363  monomialexps[nmonomials] = NULL;
13364  monomialcoefs[nmonomials] = consdata->quadvarterms[j].lincoef;
13365  monomialnvars[nmonomials] = 1;
13366  ++nmonomials;
13367  }
13368 
13369  if( consdata->quadvarterms[j].sqrcoef != 0.0 )
13370  {
13371  assert(nmonomials < monomialssize);
13372 
13373  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 1) ); /*lint !e866 */
13374  SCIP_CALL( SCIPallocBufferArray(scip, &monomialexps[nmonomials], 1) ); /*lint !e866 */
13375 
13376  monomialvars[nmonomials][0] = consdata->quadvarterms[j].var;
13377  monomialexps[nmonomials][0] = 2.0;
13378  monomialcoefs[nmonomials] = consdata->quadvarterms[j].sqrcoef;
13379  monomialnvars[nmonomials] = 1;
13380  ++nmonomials;
13381  }
13382  }
13383 
13384  for( j = 0; j < consdata->nbilinterms; ++j )
13385  {
13386  assert(nmonomials < monomialssize);
13387 
13388  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 2) ); /*lint !e866 */
13389 
13390  monomialvars[nmonomials][0] = consdata->bilinterms[j].var1;
13391  monomialvars[nmonomials][1] = consdata->bilinterms[j].var2;
13392  monomialexps[nmonomials] = NULL;
13393  monomialcoefs[nmonomials] = consdata->bilinterms[j].coef;
13394  monomialnvars[nmonomials] = 2;
13395  ++nmonomials;
13396  }
13397 
13398  SCIP_CALL( SCIPwriteVarsPolynomial(scip, file, monomialvars, monomialexps, monomialcoefs, monomialnvars, nmonomials, TRUE) );
13399 
13400  for( j = 0; j < nmonomials; ++j )
13401  {
13402  SCIPfreeBufferArray(scip, &monomialvars[j]);
13403  SCIPfreeBufferArrayNull(scip, &monomialexps[j]);
13404  }
13405 
13406  SCIPfreeBufferArray(scip, &monomialvars);
13407  SCIPfreeBufferArray(scip, &monomialexps);
13408  SCIPfreeBufferArray(scip, &monomialcoefs);
13409  SCIPfreeBufferArray(scip, &monomialnvars);
13410  }
13411 
13412  /* print right hand side */
13413  if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
13414  {
13415  SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
13416  }
13417  else if( !SCIPisInfinity(scip, consdata->rhs) )
13418  {
13419  SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
13420  }
13421  else if( !SCIPisInfinity(scip, -consdata->lhs) )
13422  {
13423  SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
13424  }
13425  else
13426  {
13427  /* should be ignored by parser */
13428  SCIPinfoMessage(scip, file, " [free]");
13429  }
13430 
13431  return SCIP_OKAY;
13432 }
13433 
13434 /** feasibility check method of constraint handler for integral solutions */
13435 static
13436 SCIP_DECL_CONSCHECK(consCheckQuadratic)
13437 { /*lint --e{715}*/
13438  SCIP_CONSHDLRDATA* conshdlrdata;
13439  SCIP_CONSDATA* consdata;
13440  SCIP_Real maxviol;
13441  int c;
13442  SCIP_Bool maypropfeasible; /* whether we may be able to propose a feasible solution */
13443  SCIP_Bool solviolbounds;
13444 
13445  assert(scip != NULL);
13446  assert(conss != NULL || nconss == 0);
13447  assert(result != NULL);
13448 
13449  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13450  assert(conshdlrdata != NULL);
13451 
13452  *result = SCIP_FEASIBLE;
13453 
13454  maxviol = 0.0;
13455  maypropfeasible = conshdlrdata->linfeasshift && (conshdlrdata->trysolheur != NULL) &&
13457  for( c = 0; c < nconss; ++c )
13458  {
13459  assert(conss != NULL);
13460  SCIP_CALL( computeViolation(scip, conss[c], sol, &solviolbounds) );
13461  assert(!solviolbounds); /* see also issue #627 */
13462 
13463  consdata = SCIPconsGetData(conss[c]);
13464  assert(consdata != NULL);
13465 
13466  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
13467  {
13468  *result = SCIP_INFEASIBLE;
13469  if( printreason )
13470  {
13471  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
13472  SCIPinfoMessage(scip, NULL, ";\n");
13473  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
13474  {
13475  SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g (scaled: %.15g)\n", consdata->lhs - consdata->activity, consdata->lhsviol);
13476  }
13477  if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
13478  {
13479  SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g (scaled: %.15g)\n", consdata->activity - consdata->rhs, consdata->rhsviol);
13480  }
13481  }
13482  if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible && !completely )
13483  return SCIP_OKAY;
13484  if( consdata->lhsviol > maxviol || consdata->rhsviol > maxviol )
13485  maxviol = consdata->lhsviol + consdata->rhsviol;
13486 
13487  /* do not try to shift linear variables if activity is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
13488  if( maypropfeasible && SCIPisInfinity(scip, REALABS(consdata->activity)) )
13489  maypropfeasible = FALSE;
13490 
13491  if( maypropfeasible )
13492  {
13493  /* update information on linear variables that may be in- or decreased, if initsolve has not done so yet */
13495  consdataFindUnlockedLinearVar(scip, consdata);
13496 
13497  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
13498  {
13499  /* check if there is a variable which may help to get the left hand side satisfied
13500  * if there is no such var, then we cannot get feasible */
13501  if( !(consdata->linvar_mayincrease >= 0 && consdata->lincoefs[consdata->linvar_mayincrease] > 0.0) &&
13502  ! (consdata->linvar_maydecrease >= 0 && consdata->lincoefs[consdata->linvar_maydecrease] < 0.0) )
13503  maypropfeasible = FALSE;
13504  }
13505  else
13506  {
13507  assert(SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)));
13508  /* check if there is a variable which may help to get the right hand side satisfied
13509  * if there is no such var, then we cannot get feasible */
13510  if( !(consdata->linvar_mayincrease >= 0 && consdata->lincoefs[consdata->linvar_mayincrease] < 0.0) &&
13511  ! (consdata->linvar_maydecrease >= 0 && consdata->lincoefs[consdata->linvar_maydecrease] > 0.0) )
13512  maypropfeasible = FALSE;
13513  }
13514  }
13515  }
13516  }
13517 
13518  if( *result == SCIP_INFEASIBLE && maypropfeasible )
13519  {
13520  SCIP_Bool success;
13521 
13522  SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
13523 
13524  /* do not pass solution to NLP heuristic if we made it feasible this way */
13525  if( success )
13526  return SCIP_OKAY;
13527  }
13528 
13529  if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL && !SCIPisInfinity(scip, maxviol) )
13530  {
13531  SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
13532  }
13533 
13534  return SCIP_OKAY;
13535 }
13536 
13537 /** constraint copying method of constraint handler */
13538 static
13539 SCIP_DECL_CONSCOPY(consCopyQuadratic)
13541  SCIP_CONSDATA* consdata;
13542  SCIP_CONSDATA* targetconsdata;
13543  SCIP_VAR** linvars;
13544  SCIP_QUADVARTERM* quadvarterms;
13545  SCIP_BILINTERM* bilinterms;
13546  int i;
13547  int j;
13548  int k;
13549 
13550  assert(scip != NULL);
13551  assert(cons != NULL);
13552  assert(sourcescip != NULL);
13553  assert(sourceconshdlr != NULL);
13554  assert(sourcecons != NULL);
13555  assert(varmap != NULL);
13556  assert(valid != NULL);
13557 
13558  consdata = SCIPconsGetData(sourcecons);
13559  assert(consdata != NULL);
13560 
13561  linvars = NULL;
13562  quadvarterms = NULL;
13563  bilinterms = NULL;
13564 
13565  *valid = TRUE;
13566 
13567  if( consdata->nlinvars != 0 )
13568  {
13569  SCIP_CALL( SCIPallocBufferArray(sourcescip, &linvars, consdata->nlinvars) );
13570  for( i = 0; i < consdata->nlinvars; ++i )
13571  {
13572  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, consdata->linvars[i], &linvars[i], varmap, consmap, global, valid) );
13573  assert(!(*valid) || linvars[i] != NULL);
13574 
13575  /* we do not copy, if a variable is missing */
13576  if( !(*valid) )
13577  goto TERMINATE;
13578  }
13579  }
13580 
13581  if( consdata->nbilinterms != 0 )
13582  {
13583  SCIP_CALL( SCIPallocBufferArray(sourcescip, &bilinterms, consdata->nbilinterms) );
13584  }
13585 
13586  if( consdata->nquadvars != 0 )
13587  {
13588  SCIP_CALL( SCIPallocBufferArray(sourcescip, &quadvarterms, consdata->nquadvars) );
13589  for( i = 0; i < consdata->nquadvars; ++i )
13590  {
13591  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, consdata->quadvarterms[i].var, &quadvarterms[i].var, varmap, consmap, global, valid) );
13592  assert(!(*valid) || quadvarterms[i].var != NULL);
13593 
13594  /* we do not copy, if a variable is missing */
13595  if( !(*valid) )
13596  goto TERMINATE;
13597 
13598  quadvarterms[i].lincoef = consdata->quadvarterms[i].lincoef;
13599  quadvarterms[i].sqrcoef = consdata->quadvarterms[i].sqrcoef;
13600  quadvarterms[i].eventdata = NULL;
13601  quadvarterms[i].nadjbilin = consdata->quadvarterms[i].nadjbilin;
13602  quadvarterms[i].adjbilin = consdata->quadvarterms[i].adjbilin;
13603 
13604  assert(consdata->nbilinterms != 0 || consdata->quadvarterms[i].nadjbilin == 0);
13605 
13606  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
13607  {
13608  assert(bilinterms != NULL);
13609 
13610  k = consdata->quadvarterms[i].adjbilin[j];
13611  assert(consdata->bilinterms[k].var1 != NULL);
13612  assert(consdata->bilinterms[k].var2 != NULL);
13613  if( consdata->bilinterms[k].var1 == consdata->quadvarterms[i].var )
13614  {
13615  assert(consdata->bilinterms[k].var2 != consdata->quadvarterms[i].var);
13616  bilinterms[k].var1 = quadvarterms[i].var;
13617  }
13618  else
13619  {
13620  assert(consdata->bilinterms[k].var2 == consdata->quadvarterms[i].var);
13621  bilinterms[k].var2 = quadvarterms[i].var;
13622  }
13623  bilinterms[k].coef = consdata->bilinterms[k].coef;
13624  }
13625  }
13626  }
13627 
13628  assert(stickingatnode == FALSE);
13629  SCIP_CALL( SCIPcreateConsQuadratic2(scip, cons, name ? name : SCIPconsGetName(sourcecons),
13630  consdata->nlinvars, linvars, consdata->lincoefs,
13631  consdata->nquadvars, quadvarterms,
13632  consdata->nbilinterms, bilinterms,
13633  consdata->lhs, consdata->rhs,
13634  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
13635 
13636  /* copy information on curvature */
13637  targetconsdata = SCIPconsGetData(*cons);
13638  targetconsdata->isconvex = consdata->isconvex;
13639  targetconsdata->isconcave = consdata->isconcave;
13640  targetconsdata->iscurvchecked = consdata->iscurvchecked;
13641 
13642  TERMINATE:
13643  SCIPfreeBufferArrayNull(sourcescip, &quadvarterms);
13644  SCIPfreeBufferArrayNull(sourcescip, &bilinterms);
13645  SCIPfreeBufferArrayNull(sourcescip, &linvars);
13646 
13647  return SCIP_OKAY;
13648 }
13649 
13650 /** constraint parsing method of constraint handler */
13651 static
13652 SCIP_DECL_CONSPARSE(consParseQuadratic)
13653 { /*lint --e{715}*/
13654  SCIP_VAR*** monomialvars;
13655  SCIP_Real** monomialexps;
13656  SCIP_Real* monomialcoefs;
13657  char* endptr;
13658  int* monomialnvars;
13659  int nmonomials;
13660 
13661  SCIP_Real lhs;
13662  SCIP_Real rhs;
13663 
13664  assert(scip != NULL);
13665  assert(success != NULL);
13666  assert(str != NULL);
13667  assert(name != NULL);
13668  assert(cons != NULL);
13669 
13670  /* set left and right hand side to their default values */
13671  lhs = -SCIPinfinity(scip);
13672  rhs = SCIPinfinity(scip);
13673 
13674  (*success) = FALSE;
13675 
13676  /* return of string empty */
13677  if( !*str )
13678  return SCIP_OKAY;
13679 
13680  /* ignore whitespace */
13681  while( isspace((unsigned char)*str) )
13682  ++str;
13683 
13684  /* check for left hand side */
13685  if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
13686  {
13687  /* there is a number coming, maybe it is a left-hand-side */
13688  if( !SCIPstrToRealValue(str, &lhs, &endptr) )
13689  {
13690  SCIPerrorMessage("error parsing number from <%s>\n", str);
13691  return SCIP_OKAY;
13692  }
13693 
13694  /* ignore whitespace */
13695  while( isspace((unsigned char)*endptr) )
13696  ++endptr;
13697 
13698  if( endptr[0] != '<' || endptr[1] != '=' )
13699  {
13700  /* no '<=' coming, so it was the first coefficient, but not a left-hand-side */
13701  lhs = -SCIPinfinity(scip);
13702  }
13703  else
13704  {
13705  /* it was indeed a left-hand-side, so continue parsing after it */
13706  str = endptr + 2;
13707 
13708  /* ignore whitespace */
13709  while( isspace((unsigned char)*str) )
13710  ++str;
13711  }
13712  }
13713 
13714  SCIP_CALL( SCIPparseVarsPolynomial(scip, str, &monomialvars, &monomialexps, &monomialcoefs, &monomialnvars, &nmonomials, &endptr, success) );
13715 
13716  if( *success )
13717  {
13718  /* check for right hand side */
13719  str = endptr;
13720 
13721  /* ignore whitespace */
13722  while( isspace((unsigned char)*str) )
13723  ++str;
13724 
13725  if( *str && str[0] == '<' && str[1] == '=' )
13726  {
13727  /* we seem to get a right-hand-side */
13728  str += 2;
13729 
13730  if( !SCIPstrToRealValue(str, &rhs, &endptr) )
13731  {
13732  SCIPerrorMessage("error parsing right-hand-side from %s\n", str);
13733  *success = FALSE;
13734  }
13735  }
13736  else if( *str && str[0] == '>' && str[1] == '=' )
13737  {
13738  /* we seem to get a left-hand-side */
13739  str += 2;
13740 
13741  /* we should not have a left-hand-side already */
13742  assert(SCIPisInfinity(scip, -lhs));
13743 
13744  if( !SCIPstrToRealValue(str, &lhs, &endptr) )
13745  {
13746  SCIPerrorMessage("error parsing left-hand-side from %s\n", str);
13747  *success = FALSE;
13748  }
13749  }
13750  else if( *str && str[0] == '=' && str[1] == '=' )
13751  {
13752  /* we seem to get a left- and right-hand-side */
13753  str += 2;
13754 
13755  /* we should not have a left-hand-side already */
13756  assert(SCIPisInfinity(scip, -lhs));
13757 
13758  if( !SCIPstrToRealValue(str, &lhs, &endptr) )
13759  {
13760  SCIPerrorMessage("error parsing left-hand-side from %s\n", str);
13761  *success = FALSE;
13762  }
13763  else
13764  {
13765  rhs = lhs;
13766  }
13767  }
13768  }
13769 
13770  if( *success )
13771  {
13772  int i;
13773 
13774  /* setup constraint */
13775  assert(stickingatnode == FALSE);
13776  SCIP_CALL( SCIPcreateConsQuadratic(scip, cons, name, 0, NULL, NULL,
13777  0, NULL, NULL, NULL, lhs, rhs,
13778  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
13779 
13780  for( i = 0; i < nmonomials; ++i )
13781  {
13782  if( monomialnvars[i] == 0 )
13783  {
13784  /* constant monomial */
13785  SCIPaddConstantQuadratic(scip, *cons, monomialcoefs[i]);
13786  }
13787  else if( monomialnvars[i] == 1 && monomialexps[i][0] == 1.0 )
13788  {
13789  /* linear monomial */
13790  SCIP_CALL( SCIPaddLinearVarQuadratic(scip, *cons, monomialvars[i][0], monomialcoefs[i]) );
13791  }
13792  else if( monomialnvars[i] == 1 && monomialexps[i][0] == 2.0 )
13793  {
13794  /* square monomial */
13795  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, monomialvars[i][0], 0.0, monomialcoefs[i]) );
13796  }
13797  else if( monomialnvars[i] == 2 && monomialexps[i][0] == 1.0 && monomialexps[i][1] == 1.0 )
13798  {
13799  /* bilinear term */
13800  SCIP_VAR* var1;
13801  SCIP_VAR* var2;
13802  int pos;
13803 
13804  var1 = monomialvars[i][0];
13805  var2 = monomialvars[i][1];
13806  if( var1 == var2 )
13807  {
13808  /* actually a square term */
13809  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, var1, 0.0, monomialcoefs[i]) );
13810  }
13811  else
13812  {
13813  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, *cons, var1, &pos) );
13814  if( pos == -1 )
13815  {
13816  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, var1, 0.0, 0.0) );
13817  }
13818 
13819  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, *cons, var2, &pos) );
13820  if( pos == -1 )
13821  {
13822  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, var2, 0.0, 0.0) );
13823  }
13824  }
13825 
13826  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, *cons, var1, var2, monomialcoefs[i]) );
13827  }
13828  else
13829  {
13830  SCIPerrorMessage("polynomial in quadratic constraint does not have degree at most 2\n");
13831  *success = FALSE;
13832  SCIP_CALL( SCIPreleaseCons(scip, cons) );
13833  break;
13834  }
13835  }
13836  }
13837 
13838  SCIPfreeParseVarsPolynomialData(scip, &monomialvars, &monomialexps, &monomialcoefs, &monomialnvars, nmonomials);
13839 
13840  return SCIP_OKAY;
13841 }
13842 
13843 /** constraint method of constraint handler which returns the variables (if possible) */
13844 static
13845 SCIP_DECL_CONSGETVARS(consGetVarsQuadratic)
13846 { /*lint --e{715}*/
13847  SCIP_CONSDATA* consdata;
13848 
13849  assert(cons != NULL);
13850  assert(success != NULL);
13851 
13852  consdata = SCIPconsGetData(cons);
13853  assert(consdata != NULL);
13854 
13855  if( varssize < consdata->nlinvars + consdata->nquadvars )
13856  (*success) = FALSE;
13857  else
13858  {
13859  int i;
13860 
13861  assert(vars != NULL);
13862 
13863  BMScopyMemoryArray(vars, consdata->linvars, consdata->nlinvars);
13864 
13865  for( i = 0; i < consdata->nquadvars; ++i )
13866  vars[consdata->nlinvars+i] = consdata->quadvarterms[i].var;
13867 
13868  (*success) = TRUE;
13869  }
13870 
13871  return SCIP_OKAY;
13872 }
13873 
13874 /** constraint method of constraint handler which returns the number of variables (if possible) */
13875 static
13876 SCIP_DECL_CONSGETNVARS(consGetNVarsQuadratic)
13877 { /*lint --e{715}*/
13878  SCIP_CONSDATA* consdata;
13879 
13880  assert(cons != NULL);
13881  assert(success != NULL);
13882 
13883  consdata = SCIPconsGetData(cons);
13884  assert(consdata != NULL);
13885 
13886  (*nvars) = consdata->nlinvars + consdata->nquadvars;
13887  (*success) = TRUE;
13888 
13889  return SCIP_OKAY;
13890 }
13891 
13892 
13893 /*
13894  * constraint specific interface methods
13895  */
13896 
13897 /** creates the handler for quadratic constraints and includes it in SCIP */
13899  SCIP* scip /**< SCIP data structure */
13900  )
13901 {
13902  SCIP_CONSHDLRDATA* conshdlrdata;
13903  SCIP_CONSHDLR* conshdlr;
13904 
13905  /* create quadratic constraint handler data */
13906  SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
13907  BMSclearMemory(conshdlrdata);
13908 
13909  /* include constraint handler */
13912  consEnfolpQuadratic, consEnfopsQuadratic, consCheckQuadratic, consLockQuadratic,
13913  conshdlrdata) );
13914  assert(conshdlr != NULL);
13915 
13916 
13917  /* set non-fundamental callbacks via specific setter functions */
13918  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyQuadratic, consCopyQuadratic) );
13919  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteQuadratic) );
13920  SCIP_CALL( SCIPsetConshdlrDisable(scip, conshdlr, consDisableQuadratic) );
13921  SCIP_CALL( SCIPsetConshdlrEnable(scip, conshdlr, consEnableQuadratic) );
13922  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitQuadratic) );
13923  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreQuadratic) );
13924  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolQuadratic) );
13925  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeQuadratic) );
13926  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsQuadratic) );
13927  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsQuadratic) );
13928  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitQuadratic) );
13929  SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolQuadratic) );
13930  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpQuadratic) );
13931  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseQuadratic) );
13932  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolQuadratic, CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
13933  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintQuadratic) );
13934  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropQuadratic, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
13936  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpQuadratic, consSepasolQuadratic, CONSHDLR_SEPAFREQ,
13938  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransQuadratic) );
13939  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxQuadratic) );
13940 
13941  /* add quadratic constraint handler parameters */
13942  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/replacebinaryprod",
13943  "max. length of linear term which when multiplied with a binary variables is replaced by an auxiliary variable and a linear reformulation (0 to turn off)",
13944  &conshdlrdata->replacebinaryprodlength, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
13945 
13946  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/empathy4and",
13947  "empathy level for using the AND constraint handler: 0 always avoid using AND; 1 use AND sometimes; 2 use AND as often as possible",
13948  &conshdlrdata->empathy4and, FALSE, 0, 0, 2, NULL, NULL) );
13949 
13950  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/binreforminitial",
13951  "whether to make non-varbound linear constraints added due to replacing products with binary variables initial",
13952  &conshdlrdata->binreforminitial, TRUE, FALSE, NULL, NULL) );
13953 
13954  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/binreformbinaryonly",
13955  "whether to consider only binary variables when replacing products with binary variables",
13956  &conshdlrdata->binreformbinaryonly, FALSE, TRUE, NULL, NULL) );
13957 
13958  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/binreformmaxcoef",
13959  "limit (as factor on 1/feastol) on coefficients and coef. range in linear constraints created when replacing products with binary variables",
13960  &conshdlrdata->binreformmaxcoef, TRUE, 1e-4, 0.0, SCIPinfinity(scip), NULL, NULL) );
13961 
13962  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/cutmaxrange",
13963  "maximal coef range of a cut (maximal coefficient divided by minimal coefficient) in order to be added to LP relaxation",
13964  &conshdlrdata->cutmaxrange, TRUE, 1e+7, 0.0, SCIPinfinity(scip), NULL, NULL) );
13965 
13966  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/mincurvcollectbilinterms",
13967  "minimal curvature of constraints to be considered when returning bilinear terms to other plugins",
13968  &conshdlrdata->mincurvcollectbilinterms, TRUE, 0.8, -SCIPinfinity(scip), SCIPinfinity(scip), NULL, NULL) );
13969 
13970  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/linearizeheursol",
13971  "whether linearizations of convex quadratic constraints should be added to cutpool in a solution found by some heuristic",
13972  &conshdlrdata->linearizeheursol, TRUE, TRUE, NULL, NULL) );
13973 
13974  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/checkcurvature",
13975  "whether multivariate quadratic functions should be checked for convexity/concavity",
13976  &conshdlrdata->checkcurvature, FALSE, TRUE, NULL, NULL) );
13977 
13978  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/checkfactorable",
13979  "whether constraint functions should be checked to be factorable",
13980  &conshdlrdata->checkfactorable, TRUE, TRUE, NULL, NULL) );
13981 
13982  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/checkquadvarlocks",
13983  "whether quadratic variables contained in a single constraint should be forced to be at their lower or upper bounds ('d'isable, change 't'ype, add 'b'ound disjunction)",
13984  &conshdlrdata->checkquadvarlocks, TRUE, 't', "bdt", NULL, NULL) );
13985 
13986  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/linfeasshift",
13987  "whether to try to make solutions in check function feasible by shifting a linear variable (esp. useful if constraint was actually objective function)",
13988  &conshdlrdata->linfeasshift, TRUE, TRUE, NULL, NULL) );
13989 
13990  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxdisaggrsize",
13991  "maximum number of created constraints when disaggregating a quadratic constraint (<= 1: off)",
13992  &conshdlrdata->maxdisaggrsize, FALSE, 1, 1, INT_MAX, NULL, NULL) );
13993 
13994  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/disaggrmergemethod",
13995  "strategy how to merge independent blocks to reach maxdisaggrsize limit (keep 'b'iggest blocks and merge others; keep 's'mallest blocks and merge other; merge small blocks into bigger blocks to reach 'm'ean sizes)",
13996  &conshdlrdata->disaggrmergemethod, TRUE, 'm', "bms", NULL, NULL) );
13997 
13998  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
13999  "limit on number of propagation rounds for a single constraint within one round of SCIP propagation during solve",
14000  &conshdlrdata->maxproprounds, TRUE, 1, 0, INT_MAX, NULL, NULL) );
14001 
14002  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproproundspresolve",
14003  "limit on number of propagation rounds for a single constraint within one round of SCIP presolve",
14004  &conshdlrdata->maxproproundspresolve, TRUE, 10, 0, INT_MAX, NULL, NULL) );
14005 
14006  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/enfolplimit",
14007  "maximum number of enforcement rounds before declaring the LP relaxation infeasible (-1: no limit); WARNING: changing this parameter might lead to incorrect results!",
14008  &conshdlrdata->enfolplimit, TRUE, -1, -1, INT_MAX, NULL, NULL) );
14009 
14010  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/sepanlpmincont",
14011  "minimal required fraction of continuous variables in problem to use solution of NLP relaxation in root for separation",
14012  &conshdlrdata->sepanlpmincont, FALSE, 1.0, 0.0, 2.0, NULL, NULL) );
14013 
14014  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/enfocutsremovable",
14015  "are cuts added during enforcement removable from the LP in the same node?",
14016  &conshdlrdata->enfocutsremovable, TRUE, FALSE, NULL, NULL) );
14017 
14018  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/gaugecuts",
14019  "should convex quadratics generated strong cuts via gauge function?",
14020  &conshdlrdata->gaugecuts, FALSE, TRUE, NULL, NULL) );
14021 
14022  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/interiorcomputation",
14023  "how the interior point for gauge cuts should be computed: 'a'ny point per constraint, 'm'ost interior per constraint",
14024  &conshdlrdata->interiorcomputation, TRUE, 'a', "am", NULL, NULL) );
14025 
14026  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/projectedcuts",
14027  "should convex quadratics generated strong cuts via projections?",
14028  &conshdlrdata->projectedcuts, FALSE, FALSE, NULL, NULL) );
14029 
14030  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branchscoring",
14031  "which score to give branching candidates: convexification 'g'ap, constraint 'v'iolation, 'c'entrality of variable value in domain",
14032  &conshdlrdata->branchscoring, TRUE, 'g', "cgv", NULL, NULL) );
14033 
14034  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/usebilinineqbranch",
14035  "should linear inequalities be consindered when computing the branching scores for bilinear terms?",
14036  &conshdlrdata->usebilinineqbranch, FALSE, FALSE, NULL, NULL) );
14037 
14038  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/minscorebilinterms",
14039  "minimal required score in order to use linear inequalities for tighter bilinear relaxations",
14040  &conshdlrdata->minscorebilinterms, FALSE, 0.01, 0.0, 1.0, NULL, NULL) );
14041 
14042  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/bilinineqmaxseparounds",
14043  "maximum number of separation rounds to use linear inequalities for the bilinear term relaxation in a local node",
14044  &conshdlrdata->bilinineqmaxseparounds, TRUE, 3, 0, INT_MAX, NULL, NULL) );
14045 
14046  conshdlrdata->eventhdlr = NULL;
14047  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlr),CONSHDLR_NAME"_boundchange", "signals a bound change to a quadratic constraint",
14048  processVarEvent, NULL) );
14049  assert(conshdlrdata->eventhdlr != NULL);
14050 
14051  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME"_newsolution", "handles the event that a new primal solution has been found",
14052  processNewSolutionEvent, NULL) );
14053 
14054  /* include the quadratic constraint upgrade in the nonlinear constraint handler */
14055  SCIP_CALL( SCIPincludeNonlinconsUpgrade(scip, nonlinconsUpgdQuadratic, NULL, NONLINCONSUPGD_PRIORITY, TRUE, CONSHDLR_NAME) );
14056 
14057  return SCIP_OKAY;
14058 }
14059 
14060 /** includes a quadratic constraint update method into the quadratic constraint handler */
14062  SCIP* scip, /**< SCIP data structure */
14063  SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), /**< method to call for upgrading quadratic constraint */
14064  int priority, /**< priority of upgrading method */
14065  SCIP_Bool active, /**< should the upgrading method be active by default? */
14066  const char* conshdlrname /**< name of the constraint handler */
14067  )
14068 {
14069  SCIP_CONSHDLR* conshdlr;
14070  SCIP_CONSHDLRDATA* conshdlrdata;
14071  SCIP_QUADCONSUPGRADE* quadconsupgrade;
14072  char paramname[SCIP_MAXSTRLEN];
14073  char paramdesc[SCIP_MAXSTRLEN];
14074  int i;
14075 
14076  assert(quadconsupgd != NULL);
14077  assert(conshdlrname != NULL );
14078 
14079  /* find the quadratic constraint handler */
14080  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14081  if( conshdlr == NULL )
14082  {
14083  SCIPerrorMessage("quadratic constraint handler not found\n");
14084  return SCIP_PLUGINNOTFOUND;
14085  }
14086 
14087  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14088  assert(conshdlrdata != NULL);
14089 
14090  if( !conshdlrdataHasUpgrade(scip, conshdlrdata, quadconsupgd, conshdlrname) )
14091  {
14092  /* create a quadratic constraint upgrade data object */
14093  SCIP_CALL( SCIPallocBlockMemory(scip, &quadconsupgrade) );
14094  quadconsupgrade->quadconsupgd = quadconsupgd;
14095  quadconsupgrade->priority = priority;
14096  quadconsupgrade->active = active;
14097 
14098  /* insert quadratic constraint upgrade method into constraint handler data */
14099  assert(conshdlrdata->nquadconsupgrades <= conshdlrdata->quadconsupgradessize);
14100  if( conshdlrdata->nquadconsupgrades+1 > conshdlrdata->quadconsupgradessize )
14101  {
14102  int newsize;
14103 
14104  newsize = SCIPcalcMemGrowSize(scip, conshdlrdata->nquadconsupgrades+1);
14105  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->quadconsupgrades, conshdlrdata->quadconsupgradessize, newsize) );
14106  conshdlrdata->quadconsupgradessize = newsize;
14107  }
14108  assert(conshdlrdata->nquadconsupgrades+1 <= conshdlrdata->quadconsupgradessize);
14109 
14110  for( i = conshdlrdata->nquadconsupgrades; i > 0 && conshdlrdata->quadconsupgrades[i-1]->priority < quadconsupgrade->priority; --i )
14111  conshdlrdata->quadconsupgrades[i] = conshdlrdata->quadconsupgrades[i-1];
14112  assert(0 <= i && i <= conshdlrdata->nquadconsupgrades);
14113  conshdlrdata->quadconsupgrades[i] = quadconsupgrade;
14114  conshdlrdata->nquadconsupgrades++;
14115 
14116  /* adds parameter to turn on and off the upgrading step */
14117  (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
14118  (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable quadratic upgrading for constraint handler <%s>", conshdlrname);
14120  paramname, paramdesc,
14121  &quadconsupgrade->active, FALSE, active, NULL, NULL) );
14122  }
14123 
14124  return SCIP_OKAY;
14125 }
14126 
14127 /** Creates and captures a quadratic constraint.
14128  *
14129  * The constraint should be given in the form
14130  * \f[
14131  * \ell \leq \sum_{i=1}^n b_i x_i + \sum_{j=1}^m a_j y_j z_j \leq u,
14132  * \f]
14133  * where \f$x_i = y_j = z_k\f$ is possible.
14134  *
14135  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
14136  */
14138  SCIP* scip, /**< SCIP data structure */
14139  SCIP_CONS** cons, /**< pointer to hold the created constraint */
14140  const char* name, /**< name of constraint */
14141  int nlinvars, /**< number of linear terms (n) */
14142  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
14143  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
14144  int nquadterms, /**< number of quadratic terms (m) */
14145  SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms (y_j) */
14146  SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms (z_j) */
14147  SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms (a_j) */
14148  SCIP_Real lhs, /**< left hand side of quadratic equation (ell) */
14149  SCIP_Real rhs, /**< right hand side of quadratic equation (u) */
14150  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
14151  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
14152  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
14153  * Usually set to TRUE. */
14154  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
14155  * TRUE for model constraints, FALSE for additional, redundant constraints. */
14156  SCIP_Bool check, /**< should the constraint be checked for feasibility?
14157  * TRUE for model constraints, FALSE for additional, redundant constraints. */
14158  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
14159  * Usually set to TRUE. */
14160  SCIP_Bool local, /**< is constraint only valid locally?
14161  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
14162  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
14163  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
14164  * adds coefficients to this constraint. */
14165  SCIP_Bool dynamic, /**< is constraint subject to aging?
14166  * Usually set to FALSE. Set to TRUE for own cuts which
14167  * are separated as constraints. */
14168  SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
14169  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
14170  )
14171 {
14172  SCIP_CONSHDLR* conshdlr;
14173  SCIP_CONSDATA* consdata;
14174  SCIP_HASHMAP* quadvaridxs;
14175  SCIP_Real sqrcoef;
14176  int i;
14177  int var1pos;
14178  int var2pos;
14179 
14180  int nbilinterms;
14181 
14182  assert(linvars != NULL || nlinvars == 0);
14183  assert(lincoefs != NULL || nlinvars == 0);
14184  assert(quadvars1 != NULL || nquadterms == 0);
14185  assert(quadvars2 != NULL || nquadterms == 0);
14186  assert(quadcoefs != NULL || nquadterms == 0);
14187 
14188  assert(modifiable == FALSE); /* we do not support column generation */
14189 
14190  /* find the quadratic constraint handler */
14191  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14192  if( conshdlr == NULL )
14193  {
14194  SCIPerrorMessage("quadratic constraint handler not found\n");
14195  return SCIP_PLUGINNOTFOUND;
14196  }
14197 
14198  /* create constraint data and constraint */
14199  SCIP_CALL( consdataCreateEmpty(scip, &consdata) );
14200 
14201  consdata->lhs = lhs;
14202  consdata->rhs = rhs;
14203 
14204  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
14205  local, modifiable, dynamic, removable, FALSE) );
14206 
14207  /* add quadratic variables and remember their indices */
14208  SCIP_CALL( SCIPhashmapCreate(&quadvaridxs, SCIPblkmem(scip), nquadterms) );
14209  nbilinterms = 0;
14210  for( i = 0; i < nquadterms; ++i )
14211  {
14212  if( SCIPisZero(scip, quadcoefs[i]) ) /*lint !e613*/
14213  continue;
14214 
14215  /* if it is actually a square term, remember it's coefficient */
14216  /* cppcheck-suppress nullPointer */
14217  if( quadvars1[i] == quadvars2[i] ) /*lint !e613*/
14218  sqrcoef = quadcoefs[i]; /*lint !e613 */
14219  else
14220  sqrcoef = 0.0;
14221 
14222  /* add quadvars1[i], if not in there already */
14223  if( !SCIPhashmapExists(quadvaridxs, quadvars1[i]) ) /*lint !e613*/
14224  {
14225  SCIP_CALL( addQuadVarTerm(scip, *cons, quadvars1[i], 0.0, sqrcoef) ); /*lint !e613*/
14226  assert(consdata->nquadvars >= 0);
14227  assert(consdata->quadvarterms[consdata->nquadvars-1].var == quadvars1[i]); /*lint !e613*/
14228 
14229  SCIP_CALL( SCIPhashmapInsert(quadvaridxs, quadvars1[i], (void*)(size_t)(consdata->nquadvars-1)) ); /*lint !e613*/
14230  }
14231  else if( !SCIPisZero(scip, sqrcoef) )
14232  {
14233  /* if it's there already, but we got a square coefficient, add it to the previous one */
14234  var1pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, quadvars1[i]); /*lint !e613*/
14235  assert(consdata->quadvarterms[var1pos].var == quadvars1[i]); /*lint !e613*/
14236  consdata->quadvarterms[var1pos].sqrcoef += sqrcoef;
14237  }
14238 
14239  /* cppcheck-suppress nullPointer */
14240  if( quadvars1[i] == quadvars2[i] ) /*lint !e613*/
14241  continue;
14242 
14243  /* add quadvars2[i], if not in there already */
14244  if( !SCIPhashmapExists(quadvaridxs, quadvars2[i]) ) /*lint !e613*/
14245  {
14246  assert(sqrcoef == 0.0);
14247  SCIP_CALL( addQuadVarTerm(scip, *cons, quadvars2[i], 0.0, 0.0) ); /*lint !e613*/
14248  assert(consdata->nquadvars >= 0);
14249  assert(consdata->quadvarterms[consdata->nquadvars-1].var == quadvars2[i]); /*lint !e613*/
14250 
14251  SCIP_CALL( SCIPhashmapInsert(quadvaridxs, quadvars2[i], (void*)(size_t)(consdata->nquadvars-1)) ); /*lint !e613*/
14252  }
14253 
14254  ++nbilinterms;
14255  }
14256 
14257  /* add bilinear terms, if we saw any */
14258  if( nbilinterms > 0 )
14259  {
14260  SCIP_CALL( consdataEnsureBilinSize(scip, consdata, nbilinterms) );
14261  for( i = 0; i < nquadterms; ++i )
14262  {
14263  if( SCIPisZero(scip, quadcoefs[i]) ) /*lint !e613*/
14264  continue;
14265 
14266  /* square terms have been taken care of already */
14267  if( quadvars1[i] == quadvars2[i] ) /*lint !e613 */
14268  continue;
14269 
14270  assert(SCIPhashmapExists(quadvaridxs, quadvars1[i])); /*lint !e613*/
14271  assert(SCIPhashmapExists(quadvaridxs, quadvars2[i])); /*lint !e613*/
14272 
14273  var1pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, quadvars1[i]); /*lint !e613*/
14274  var2pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, quadvars2[i]); /*lint !e613*/
14275 
14276  SCIP_CALL( addBilinearTerm(scip, *cons, var1pos, var2pos, quadcoefs[i]) ); /*lint !e613*/
14277  }
14278  }
14279 
14280  /* add linear variables */
14281  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, nlinvars) );
14282  for( i = 0; i < nlinvars; ++i )
14283  {
14284  if( SCIPisZero(scip, lincoefs[i]) ) /*lint !e613*/
14285  continue;
14286 
14287  /* if it's a linear coefficient for a quadratic variable, add it there, otherwise add as linear variable */
14288  if( SCIPhashmapExists(quadvaridxs, linvars[i]) ) /*lint !e613*/
14289  {
14290  var1pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, linvars[i]); /*lint !e613*/
14291  assert(consdata->quadvarterms[var1pos].var == linvars[i]); /*lint !e613*/
14292  consdata->quadvarterms[var1pos].lincoef += lincoefs[i]; /*lint !e613*/
14293  }
14294  else
14295  {
14296  SCIP_CALL( addLinearCoef(scip, *cons, linvars[i], lincoefs[i]) ); /*lint !e613*/
14297  }
14298  }
14299 
14300  SCIPhashmapFree(&quadvaridxs);
14301 
14302  SCIPdebugMsg(scip, "created quadratic constraint ");
14303  SCIPdebugPrintCons(scip, *cons, NULL);
14304 
14305  return SCIP_OKAY;
14306 }
14307 
14308 /** creates and captures a quadratic constraint with all its
14309  * flags set to their default values.
14310  *
14311  * The constraint should be given in the form
14312  * \f[
14313  * \ell \leq \sum_{i=1}^n b_i x_i + \sum_{j=1}^m a_j y_j z_j \leq u,
14314  * \f]
14315  * where \f$x_i = y_j = z_k\f$ is possible.
14316  *
14317  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
14318  */
14320  SCIP* scip, /**< SCIP data structure */
14321  SCIP_CONS** cons, /**< pointer to hold the created constraint */
14322  const char* name, /**< name of constraint */
14323  int nlinvars, /**< number of linear terms (n) */
14324  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
14325  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
14326  int nquadterms, /**< number of quadratic terms (m) */
14327  SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms (y_j) */
14328  SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms (z_j) */
14329  SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms (a_j) */
14330  SCIP_Real lhs, /**< left hand side of quadratic equation (ell) */
14331  SCIP_Real rhs /**< right hand side of quadratic equation (u) */
14332  )
14333 {
14334  SCIP_CALL( SCIPcreateConsQuadratic(scip, cons, name, nlinvars, linvars, lincoefs,
14335  nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
14336  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
14337 
14338  return SCIP_OKAY;
14339 }
14340 
14341 /** Creates and captures a quadratic constraint.
14342  *
14343  * The constraint should be given in the form
14344  * \f[
14345  * \ell \leq \sum_{i=1}^n b_i x_i + \sum_{j=1}^m (a_j y_j^2 + b_j y_j) + \sum_{k=1}^p c_k v_k w_k \leq u.
14346  * \f]
14347  *
14348  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
14349  */
14351  SCIP* scip, /**< SCIP data structure */
14352  SCIP_CONS** cons, /**< pointer to hold the created constraint */
14353  const char* name, /**< name of constraint */
14354  int nlinvars, /**< number of linear terms (n) */
14355  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
14356  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
14357  int nquadvarterms, /**< number of quadratic terms (m) */
14358  SCIP_QUADVARTERM* quadvarterms, /**< quadratic variable terms */
14359  int nbilinterms, /**< number of bilinear terms (p) */
14360  SCIP_BILINTERM* bilinterms, /**< bilinear terms */
14361  SCIP_Real lhs, /**< constraint left hand side (ell) */
14362  SCIP_Real rhs, /**< constraint right hand side (u) */
14363  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? */
14364  SCIP_Bool separate, /**< should the constraint be separated during LP processing? */
14365  SCIP_Bool enforce, /**< should the constraint be enforced during node processing? */
14366  SCIP_Bool check, /**< should the constraint be checked for feasibility? */
14367  SCIP_Bool propagate, /**< should the constraint be propagated during node processing? */
14368  SCIP_Bool local, /**< is constraint only valid locally? */
14369  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)? */
14370  SCIP_Bool dynamic, /**< is constraint dynamic? */
14371  SCIP_Bool removable /**< should the constraint be removed from the LP due to aging or cleanup? */
14372  )
14373 {
14374  SCIP_CONSHDLR* conshdlr;
14375  SCIP_CONSDATA* consdata;
14376 
14377  assert(modifiable == FALSE); /* we do not support column generation */
14378  assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
14379  assert(nquadvarterms == 0 || quadvarterms != NULL);
14380  assert(nbilinterms == 0 || bilinterms != NULL);
14381 
14382  /* find the quadratic constraint handler */
14383  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14384  if( conshdlr == NULL )
14385  {
14386  SCIPerrorMessage("quadratic constraint handler not found\n");
14387  return SCIP_PLUGINNOTFOUND;
14388  }
14389 
14390  /* create constraint data */
14391  SCIP_CALL( consdataCreate(scip, &consdata, lhs, rhs,
14392  nlinvars, linvars, lincoefs, nquadvarterms, quadvarterms, nbilinterms, bilinterms,
14393  TRUE) );
14394 
14395  /* create constraint */
14396  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
14397  local, modifiable, dynamic, removable, FALSE) );
14398 
14399  return SCIP_OKAY;
14400 }
14401 
14402 /** creates and captures a quadratic constraint in its most basic version, i.e.,
14403  * all constraint flags are set to their default values.
14404  *
14405  * The constraint should be given in the form
14406  * \f[
14407  * \ell \leq \sum_{i=1}^n b_i x_i + \sum_{j=1}^m (a_j y_j^2 + b_j y_j) + \sum_{k=1}^p c_k v_k w_k \leq u.
14408  * \f]
14409  *
14410  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
14411  */
14413  SCIP* scip, /**< SCIP data structure */
14414  SCIP_CONS** cons, /**< pointer to hold the created constraint */
14415  const char* name, /**< name of constraint */
14416  int nlinvars, /**< number of linear terms (n) */
14417  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
14418  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
14419  int nquadvarterms, /**< number of quadratic terms (m) */
14420  SCIP_QUADVARTERM* quadvarterms, /**< quadratic variable terms */
14421  int nbilinterms, /**< number of bilinear terms (p) */
14422  SCIP_BILINTERM* bilinterms, /**< bilinear terms */
14423  SCIP_Real lhs, /**< constraint left hand side (ell) */
14424  SCIP_Real rhs /**< constraint right hand side (u) */
14425  )
14426 {
14427  SCIP_CALL( SCIPcreateConsQuadratic2(scip, cons, name, nlinvars, linvars, lincoefs,
14428  nquadvarterms, quadvarterms, nbilinterms, bilinterms, lhs, rhs,
14429  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
14430 
14431  return SCIP_OKAY;
14432 }
14433 
14434 
14435 /** Adds a constant to the constraint function, that is, subtracts a constant from both sides */
14437  SCIP* scip, /**< SCIP data structure */
14438  SCIP_CONS* cons, /**< constraint */
14439  SCIP_Real constant /**< constant to subtract from both sides */
14440  )
14441 {
14442  SCIP_CONSDATA* consdata;
14443 
14444  assert(scip != NULL);
14445  assert(cons != NULL);
14446  assert(!SCIPisInfinity(scip, REALABS(constant)));
14447 
14448  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
14449  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
14450  {
14451  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
14452  SCIPABORT();
14453  }
14454 
14455  consdata = SCIPconsGetData(cons);
14456  assert(consdata != NULL);
14457  assert(consdata->lhs <= consdata->rhs);
14458 
14459  if( !SCIPisInfinity(scip, -consdata->lhs) )
14460  consdata->lhs -= constant;
14461  if( !SCIPisInfinity(scip, consdata->rhs) )
14462  consdata->rhs -= constant;
14463 
14464  if( consdata->lhs > consdata->rhs )
14465  {
14466  assert(SCIPisEQ(scip, consdata->lhs, consdata->rhs));
14467  consdata->lhs = consdata->rhs;
14468  }
14469 }
14470 
14471 /** Adds a linear variable with coefficient to a quadratic constraint. */
14473  SCIP* scip, /**< SCIP data structure */
14474  SCIP_CONS* cons, /**< constraint */
14475  SCIP_VAR* var, /**< variable */
14476  SCIP_Real coef /**< coefficient of variable */
14477  )
14478 {
14479  assert(scip != NULL);
14480  assert(cons != NULL);
14481  assert(var != NULL);
14482  assert(!SCIPisInfinity(scip, REALABS(coef)));
14483 
14484  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
14485  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
14486  {
14487  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
14488  return SCIP_INVALIDCALL;
14489  }
14490 
14491  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
14492 
14493  return SCIP_OKAY;
14494 }
14495 
14496 /** Adds a quadratic variable with linear and square coefficient to a quadratic constraint. */
14498  SCIP* scip, /**< SCIP data structure */
14499  SCIP_CONS* cons, /**< constraint */
14500  SCIP_VAR* var, /**< variable */
14501  SCIP_Real lincoef, /**< linear coefficient of variable */
14502  SCIP_Real sqrcoef /**< square coefficient of variable */
14503  )
14504 {
14505  assert(scip != NULL);
14506  assert(cons != NULL);
14507  assert(var != NULL);
14508  assert(!SCIPisInfinity(scip, REALABS(lincoef)));
14509  assert(!SCIPisInfinity(scip, REALABS(sqrcoef)));
14510 
14511  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
14512  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
14513  {
14514  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
14515  return SCIP_INVALIDCALL;
14516  }
14517 
14518  SCIP_CALL( addQuadVarTerm(scip, cons, var, lincoef, sqrcoef) );
14519 
14520  return SCIP_OKAY;
14521 }
14522 
14523 /** Adds a linear coefficient for a quadratic variable.
14524  *
14525  * Variable will be added with square coefficient 0.0 if not existing yet.
14526  */
14528  SCIP* scip, /**< SCIP data structure */
14529  SCIP_CONS* cons, /**< constraint */
14530  SCIP_VAR* var, /**< variable */
14531  SCIP_Real coef /**< value to add to linear coefficient of variable */
14532  )
14533 {
14534  SCIP_CONSDATA* consdata;
14535  int pos;
14536 
14537  assert(scip != NULL);
14538  assert(cons != NULL);
14539  assert(var != NULL);
14540  assert(!SCIPisInfinity(scip, REALABS(coef)));
14541 
14542  if( SCIPisZero(scip, coef) )
14543  return SCIP_OKAY;
14544 
14545  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
14546  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
14547  {
14548  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
14549  return SCIP_INVALIDCALL;
14550  }
14551 
14552  consdata = SCIPconsGetData(cons);
14553  assert(consdata != NULL);
14554 
14555  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var, &pos) );
14556  if( pos < 0 )
14557  {
14558  SCIP_CALL( addQuadVarTerm(scip, cons, var, coef, 0.0) );
14559  return SCIP_OKAY;
14560  }
14561  assert(pos < consdata->nquadvars);
14562  assert(consdata->quadvarterms[pos].var == var);
14563 
14564  consdata->quadvarterms[pos].lincoef += coef;
14565 
14566  /* update flags and invalid activities */
14567  consdata->ispropagated = FALSE;
14568  consdata->ispresolved = consdata->ispresolved && !SCIPisZero(scip, consdata->quadvarterms[pos].lincoef);
14569 
14570  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
14571  consdata->activity = SCIP_INVALID;
14572 
14573  return SCIP_OKAY;
14574 }
14575 
14576 /** Adds a square coefficient for a quadratic variable.
14577  *
14578  * Variable will be added with linear coefficient 0.0 if not existing yet.
14579  */
14581  SCIP* scip, /**< SCIP data structure */
14582  SCIP_CONS* cons, /**< constraint */
14583  SCIP_VAR* var, /**< variable */
14584  SCIP_Real coef /**< value to add to square coefficient of variable */
14585  )
14586 {
14587  SCIP_CONSDATA* consdata;
14588  int pos;
14589 
14590  assert(scip != NULL);
14591  assert(cons != NULL);
14592  assert(var != NULL);
14593  assert(!SCIPisInfinity(scip, REALABS(coef)));
14594 
14595  if( SCIPisZero(scip, coef) )
14596  return SCIP_OKAY;
14597 
14598  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
14599  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
14600  {
14601  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
14602  return SCIP_INVALIDCALL;
14603  }
14604 
14605  consdata = SCIPconsGetData(cons);
14606  assert(consdata != NULL);
14607 
14608  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var, &pos) );
14609  if( pos < 0 )
14610  {
14611  SCIP_CALL( addQuadVarTerm(scip, cons, var, 0.0, coef) );
14612  return SCIP_OKAY;
14613  }
14614  assert(pos < consdata->nquadvars);
14615  assert(consdata->quadvarterms[pos].var == var);
14616 
14617  consdata->quadvarterms[pos].sqrcoef += coef;
14618 
14619  /* update flags and invalid activities */
14620  consdata->isconvex = FALSE;
14621  consdata->isconcave = FALSE;
14622  consdata->iscurvchecked = FALSE;
14623  consdata->ispropagated = FALSE;
14624  consdata->ispresolved = consdata->ispresolved && !SCIPisZero(scip, consdata->quadvarterms[pos].sqrcoef);
14625 
14626  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
14627  consdata->activity = SCIP_INVALID;
14628 
14629  return SCIP_OKAY;
14630 }
14631 
14632 /** Adds a bilinear term to a quadratic constraint.
14633  *
14634  * Variables will be added with linear and square coefficient 0.0 if not existing yet.
14635  * If variables are equal, only the square coefficient of the variable is updated.
14636  */
14638  SCIP* scip, /**< SCIP data structure */
14639  SCIP_CONS* cons, /**< constraint */
14640  SCIP_VAR* var1, /**< first variable */
14641  SCIP_VAR* var2, /**< second variable */
14642  SCIP_Real coef /**< coefficient of bilinear term */
14643  )
14644 {
14645  SCIP_CONSDATA* consdata;
14646  int var1pos;
14647  int var2pos;
14648 
14649  assert(scip != NULL);
14650  assert(cons != NULL);
14651  assert(var1 != NULL);
14652  assert(var2 != NULL);
14653  assert(!SCIPisInfinity(scip, REALABS(coef)));
14654 
14655  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
14656  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
14657  {
14658  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
14659  return SCIP_INVALIDCALL;
14660  }
14661 
14662  if( var1 == var2 )
14663  {
14664  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, cons, var1, coef) );
14665  return SCIP_OKAY;
14666  }
14667 
14668  consdata = SCIPconsGetData(cons);
14669  assert(consdata != NULL);
14670 
14671  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var1, &var1pos) );
14672  if( var1pos < 0 )
14673  {
14674  SCIP_CALL( addQuadVarTerm(scip, cons, var1, 0.0, 0.0) );
14675  var1pos = consdata->nquadvars-1;
14676  }
14677 
14678  if( !consdata->quadvarssorted )
14679  {
14680  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
14681  /* sorting may change the position of var1 */
14682  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var1, &var1pos) );
14683  assert(var1pos >= 0);
14684  }
14685 
14686  assert(consdata->quadvarssorted);
14687  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var2, &var2pos) );
14688  if( var2pos < 0 )
14689  {
14690  SCIP_CALL( addQuadVarTerm(scip, cons, var2, 0.0, 0.0) );
14691  var2pos = consdata->nquadvars-1;
14692  }
14693 
14694  assert(consdata->quadvarterms[var1pos].var == var1);
14695  assert(consdata->quadvarterms[var2pos].var == var2);
14696 
14697  SCIP_CALL( addBilinearTerm(scip, cons, var1pos, var2pos, coef) );
14698 
14699  return SCIP_OKAY;
14700 }
14701 
14702 /** Gets the quadratic constraint as a nonlinear row representation. */
14704  SCIP* scip, /**< SCIP data structure */
14705  SCIP_CONS* cons, /**< constraint */
14706  SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
14707  )
14708 {
14709  SCIP_CONSDATA* consdata;
14710 
14711  assert(cons != NULL);
14712  assert(nlrow != NULL);
14713 
14714  consdata = SCIPconsGetData(cons);
14715  assert(consdata != NULL);
14716 
14717  if( consdata->nlrow == NULL )
14718  {
14719  SCIP_CALL( createNlRow(scip, cons) );
14720  }
14721  assert(consdata->nlrow != NULL);
14722  *nlrow = consdata->nlrow;
14723 
14724  return SCIP_OKAY;
14725 }
14726 
14727 /** Gets the number of variables in the linear term of a quadratic constraint. */
14729  SCIP* scip, /**< SCIP data structure */
14730  SCIP_CONS* cons /**< constraint */
14731  )
14732 {
14733  assert(cons != NULL);
14734  assert(SCIPconsGetData(cons) != NULL);
14735 
14736  return SCIPconsGetData(cons)->nlinvars;
14737 }
14738 
14739 /** Gets the variables in the linear part of a quadratic constraint.
14740  * Length is given by SCIPgetNLinearVarsQuadratic.
14741  */
14743  SCIP* scip, /**< SCIP data structure */
14744  SCIP_CONS* cons /**< constraint */
14745  )
14746 {
14747  assert(cons != NULL);
14748  assert(SCIPconsGetData(cons) != NULL);
14749 
14750  return SCIPconsGetData(cons)->linvars;
14751 }
14752 
14753 /** Gets the coefficients in the linear part of a quadratic constraint.
14754  * Length is given by SCIPgetNLinearVarsQuadratic.
14755  */
14757  SCIP* scip, /**< SCIP data structure */
14758  SCIP_CONS* cons /**< constraint */
14759  )
14760 {
14761  assert(cons != NULL);
14762  assert(SCIPconsGetData(cons) != NULL);
14763 
14764  return SCIPconsGetData(cons)->lincoefs;
14765 }
14766 
14767 /** Gets the number of quadratic variable terms of a quadratic constraint.
14768  */
14770  SCIP* scip, /**< SCIP data structure */
14771  SCIP_CONS* cons /**< constraint */
14772  )
14773 {
14774  assert(cons != NULL);
14775  assert(SCIPconsGetData(cons) != NULL);
14776 
14777  return SCIPconsGetData(cons)->nquadvars;
14778 }
14779 
14780 /** Gets the quadratic variable terms of a quadratic constraint.
14781  * Length is given by SCIPgetNQuadVarTermsQuadratic.
14782  */
14784  SCIP* scip, /**< SCIP data structure */
14785  SCIP_CONS* cons /**< constraint */
14786  )
14787 {
14788  assert(cons != NULL);
14789  assert(SCIPconsGetData(cons) != NULL);
14790 
14791  return SCIPconsGetData(cons)->quadvarterms;
14792 }
14793 
14794 /** Ensures that quadratic variable terms are sorted. */
14796  SCIP* scip, /**< SCIP data structure */
14797  SCIP_CONS* cons /**< constraint */
14798  )
14799 {
14800  assert(cons != NULL);
14801  assert(SCIPconsGetData(cons) != NULL);
14802 
14804 
14805  return SCIP_OKAY;
14806 }
14807 
14808 /** Finds the position of a quadratic variable term for a given variable.
14809  *
14810  * @note If the quadratic variable terms have not been sorted before, then a search may reorder the current order of the terms.
14811  */
14813  SCIP* scip, /**< SCIP data structure */
14814  SCIP_CONS* cons, /**< constraint */
14815  SCIP_VAR* var, /**< variable to search for */
14816  int* pos /**< buffer to store position of quadvarterm for var, or -1 if not found */
14817  )
14818 {
14819  assert(cons != NULL);
14820  assert(SCIPconsGetData(cons) != NULL);
14821  assert(var != NULL);
14822  assert(pos != NULL);
14823 
14824  SCIP_CALL( consdataFindQuadVarTerm(scip, SCIPconsGetData(cons), var, pos) );
14825 
14826  return SCIP_OKAY;
14827 }
14828 
14829 /** Gets the number of bilinear terms of a quadratic constraint. */
14831  SCIP* scip, /**< SCIP data structure */
14832  SCIP_CONS* cons /**< constraint */
14833  )
14834 {
14835  assert(cons != NULL);
14836  assert(SCIPconsGetData(cons) != NULL);
14837 
14838  return SCIPconsGetData(cons)->nbilinterms;
14839 }
14840 
14841 /** Gets the bilinear terms of a quadratic constraint.
14842  * Length is given by SCIPgetNBilinTermQuadratic.
14843  */
14845  SCIP* scip, /**< SCIP data structure */
14846  SCIP_CONS* cons /**< constraint */
14847  )
14848 {
14849  assert(cons != NULL);
14850  assert(SCIPconsGetData(cons) != NULL);
14851 
14852  return SCIPconsGetData(cons)->bilinterms;
14853 }
14854 
14855 /** Gets the left hand side of a quadratic constraint. */
14857  SCIP* scip, /**< SCIP data structure */
14858  SCIP_CONS* cons /**< constraint */
14859  )
14860 {
14861  assert(cons != NULL);
14862  assert(SCIPconsGetData(cons) != NULL);
14863 
14864  return SCIPconsGetData(cons)->lhs;
14865 }
14866 
14867 /** Gets the right hand side of a quadratic constraint. */
14869  SCIP* scip, /**< SCIP data structure */
14870  SCIP_CONS* cons /**< constraint */
14871  )
14872 {
14873  assert(cons != NULL);
14874  assert(SCIPconsGetData(cons) != NULL);
14875 
14876  return SCIPconsGetData(cons)->rhs;
14877 }
14878 
14879 /** get index of a variable in linvars that may be decreased without making any other constraint infeasible, or -1 if none */
14881  SCIP* scip, /**< SCIP data structure */
14882  SCIP_CONS* cons /**< constraint */
14883  )
14884 {
14885  SCIP_CONSDATA* consdata;
14886 
14887  assert(cons != NULL);
14888 
14889  consdata = SCIPconsGetData(cons);
14890  assert(consdata != NULL);
14891 
14892  /* check for a linear variable that can be increase or decreased without harming feasibility */
14893  consdataFindUnlockedLinearVar(scip, consdata);
14894 
14895  return consdata->linvar_maydecrease;
14896 }
14897 
14898 /** get index of a variable in linvars that may be increased without making any other constraint infeasible, or -1 if none */
14900  SCIP* scip, /**< SCIP data structure */
14901  SCIP_CONS* cons /**< constraint */
14902  )
14903 {
14904  SCIP_CONSDATA* consdata;
14905 
14906  assert(cons != NULL);
14907 
14908  consdata = SCIPconsGetData(cons);
14909  assert(consdata != NULL);
14910 
14911  /* check for a linear variable that can be increase or decreased without harming feasibility */
14912  consdataFindUnlockedLinearVar(scip, consdata);
14913 
14914  return consdata->linvar_mayincrease;
14915 }
14916 
14917 /** Check the quadratic function of a quadratic constraint for its semi-definiteness, if not done yet. */
14919  SCIP* scip, /**< SCIP data structure */
14920  SCIP_CONS* cons /**< constraint */
14921  )
14922 {
14923  assert(cons != NULL);
14924 
14925  SCIP_CALL( checkCurvature(scip, cons, TRUE) );
14926 
14927  return SCIP_OKAY;
14928 }
14929 
14930 /** Indicates whether the quadratic function of a quadratic constraint is (known to be) convex. */
14932  SCIP* scip, /**< SCIP data structure */
14933  SCIP_CONS* cons /**< constraint */
14934  )
14935 {
14936  SCIP_Bool determined;
14937 
14938  assert(cons != NULL);
14939  assert(SCIPconsGetData(cons) != NULL);
14940 
14941  checkCurvatureEasy(scip, cons, &determined, FALSE);
14942  assert(determined);
14943 
14944  return (SCIPconsGetData(cons)->isconvex);
14945 }
14946 
14947 /** Indicates whether the quadratic function of a quadratic constraint is (known to be) concave. */
14949  SCIP* scip, /**< SCIP data structure */
14950  SCIP_CONS* cons /**< constraint */
14951  )
14952 {
14953  SCIP_Bool determined;
14954 
14955  assert(cons != NULL);
14956  assert(SCIPconsGetData(cons) != NULL);
14957 
14958  checkCurvatureEasy(scip, cons, &determined, FALSE);
14959  assert(determined);
14960 
14961  return (SCIPconsGetData(cons)->isconcave);
14962 }
14963 
14964 /** Computes the violation of a constraint by a solution */
14966  SCIP* scip, /**< SCIP data structure */
14967  SCIP_CONS* cons, /**< constraint */
14968  SCIP_SOL* sol, /**< solution which violation to calculate, or NULL for LP solution */
14969  SCIP_Real* violation /**< pointer to store violation of constraint */
14970  )
14971 {
14972  SCIP_CONSDATA* consdata;
14973  SCIP_Bool solviolbounds;
14974 
14975  assert(scip != NULL);
14976  assert(cons != NULL);
14977  assert(violation != NULL);
14978 
14979  SCIP_CALL( computeViolation(scip, cons, sol, &solviolbounds) );
14980  /* we don't care here whether the solution violated variable bounds */
14981 
14982  consdata = SCIPconsGetData(cons);
14983  assert(consdata != NULL);
14984 
14985  *violation = MAX(consdata->lhsviol, consdata->rhsviol);
14986 
14987  return SCIP_OKAY;
14988 }
14989 
14990 /** Indicates whether the quadratic constraint is local w.r.t. the current local bounds.
14991  *
14992  * That is, checks whether each variable with a square term is fixed and for each bilinear term at least one variable is fixed.
14993  */
14995  SCIP* scip, /**< SCIP data structure */
14996  SCIP_CONS* cons /**< constraint */
14997  )
14998 {
14999  SCIP_CONSDATA* consdata;
15000  SCIP_VAR* var1;
15001  SCIP_VAR* var2;
15002  int i;
15003 
15004  assert(scip != NULL);
15005  assert(cons != NULL);
15006 
15007  consdata = SCIPconsGetData(cons);
15008  assert(consdata != NULL);
15009 
15010  /* check all square terms */
15011  for( i = 0; i < consdata->nquadvars; ++i )
15012  {
15013  if( consdata->quadvarterms[i].sqrcoef == 0.0 )
15014  continue;
15015 
15016  var1 = consdata->quadvarterms[i].var;
15017  assert(var1 != NULL);
15018 
15019  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var1), SCIPvarGetUbLocal(var1)) )
15020  return FALSE;
15021  }
15022 
15023  for( i = 0; i < consdata->nbilinterms; ++i )
15024  {
15025  var1 = consdata->bilinterms[i].var1;
15026  var2 = consdata->bilinterms[i].var2;
15027 
15028  assert(var1 != NULL);
15029  assert(var2 != NULL);
15030 
15031  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var1), SCIPvarGetUbLocal(var1)) &&
15032  ! SCIPisRelEQ(scip, SCIPvarGetLbLocal(var2), SCIPvarGetUbLocal(var2)) )
15033  return FALSE;
15034  }
15035 
15036  return TRUE;
15037 }
15038 
15039 /** Adds the constraint to an NLPI problem. */
15041  SCIP* scip, /**< SCIP data structure */
15042  SCIP_CONS* cons, /**< constraint */
15043  SCIP_NLPI* nlpi, /**< interface to NLP solver */
15044  SCIP_NLPIPROBLEM* nlpiprob, /**< NLPI problem where to add constraint */
15045  SCIP_HASHMAP* scipvar2nlpivar, /**< mapping from SCIP variables to variable indices in NLPI */
15046  SCIP_Bool names /**< whether to pass constraint names to NLPI */
15047  )
15048 {
15049  SCIP_CONSDATA* consdata;
15050  int nlininds;
15051  int* lininds;
15052  SCIP_Real* linvals;
15053  int nquadelems;
15054  SCIP_QUADELEM* quadelems;
15055  SCIP_VAR* othervar;
15056  const char* name;
15057  int j;
15058  int l;
15059  int lincnt;
15060  int quadcnt;
15061  int idx1;
15062  int idx2;
15063 
15064  assert(scip != NULL);
15065  assert(cons != NULL);
15066  assert(nlpi != NULL);
15067  assert(nlpiprob != NULL);
15068  assert(scipvar2nlpivar != NULL);
15069 
15070  consdata = SCIPconsGetData(cons);
15071  assert(consdata != NULL);
15072 
15073  /* count nonzeros in quadratic part */
15074  nlininds = consdata->nlinvars;
15075  nquadelems = consdata->nbilinterms;
15076  for( j = 0; j < consdata->nquadvars; ++j )
15077  {
15078  if( consdata->quadvarterms[j].sqrcoef != 0.0 )
15079  ++nquadelems;
15080  if( consdata->quadvarterms[j].lincoef != 0.0 )
15081  ++nlininds;
15082  }
15083 
15084  /* setup linear part */
15085  lininds = NULL;
15086  linvals = NULL;
15087  lincnt = 0;
15088  if( nlininds > 0 )
15089  {
15090  SCIP_CALL( SCIPallocBufferArray(scip, &lininds, nlininds) );
15091  SCIP_CALL( SCIPallocBufferArray(scip, &linvals, nlininds) );
15092 
15093  for( j = 0; j < consdata->nlinvars; ++j )
15094  {
15095  linvals[j] = consdata->lincoefs[j];
15096  assert(SCIPhashmapExists(scipvar2nlpivar, consdata->linvars[j]));
15097  lininds[j] = (int) (size_t) SCIPhashmapGetImage(scipvar2nlpivar, consdata->linvars[j]);
15098  }
15099 
15100  lincnt = consdata->nlinvars;
15101  }
15102 
15103  /* setup quadratic part */
15104  quadelems = NULL;
15105  if( nquadelems > 0 )
15106  {
15107  SCIP_CALL( SCIPallocBufferArray(scip, &quadelems, nquadelems) );
15108  }
15109  quadcnt = 0;
15110 
15111  for( j = 0; j < consdata->nquadvars; ++j )
15112  {
15113  assert(SCIPhashmapExists(scipvar2nlpivar, consdata->quadvarterms[j].var));
15114  idx1 = (int)(size_t)SCIPhashmapGetImage(scipvar2nlpivar, consdata->quadvarterms[j].var);
15115  if( consdata->quadvarterms[j].lincoef != 0.0 )
15116  {
15117  assert(lininds != NULL);
15118  assert(linvals != NULL);
15119  lininds[lincnt] = idx1;
15120  linvals[lincnt] = consdata->quadvarterms[j].lincoef;
15121  ++lincnt;
15122  }
15123 
15124  if( consdata->quadvarterms[j].sqrcoef != 0.0 )
15125  {
15126  assert(quadcnt < nquadelems);
15127  assert(quadelems != NULL);
15128  quadelems[quadcnt].idx1 = idx1;
15129  quadelems[quadcnt].idx2 = idx1;
15130  quadelems[quadcnt].coef = consdata->quadvarterms[j].sqrcoef;
15131  ++quadcnt;
15132  }
15133 
15134  for( l = 0; l < consdata->quadvarterms[j].nadjbilin; ++l )
15135  {
15136  othervar = consdata->bilinterms[consdata->quadvarterms[j].adjbilin[l]].var2;
15137  /* if othervar is on position 2, then we process this bilinear term later (or it was processed already) */
15138  if( othervar == consdata->quadvarterms[j].var )
15139  continue;
15140 
15141  assert(quadcnt < nquadelems);
15142  assert(quadelems != NULL);
15143  assert(SCIPhashmapExists(scipvar2nlpivar, othervar));
15144  idx2 = (int)(size_t)SCIPhashmapGetImage(scipvar2nlpivar, othervar);
15145  quadelems[quadcnt].idx1 = MIN(idx1, idx2);
15146  quadelems[quadcnt].idx2 = MAX(idx1, idx2);
15147  quadelems[quadcnt].coef = consdata->bilinterms[consdata->quadvarterms[j].adjbilin[l]].coef;
15148  ++quadcnt;
15149  }
15150  }
15151 
15152  assert(quadcnt == nquadelems);
15153  assert(lincnt == nlininds);
15154 
15155  name = names ? SCIPconsGetName(cons) : NULL;
15156 
15157  SCIP_CALL( SCIPnlpiAddConstraints(nlpi, nlpiprob, 1,
15158  &consdata->lhs, &consdata->rhs,
15159  &nlininds, &lininds, &linvals ,
15160  &nquadelems, &quadelems,
15161  NULL, NULL, &name) );
15162 
15163  SCIPfreeBufferArrayNull(scip, &quadelems);
15164  SCIPfreeBufferArrayNull(scip, &lininds);
15165  SCIPfreeBufferArrayNull(scip, &linvals);
15166 
15167  return SCIP_OKAY;
15168 }
15169 
15170 
15171 /** sets the left hand side of a quadratic constraint
15172  *
15173  * @note This method may only be called during problem creation stage for an original constraint.
15174  */
15176  SCIP* scip, /**< SCIP data structure */
15177  SCIP_CONS* cons, /**< constraint data */
15178  SCIP_Real lhs /**< new left hand side */
15179  )
15180 {
15181  SCIP_CONSDATA* consdata;
15182 
15183  assert(scip != NULL);
15184  assert(cons != NULL);
15185  assert(!SCIPisInfinity(scip, lhs));
15186 
15187  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
15188  {
15189  SCIPerrorMessage("constraint is not quadratic\n");
15190  return SCIP_INVALIDDATA;
15191  }
15192 
15193  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) )
15194  {
15195  SCIPerrorMessage("method may only be called during problem creation stage for original constraints\n");
15196  return SCIP_INVALIDDATA;
15197  }
15198 
15199  consdata = SCIPconsGetData(cons);
15200  assert(consdata != NULL);
15201  assert(!SCIPisInfinity(scip, consdata->lhs));
15202 
15203  /* adjust value to not be smaller than -inf */
15204  if( SCIPisInfinity(scip, -lhs) )
15205  lhs = -SCIPinfinity(scip);
15206 
15207  /* check for lhs <= rhs */
15208  if( !SCIPisLE(scip, lhs, consdata->rhs) )
15209  return SCIP_INVALIDDATA;
15210 
15211  consdata->lhs = lhs;
15212 
15213  return SCIP_OKAY;
15214 }
15215 
15216 /** sets the right hand side of a quadratic constraint
15217  *
15218  * @note This method may only be called during problem creation stage for an original constraint.
15219  */
15221  SCIP* scip, /**< SCIP data structure */
15222  SCIP_CONS* cons, /**< constraint data */
15223  SCIP_Real rhs /**< new right hand side */
15224  )
15225 {
15226  SCIP_CONSDATA* consdata;
15227 
15228  assert(scip != NULL);
15229  assert(cons != NULL);
15230  assert(!SCIPisInfinity(scip, -rhs));
15231 
15232  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
15233  {
15234  SCIPerrorMessage("constraint is not quadratic\n");
15235  return SCIP_INVALIDDATA;
15236  }
15237 
15238  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) )
15239  {
15240  SCIPerrorMessage("method may only be called during problem creation stage for original constraints\n");
15241  return SCIP_INVALIDDATA;
15242  }
15243 
15244  consdata = SCIPconsGetData(cons);
15245  assert(consdata != NULL);
15246  assert(!SCIPisInfinity(scip, -consdata->rhs));
15247 
15248  /* adjust value to not be greater than inf */
15249  if( SCIPisInfinity(scip, rhs) )
15250  rhs = SCIPinfinity(scip);
15251 
15252  /* check for lhs <= rhs */
15253  if( !SCIPisLE(scip, consdata->lhs, rhs) )
15254  return SCIP_INVALIDDATA;
15255 
15256  consdata->rhs = rhs;
15257 
15258  return SCIP_OKAY;
15259 }
15260 
15261 /** gets the feasibility of the quadratic constraint in the given solution */
15263  SCIP* scip, /**< SCIP data structure */
15264  SCIP_CONS* cons, /**< constraint data */
15265  SCIP_SOL* sol, /**< solution, or NULL to use current node's solution */
15266  SCIP_Real* feasibility /**< pointer to store the feasibility */
15267  )
15268 {
15269  SCIP_CONSDATA* consdata;
15270  SCIP_Bool solviolbounds;
15271 
15272  assert(scip != NULL);
15273  assert(cons != NULL);
15274  assert(feasibility != NULL);
15275 
15276  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
15277  {
15278  SCIPerrorMessage("constraint is not quadratic\n");
15279  SCIPABORT();
15280  }
15281 
15282  SCIP_CALL( computeViolation(scip, cons, sol, &solviolbounds) );
15283 
15284  consdata = SCIPconsGetData(cons);
15285  assert(consdata != NULL);
15286 
15287  if( SCIPisInfinity(scip, consdata->rhs) && SCIPisInfinity(scip, -consdata->lhs) )
15288  *feasibility = SCIPinfinity(scip);
15289  else if( SCIPisInfinity(scip, -consdata->lhs) )
15290  *feasibility = (consdata->rhs - consdata->activity);
15291  else if( SCIPisInfinity(scip, consdata->rhs) )
15292  *feasibility = (consdata->activity - consdata->lhs);
15293  else
15294  {
15295  assert(!SCIPisInfinity(scip, -consdata->rhs));
15296  assert(!SCIPisInfinity(scip, consdata->lhs));
15297  *feasibility = MIN( consdata->rhs - consdata->activity, consdata->activity - consdata->lhs );
15298  }
15299 
15300  return SCIP_OKAY;
15301 }
15302 
15303 /** gets the activity of the quadratic constraint in the given solution */
15305  SCIP* scip, /**< SCIP data structure */
15306  SCIP_CONS* cons, /**< constraint data */
15307  SCIP_SOL* sol, /**< solution, or NULL to use current node's solution */
15308  SCIP_Real* activity /**< pointer to store the activity */
15309  )
15310 {
15311  SCIP_CONSDATA* consdata;
15312  SCIP_Bool solviolbounds;
15313 
15314  assert(scip != NULL);
15315  assert(cons != NULL);
15316  assert(activity != NULL);
15317 
15318  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
15319  {
15320  SCIPerrorMessage("constraint is not quadratic\n");
15321  SCIPABORT();
15322  }
15323 
15324  SCIP_CALL( computeViolation(scip, cons, sol, &solviolbounds) );
15325 
15326  consdata = SCIPconsGetData(cons);
15327  assert(consdata != NULL);
15328 
15329  *activity = consdata->activity;
15330 
15331  return SCIP_OKAY;
15332 }
15333 
15334 /** changes the linear coefficient value for a given quadratic variable in a quadratic constraint data; if not
15335  * available, it adds it
15336  *
15337  * @note this is only allowed for original constraints and variables in problem creation stage
15338  */
15340  SCIP* scip, /**< SCIP data structure */
15341  SCIP_CONS* cons, /**< constraint data */
15342  SCIP_VAR* var, /**< quadratic variable */
15343  SCIP_Real coef /**< new coefficient */
15344  )
15345 {
15346  SCIP_CONSDATA* consdata;
15347  SCIP_Bool found;
15348  int i;
15349 
15350  assert(scip != NULL);
15351  assert(cons != NULL);
15352  assert(var != NULL);
15353 
15354  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
15355  {
15356  SCIPerrorMessage("constraint is not quadratic\n");
15357  return SCIP_INVALIDDATA;
15358  }
15359 
15360  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) || !SCIPvarIsOriginal(var) )
15361  {
15362  SCIPerrorMessage("method may only be called during problem creation stage for original constraints and variables\n");
15363  return SCIP_INVALIDDATA;
15364  }
15365 
15366  consdata = SCIPconsGetData(cons);
15367  assert(consdata != NULL);
15368 
15369  /* check all quadratic variables */
15370  found = FALSE;
15371  for( i = 0; i < consdata->nquadvars; ++i )
15372  {
15373  if( var == consdata->quadvarterms[i].var )
15374  {
15375  if( found || SCIPisZero(scip, coef) )
15376  {
15377  consdata->quadvarterms[i].lincoef = 0.0;
15378 
15379  /* remember to merge quadratic variable terms */
15380  consdata->quadvarsmerged = FALSE;
15381  }
15382  else
15383  consdata->quadvarterms[i].lincoef = coef;
15384 
15385  found = TRUE;
15386  }
15387  }
15388 
15389  /* check all linear variables */
15390  i = 0;
15391  while( i < consdata->nlinvars )
15392  {
15393  if( var == consdata->linvars[i] )
15394  {
15395  if( found || SCIPisZero(scip, coef) )
15396  {
15397  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
15398 
15399  /* decrease i by one since otherwise we would skip the coefficient which has been switched to position i */
15400  i--;
15401  }
15402  else
15403  {
15404  SCIP_CALL( chgLinearCoefPos(scip, cons, i, coef) );
15405  }
15406 
15407  found = TRUE;
15408  }
15409  i++;
15410  }
15411 
15412  /* add linear term if necessary */
15413  if( !found && !SCIPisZero(scip, coef) )
15414  {
15415  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
15416  }
15417 
15418  consdata->ispropagated = FALSE;
15419  consdata->ispresolved = FALSE;
15420 
15421  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
15422  consdata->activity = SCIP_INVALID;
15423 
15424  return SCIP_OKAY;
15425 }
15426 
15427 /** changes the square coefficient value for a given quadratic variable in a quadratic constraint data; if not
15428  * available, it adds it
15429  *
15430  * @note this is only allowed for original constraints and variables in problem creation stage
15431  */
15433  SCIP* scip, /**< SCIP data structure */
15434  SCIP_CONS* cons, /**< constraint data */
15435  SCIP_VAR* var, /**< quadratic variable */
15436  SCIP_Real coef /**< new coefficient */
15437  )
15438 {
15439  SCIP_CONSDATA* consdata;
15440  SCIP_Bool found;
15441  int i;
15442 
15443  assert(scip != NULL);
15444  assert(cons != NULL);
15445  assert(var != NULL);
15446  assert(!SCIPisInfinity(scip, REALABS(coef)));
15447 
15448  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
15449  {
15450  SCIPerrorMessage("constraint is not quadratic\n");
15451  return SCIP_INVALIDDATA;
15452  }
15453 
15454  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) || !SCIPvarIsOriginal(var) )
15455  {
15456  SCIPerrorMessage("method may only be called during problem creation stage for original constraints and variables\n");
15457  return SCIP_INVALIDDATA;
15458  }
15459 
15460  consdata = SCIPconsGetData(cons);
15461  assert(consdata != NULL);
15462 
15463  /* find the quadratic variable and change its quadratic coefficient */
15464  found = FALSE;
15465  for( i = 0; i < consdata->nquadvars; ++i )
15466  {
15467  if( var == consdata->quadvarterms[i].var )
15468  {
15469  consdata->quadvarterms[i].sqrcoef = (found || SCIPisZero(scip, coef)) ? 0.0 : coef;
15470  found = TRUE;
15471  }
15472  }
15473 
15474  /* add bilinear term if necessary */
15475  if( !found && !SCIPisZero(scip, coef) )
15476  {
15477  SCIP_CALL( addQuadVarTerm(scip, cons, var, 0.0, coef) );
15478  }
15479 
15480  /* update flags and invalidate activities */
15481  consdata->isconvex = FALSE;
15482  consdata->isconcave = FALSE;
15483  consdata->iscurvchecked = FALSE;
15484  consdata->ispropagated = FALSE;
15485  consdata->ispresolved = FALSE;
15486 
15487  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
15488  consdata->activity = SCIP_INVALID;
15489 
15490  /* remember to merge quadratic variable terms */
15491  consdata->quadvarsmerged = FALSE;
15492 
15493  return SCIP_OKAY;
15494 }
15495 
15496 /** changes the bilinear coefficient value for a given quadratic variable in a quadratic constraint data; if not
15497  * available, it adds it
15498  *
15499  * @note this is only allowed for original constraints and variables in problem creation stage
15500  */
15502  SCIP* scip, /**< SCIP data structure */
15503  SCIP_CONS* cons, /**< constraint */
15504  SCIP_VAR* var1, /**< first variable */
15505  SCIP_VAR* var2, /**< second variable */
15506  SCIP_Real coef /**< coefficient of bilinear term */
15507  )
15508 {
15509  SCIP_CONSDATA* consdata;
15510  SCIP_Bool found;
15511  int i;
15512 
15513  assert(scip != NULL);
15514  assert(cons != NULL);
15515  assert(var1 != NULL);
15516  assert(var2 != NULL);
15517  assert(!SCIPisInfinity(scip, REALABS(coef)));
15518 
15519  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
15520  {
15521  SCIPerrorMessage("constraint is not quadratic\n");
15522  return SCIP_INVALIDDATA;
15523  }
15524 
15525  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) || !SCIPvarIsOriginal(var1) || !SCIPvarIsOriginal(var2) )
15526  {
15527  SCIPerrorMessage("method may only be called during problem creation stage for original constraints and variables\n");
15528  return SCIP_INVALIDDATA;
15529  }
15530 
15531  if( var1 == var2 )
15532  {
15533  SCIP_CALL( SCIPchgSquareCoefQuadratic(scip, cons, var1, coef) );
15534  return SCIP_OKAY;
15535  }
15536 
15537  consdata = SCIPconsGetData(cons);
15538  assert(consdata != NULL);
15539 
15540  /* search array of bilinear terms */
15541  found = FALSE;
15542  for( i = 0; i < consdata->nbilinterms; ++i )
15543  {
15544  if( (consdata->bilinterms[i].var1 == var1 && consdata->bilinterms[i].var2 == var2) ||
15545  (consdata->bilinterms[i].var1 == var2 && consdata->bilinterms[i].var2 == var1) )
15546  {
15547  if( found || SCIPisZero(scip, coef) )
15548  {
15549  consdata->bilinterms[i].coef = 0.0;
15550 
15551  /* remember to merge bilinear terms */
15552  consdata->bilinmerged = FALSE;
15553  }
15554  else
15555  consdata->bilinterms[i].coef = coef;
15556  found = TRUE;
15557  }
15558  }
15559 
15560  /* add bilinear term if necessary */
15561  if( !found )
15562  {
15563  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, cons, var1, var2, coef) );
15564  }
15565 
15566  /* update flags and invalidate activities */
15567  consdata->isconvex = FALSE;
15568  consdata->isconcave = FALSE;
15569  consdata->iscurvchecked = FALSE;
15570  consdata->ispropagated = FALSE;
15571  consdata->ispresolved = FALSE;
15572 
15573  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
15574  consdata->activity = SCIP_INVALID;
15575 
15576  return SCIP_OKAY;
15577 }
15578 
15579 /** returns the total number of bilinear terms that are contained in all quadratic constraints */
15581  SCIP* scip /**< SCIP data structure */
15582  )
15583 {
15584  SCIP_CONSHDLRDATA* conshdlrdata;
15585  SCIP_CONSHDLR* conshdlr;
15586 
15587  assert(scip != NULL);
15588 
15589  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
15590 
15591  if( conshdlr == NULL )
15592  return 0;
15593 
15594  conshdlrdata = SCIPconshdlrGetData(conshdlr);
15595  assert(conshdlrdata != NULL);
15596 
15597  return conshdlrdata->nbilinterms;
15598 }
15599 
15600 /** returns all bilinear terms that are contained in all quadratic constraints */
15602  SCIP* scip, /**< SCIP data structure */
15603  SCIP_VAR** RESTRICT x, /**< array to store first variable of each bilinear term */
15604  SCIP_VAR** RESTRICT y, /**< array to second variable of each bilinear term */
15605  int* RESTRICT nbilinterms, /**< buffer to store the total number of bilinear terms */
15606  int* RESTRICT nunderests, /**< array to store the total number of constraints that require to underestimate a bilinear term */
15607  int* RESTRICT noverests, /**< array to store the total number of constraints that require to overestimate a bilinear term */
15608  SCIP_Real* maxnonconvexity /**< largest absolute value of nonconvex eigenvalues of all quadratic constraints containing a bilinear term */
15609  )
15610 {
15611  SCIP_CONSHDLRDATA* conshdlrdata;
15612  SCIP_CONSHDLR* conshdlr;
15613  int i;
15614 
15615  assert(scip != NULL);
15616  assert(x != NULL);
15617  assert(y != NULL);
15618  assert(nbilinterms != NULL);
15619  assert(nunderests != NULL);
15620  assert(noverests!= NULL);
15621  assert(maxnonconvexity != NULL);
15622 
15623  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
15624 
15625  if( conshdlr == NULL )
15626  {
15627  *nbilinterms = 0;
15628  return SCIP_OKAY;
15629  }
15630 
15631  conshdlrdata = SCIPconshdlrGetData(conshdlr);
15632  assert(conshdlrdata != NULL);
15633 
15634  for( i = 0; i < conshdlrdata->nbilinterms; ++i )
15635  {
15636  x[i] = conshdlrdata->bilinestimators[i].x;
15637  y[i] = conshdlrdata->bilinestimators[i].y;
15638  nunderests[i] = conshdlrdata->bilinestimators[i].nunderest;
15639  noverests[i] = conshdlrdata->bilinestimators[i].noverest;
15640  maxnonconvexity[i] = conshdlrdata->bilinestimators[i].maxnonconvexity;
15641  }
15642 
15643  *nbilinterms = conshdlrdata->nbilinterms;
15644 
15645  return SCIP_OKAY;
15646 }
15647 
15648 /** helper function to compute the violation of an inequality of the form xcoef * x <= ycoef * y + constant for two
15649  * corner points of the domain [lbx,ubx]x[lby,uby]
15650  */
15651 static
15652 void getIneqViol(
15653  SCIP_VAR* x, /**< first variable */
15654  SCIP_VAR* y, /**< second variable */
15655  SCIP_Real xcoef, /**< x-coefficient */
15656  SCIP_Real ycoef, /**< y-coefficient */
15657  SCIP_Real constant, /**< constant */
15658  SCIP_Real* viol1, /**< buffer to store the violation of the first corner point */
15659  SCIP_Real* viol2 /**< buffer to store the violation of the second corner point */
15660  )
15661 {
15662  SCIP_Real norm;
15663 
15664  assert(viol1 != NULL);
15665  assert(viol2 != NULL);
15666 
15667  norm = SQRT(SQR(xcoef) + SQR(ycoef));
15668 
15669  /* inequality can be used for underestimating xy if and only if xcoef * ycoef > 0 */
15670  if( xcoef * ycoef >= 0 )
15671  {
15672  /* violation for top-left and bottom-right corner */
15673  *viol1 = MAX(0, (xcoef * SCIPvarGetLbLocal(x) - ycoef * SCIPvarGetUbLocal(y) - constant) / norm); /*lint !e666*/
15674  *viol2 = MAX(0, (xcoef * SCIPvarGetUbLocal(x) - ycoef * SCIPvarGetLbLocal(y) - constant) / norm); /*lint !e666*/
15675  }
15676  else
15677  {
15678  /* violation for top-right and bottom-left corner */
15679  *viol1 = MAX(0, (xcoef * SCIPvarGetUbLocal(x) - ycoef * SCIPvarGetUbLocal(y) - constant) / norm); /*lint !e666*/
15680  *viol2 = MAX(0, (xcoef * SCIPvarGetLbLocal(x) - ycoef * SCIPvarGetLbLocal(y) - constant) / norm); /*lint !e666*/
15681  }
15682 
15683  return;
15684 }
15685 
15686 /** adds a globally valid inequality of the form xcoef x <= ycoef y + constant for a bilinear term (x,y)
15687  *
15688  * @note the indices of bilinear terms match with the entries of bilinear terms returned by SCIPgetAllBilinearTermsQuadratic
15689  */
15691  SCIP* scip, /**< SCIP data structure */
15692  SCIP_VAR* x, /**< first variable */
15693  SCIP_VAR* y, /**< second variable */
15694  int idx, /**< index of the bilinear term */
15695  SCIP_Real xcoef, /**< x coefficient */
15696  SCIP_Real ycoef, /**< y coefficient */
15697  SCIP_Real constant, /**< constant part */
15698  SCIP_Bool* success /**< buffer to store whether inequality has been accepted */
15699  )
15700 {
15701  SCIP_CONSHDLRDATA* conshdlrdata;
15702  SCIP_CONSHDLR* conshdlr;
15703  BILINESTIMATOR* bilinest;
15704  SCIP_Real* ineqs;
15705  SCIP_Real viol1 = 0.0;
15706  SCIP_Real viol2 = 0.0;
15707  int* nineqs;
15708  int i;
15709 
15710  assert(scip != NULL);
15711  assert(x != NULL);
15712  assert(y != NULL);
15713  assert(idx >= 0);
15714  assert(xcoef != SCIP_INVALID); /*lint !e777 */
15715  assert(ycoef != SCIP_INVALID); /*lint !e777 */
15716  assert(constant != SCIP_INVALID); /*lint !e777 */
15717  assert(success != NULL);
15718 
15719  *success = FALSE;
15720 
15721  /* ignore inequalities that only yield to a (possible) bound tightening */
15722  if( SCIPisFeasZero(scip, xcoef) || SCIPisFeasZero(scip, ycoef) )
15723  return SCIP_OKAY;
15724 
15725  /* get constraint handler and its data */
15726  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
15727  if( conshdlr == NULL )
15728  return SCIP_OKAY;
15729 
15730  conshdlrdata = SCIPconshdlrGetData(conshdlr);
15731  assert(conshdlrdata != NULL);
15732  assert(idx < conshdlrdata->nbilinterms);
15733 
15734  bilinest = &conshdlrdata->bilinestimators[idx];
15735  assert(bilinest != NULL);
15736  assert(bilinest->x == x);
15737  assert(bilinest->y == y);
15738 
15739  SCIPdebugMsg(scip, "add bilinear term inequality: %g %s <= %g %s + %g\n", xcoef, SCIPvarGetName(bilinest->x),
15740  ycoef, SCIPvarGetName(bilinest->y), constant);
15741 
15742  if( xcoef * ycoef > 0.0 )
15743  {
15744  ineqs = bilinest->inequnderest;
15745  nineqs = &bilinest->ninequnderest;
15746  }
15747  else
15748  {
15749  ineqs = bilinest->ineqoverest;
15750  nineqs = &bilinest->nineqoverest;
15751  }
15752 
15753  /* compute violation of the inequality of the important corner points */
15754  getIneqViol(x, y, xcoef, ycoef, constant, &viol1, &viol2);
15755  SCIPdebugMsg(scip, "violations of inequality = (%g,%g)\n", viol1, viol2);
15756 
15757  /* inequality does not cut off one of the important corner points */
15758  if( SCIPisFeasLE(scip, MAX(viol1, viol2), 0.0) )
15759  return SCIP_OKAY;
15760 
15761  /* check whether inequality exists already */
15762  for( i = 0; i < *nineqs; ++i )
15763  {
15764  if( SCIPisFeasEQ(scip, xcoef, ineqs[3*i]) && SCIPisFeasEQ(scip, ycoef, ineqs[3*i+1])
15765  && SCIPisFeasEQ(scip, constant, ineqs[3*i+2]) )
15766  {
15767  SCIPdebugMsg(scip, "inequality already found -> skip\n");
15768  return SCIP_OKAY;
15769  }
15770  }
15771 
15772  /* add inequality if we found less than two so far; otherwise compare the violations to decide which which
15773  * inequality might be replaced
15774  */
15775  if( *nineqs < 2 )
15776  {
15777  ineqs[3*(*nineqs)] = xcoef;
15778  ineqs[3*(*nineqs) + 1] = ycoef;
15779  ineqs[3*(*nineqs) + 2] = constant;
15780  ++(*nineqs);
15781  *success = TRUE;
15782  }
15783  else
15784  {
15785  SCIP_Real viols1[2] = {0.0, 0.0};
15786  SCIP_Real viols2[2] = {0.0, 0.0};
15787  SCIP_Real bestviol;
15788  int pos = -1;
15789 
15790  assert(*nineqs == 2);
15791 
15792  /* compute resulting violations of both corner points when replacing an existing inequality
15793  *
15794  * given the violations (v1,w1), (v2,w2), (v3,w3) we select two inequalities i and j that
15795  * maximize max{vi,vj} + max{wi,wj} this measurement guarantees that select inequalities that
15796  * separate both important corner points
15797  */
15798  getIneqViol(x, y, ineqs[0], ineqs[1], ineqs[2], &viols1[0], &viols2[0]);
15799  getIneqViol(x, y, ineqs[3], ineqs[4], ineqs[5], &viols1[1], &viols2[1]);
15800  bestviol = MAX(viols1[0], viols1[1]) + MAX(viols2[0], viols2[1]);
15801 
15802  for( i = 0; i < 2; ++i )
15803  {
15804  SCIP_Real viol = MAX(viol1, viols1[i]) + MAX(viol2, viols2[i]);
15805  if( SCIPisGT(scip, viol, bestviol) )
15806  {
15807  bestviol = viol;
15808  /* remember inequality that should be replaced */
15809  pos = 1 - i;
15810  }
15811  }
15812 
15813  /* replace inequality at pos when replacing an existing inequality improved the total violation */
15814  if( pos != -1 )
15815  {
15816  assert(pos >= 0 && pos < 2);
15817  ineqs[3*pos] = xcoef;
15818  ineqs[3*pos+1] = ycoef;
15819  ineqs[3*pos+2] = constant;
15820  *success = TRUE;
15821  }
15822  }
15823  SCIPdebugMsg(scip, "accepted inequality? %u\n", *success);
15824 
15825  return SCIP_OKAY;
15826 }
15827 
15828 
15829 /** creates a SCIP_ROWPREP datastructure
15830  *
15831  * Initial cut represents 0 <= 0.
15832  */
15834  SCIP* scip, /**< SCIP data structure */
15835  SCIP_ROWPREP** rowprep, /**< buffer to store pointer to rowprep */
15836  SCIP_SIDETYPE sidetype, /**< whether cut will be or lower-equal or larger-equal type */
15837  SCIP_Bool local /**< whether cut will be valid only locally */
15838  )
15839 {
15840  assert(scip != NULL);
15841  assert(rowprep != NULL);
15842 
15843  SCIP_CALL( SCIPallocBlockMemory(scip, rowprep) );
15844  BMSclearMemory(*rowprep);
15845 
15846  (*rowprep)->sidetype = sidetype;
15847  (*rowprep)->local = local;
15848 
15849  return SCIP_OKAY;
15850 }
15851 
15852 /** frees a SCIP_ROWPREP datastructure */
15853 void SCIPfreeRowprep(
15854  SCIP* scip, /**< SCIP data structure */
15855  SCIP_ROWPREP** rowprep /**< pointer that stores pointer to rowprep */
15856  )
15857 {
15858  assert(scip != NULL);
15859  assert(rowprep != NULL);
15860  assert(*rowprep != NULL);
15861 
15862  SCIPfreeBlockMemoryArrayNull(scip, &(*rowprep)->vars, (*rowprep)->varssize);
15863  SCIPfreeBlockMemoryArrayNull(scip, &(*rowprep)->coefs, (*rowprep)->varssize);
15864  SCIPfreeBlockMemory(scip, rowprep);
15865 }
15866 
15867 /** creates a copy of a SCIP_ROWPREP datastructure */
15869  SCIP* scip, /**< SCIP data structure */
15870  SCIP_ROWPREP** target, /**< buffer to store pointer of rowprep copy */
15871  SCIP_ROWPREP* source /**< rowprep to copy */
15872  )
15873 {
15874  assert(scip != NULL);
15875  assert(target != NULL);
15876  assert(source != NULL);
15877 
15878  SCIP_CALL( SCIPduplicateBlockMemory(scip, target, source) );
15879  if( source->coefs != NULL )
15880  {
15881  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*target)->coefs, source->coefs, source->varssize) );
15882  }
15883  if( source->vars != NULL )
15884  {
15885  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*target)->vars, source->vars, source->varssize) );
15886  }
15887 
15888  return SCIP_OKAY;
15889 }
15890 
15891 /** ensures that rowprep has space for at least given number of additional terms
15892  *
15893  * Useful when knowing in advance how many terms will be added.
15894  */
15896  SCIP* scip, /**< SCIP data structure */
15897  SCIP_ROWPREP* rowprep, /**< rowprep */
15898  int size /**< number of additional terms for which to alloc space in rowprep */
15899  )
15900 {
15901  int oldsize;
15902 
15903  assert(scip != NULL);
15904  assert(rowprep != NULL);
15905  assert(size >= 0);
15906 
15907  if( rowprep->varssize >= rowprep->nvars + size )
15908  return SCIP_OKAY; /* already enough space left */
15909 
15910  /* realloc vars and coefs array */
15911  oldsize = rowprep->varssize;
15912  rowprep->varssize = SCIPcalcMemGrowSize(scip, rowprep->nvars + size);
15913 
15914  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &rowprep->vars, oldsize, rowprep->varssize) );
15915  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &rowprep->coefs, oldsize, rowprep->varssize) );
15916 
15917  return SCIP_OKAY;
15918 }
15919 
15920 /** prints a rowprep */
15921 void SCIPprintRowprep(
15922  SCIP* scip, /**< SCIP data structure */
15923  SCIP_ROWPREP* rowprep, /**< rowprep to be printed */
15924  FILE* file /**< file to print to, or NULL for stdout */
15925  )
15926 {
15927  int i;
15928 
15929  assert(scip != NULL);
15930  assert(rowprep != NULL);
15931 
15932  if( *rowprep->name != '\0' )
15933  {
15934  SCIPinfoMessage(scip, file, "[%s](%c) ", rowprep->name, rowprep->local ? 'l' : 'g');
15935  }
15936 
15937  for( i = 0; i < rowprep->nvars; ++i )
15938  {
15939  SCIPinfoMessage(scip, file, "%+g*<%s> ", rowprep->coefs[i], SCIPvarGetName(rowprep->vars[i]));
15940  }
15941 
15942  SCIPinfoMessage(scip, file, rowprep->sidetype == SCIP_SIDETYPE_LEFT ? ">= %g\n" : "<= %g\n", rowprep->side);
15943 }
15944 
15945 /** adds a term coef*var to a rowprep */
15947  SCIP* scip, /**< SCIP data structure */
15948  SCIP_ROWPREP* rowprep, /**< rowprep */
15949  SCIP_VAR* var, /**< variable to add */
15950  SCIP_Real coef /**< coefficient to add */
15951  )
15952 {
15953  assert(scip != NULL);
15954  assert(rowprep != NULL);
15955  assert(var != NULL);
15956 
15957  if( coef == 0.0 )
15958  return SCIP_OKAY;
15959 
15960  SCIP_CALL( SCIPensureRowprepSize(scip, rowprep, 1) );
15961  assert(rowprep->varssize > rowprep->nvars);
15962 
15963  rowprep->vars[rowprep->nvars] = var;
15964  rowprep->coefs[rowprep->nvars] = coef;
15965  ++rowprep->nvars;
15966 
15967  return SCIP_OKAY;
15968 }
15969 
15970 /** adds several terms coef*var to a rowprep */
15972  SCIP* scip, /**< SCIP data structure */
15973  SCIP_ROWPREP* rowprep, /**< rowprep */
15974  int nvars, /**< number of terms to add */
15975  SCIP_VAR** vars, /**< variables to add */
15976  SCIP_Real* coefs /**< coefficients to add */
15977  )
15978 {
15979  assert(scip != NULL);
15980  assert(rowprep != NULL);
15981  assert(vars != NULL || nvars == 0);
15982  assert(coefs != NULL || nvars == 0);
15983 
15984  if( nvars == 0 )
15985  return SCIP_OKAY;
15986 
15987  SCIP_CALL( SCIPensureRowprepSize(scip, rowprep, nvars) );
15988  assert(rowprep->varssize >= rowprep->nvars + nvars);
15989 
15990  /*lint --e{866} */
15991  BMScopyMemoryArray(rowprep->vars + rowprep->nvars, vars, nvars);
15992  BMScopyMemoryArray(rowprep->coefs + rowprep->nvars, coefs, nvars);
15993  rowprep->nvars += nvars;
15994 
15995  return SCIP_OKAY;
15996 }
15997 
15998 #ifdef NDEBUG
15999 #undef SCIPaddRowprepSide
16000 #undef SCIPaddRowprepConstant
16001 #endif
16002 
16003 /** adds constant value to side of rowprep */
16004 void SCIPaddRowprepSide(
16005  SCIP_ROWPREP* rowprep, /**< rowprep */
16006  SCIP_Real side /**< constant value to be added to side */
16007  )
16008 {
16009  assert(rowprep != NULL);
16010 
16011  rowprep->side += side;
16012 }
16013 
16014 /** adds constant term to rowprep
16015  *
16016  * Substracts constant from side.
16017  */
16019  SCIP_ROWPREP* rowprep, /**< rowprep */
16020  SCIP_Real constant /**< constant value to be added */
16021  )
16022 {
16023  assert(rowprep != NULL);
16024 
16025  SCIPaddRowprepSide(rowprep, -constant);
16026 }
16027 
16028 /** computes violation of cut in a given solution */
16030  SCIP* scip, /**< SCIP data structure */
16031  SCIP_ROWPREP* rowprep, /**< rowprep to be turned into a row */
16032  SCIP_SOL* sol /**< solution or NULL for LP solution */
16033  )
16034 {
16035  SCIP_Real activity;
16036  int i;
16037 
16038  activity = -rowprep->side;
16039  for( i = 0; i < rowprep->nvars; ++i )
16040  {
16041  /* Loose variable have the best bound as LP solution value.
16042  * HOWEVER, they become column variables when they are added to a row (via SCIPaddVarsToRow below).
16043  * When this happens, their LP solution value changes to 0.0!
16044  * So when calculating the row activity for an LP solution, we treat loose variable as if they were already column variables.
16045  */
16046  if( sol != NULL || SCIPvarGetStatus(rowprep->vars[i]) != SCIP_VARSTATUS_LOOSE )
16047  activity += rowprep->coefs[i] * SCIPgetSolVal(scip, sol, rowprep->vars[i]);
16048  }
16049 
16050  if( rowprep->sidetype == SCIP_SIDETYPE_RIGHT )
16051  /* cut is activity <= 0.0 -> violation is activity, if positive */
16052  return MAX(activity, 0.0);
16053  else
16054  /* cut is activity >= 0.0 -> violation is -activity, if positive */
16055  return MAX(-activity, 0.0);
16056 }
16057 
16058 /** Merge terms that use same variable and eliminate zero coefficients.
16059  *
16060  * Terms are sorted by variable (@see SCIPvarComp) after return.
16061  */
16063  SCIP* scip, /**< SCIP data structure */
16064  SCIP_ROWPREP* rowprep /**< rowprep to be cleaned up */
16065  )
16066 {
16067  int i;
16068  int j;
16069 
16070  assert(scip != NULL);
16071  assert(rowprep != NULL);
16072 
16073  if( rowprep->nvars <= 1 )
16074  return;
16075 
16076  /* sort terms by variable index */
16077  SCIPsortPtrReal((void**)rowprep->vars, rowprep->coefs, SCIPvarComp, rowprep->nvars);
16078 
16079  /* merge terms with same variable, drop 0 coefficients */
16080  i = 0;
16081  j = 1;
16082  while( j < rowprep->nvars )
16083  {
16084  if( rowprep->vars[i] == rowprep->vars[j] )
16085  {
16086  /* merge term j into term i */
16087  rowprep->coefs[i] += rowprep->coefs[j];
16088  ++j;
16089  continue;
16090  }
16091 
16092  if( rowprep->coefs[i] == 0.0 )
16093  {
16094  /* move term j to position i */
16095  rowprep->coefs[i] = rowprep->coefs[j];
16096  rowprep->vars[i] = rowprep->vars[j];
16097  ++j;
16098  continue;
16099  }
16100 
16101  /* move term j to position i+1 and move on */
16102  if( j != i+1 )
16103  {
16104  rowprep->vars[i+1] = rowprep->vars[j];
16105  rowprep->coefs[i+1] = rowprep->coefs[j];
16106  }
16107  ++i;
16108  ++j;
16109  }
16110 
16111  /* remaining term can have coef zero -> forget about it */
16112  if( rowprep->coefs[i] == 0.0 )
16113  --i;
16114 
16115  /* i points to last term */
16116  rowprep->nvars = i+1;
16117 }
16118 
16119 /** sort cut terms by absolute value of coefficients, from largest to smallest */
16120 static
16122  SCIP* scip, /**< SCIP data structure */
16123  SCIP_ROWPREP* rowprep /**< rowprep to be sorted */
16124  )
16125 {
16126  int i;
16127 
16128  assert(scip != NULL);
16129  assert(rowprep != NULL);
16130 
16131  /* special treatment for cuts with few variables */
16132  switch( rowprep->nvars )
16133  {
16134  case 0:
16135  case 1:
16136  break;
16137 
16138  case 2:
16139  {
16140  if( REALABS(rowprep->coefs[0]) < REALABS(rowprep->coefs[1]) )
16141  {
16142  SCIP_Real tmp1;
16143  SCIP_VAR* tmp2;
16144 
16145  tmp1 = rowprep->coefs[0];
16146  rowprep->coefs[0] = rowprep->coefs[1];
16147  rowprep->coefs[1] = tmp1;
16148 
16149  tmp2 = rowprep->vars[0];
16150  rowprep->vars[0] = rowprep->vars[1];
16151  rowprep->vars[1] = tmp2;
16152  }
16153  break;
16154  }
16155 
16156  default :
16157  {
16158  SCIP_Real* abscoefs;
16159 
16160  SCIP_CALL( SCIPallocBufferArray(scip, &abscoefs, rowprep->nvars) );
16161  for( i = 0; i < rowprep->nvars; ++i )
16162  abscoefs[i] = REALABS(rowprep->coefs[i]);
16163  SCIPsortDownRealRealPtr(abscoefs, rowprep->coefs, (void**)rowprep->vars, rowprep->nvars);
16164  SCIPfreeBufferArray(scip, &abscoefs);
16165  }
16166  }
16167 
16168  /* forget about coefs that are exactly zero (unlikely to have some) */
16169  while( rowprep->nvars > 0 && rowprep->coefs[rowprep->nvars-1] == 0.0 )
16170  --rowprep->nvars;
16171 
16172  return SCIP_OKAY;
16173 }
16174 
16175 /** try to improve coef range by aggregating cut with variable bounds
16176  *
16177  * Assumes terms have been sorted by rowprepCleanupSortTerms().
16178  */
16179 static
16181  SCIP* scip, /**< SCIP data structure */
16182  SCIP_ROWPREP* rowprep, /**< rowprep to be improve */
16183  SCIP_SOL* sol, /**< solution that we try to cut off, or NULL for LP solution */
16184  SCIP_Real maxcoefrange /**< maximal allowed coefficients range */
16185  )
16186 {
16187  SCIP_VAR* var;
16188  SCIP_Real lb;
16189  SCIP_Real ub;
16190  SCIP_Real ref;
16191  SCIP_Real coef;
16192  SCIP_Real mincoef;
16193  SCIP_Real maxcoef;
16194  SCIP_Real loss[2];
16195  int maxcoefidx;
16196  int pos;
16197 
16198  maxcoefidx = 0;
16199  if( rowprep->nvars > 0 )
16200  {
16201  maxcoef = REALABS(rowprep->coefs[0]);
16202  mincoef = REALABS(rowprep->coefs[rowprep->nvars-1]);
16203  }
16204  else
16205  mincoef = maxcoef = 1.0;
16206 
16207  /* eliminate minimal or maximal coefs as long as coef range is too large
16208  * this is likely going to eliminate coefs that are within eps of 0.0
16209  * if not, then we do so after scaling (or should we enforce this here?)
16210  */
16211  while( maxcoef / mincoef > maxcoefrange )
16212  {
16213  SCIPdebugMsg(scip, "cut coefficients have very large range: mincoef = %g maxcoef = %g\n", mincoef, maxcoef);
16214 
16215  /* max/min can only be > 1 if there is more than one var
16216  * we need this below for updating the max/min coef after eliminating a term
16217  */
16218  assert(rowprep->nvars > 1);
16219 
16220  /* try to reduce coef range by aggregating with variable bounds
16221  * that is, eliminate a term like a*x from a*x + ... <= side by adding -a*x <= -a*lb(x)
16222  * with ref(x) the reference point we try to eliminate, this would weaken the cut by a*(lb(x)-ref(x))
16223  *
16224  * we consider eliminating either the term with maximal or the one with minimal coefficient,
16225  * taking the one that leads to the least weakening of the cut
16226  *
16227  * TODO (suggested by @bzfserra, see !496):
16228  * - Also one could think of not completely removing the coefficient but do an aggregation that makes the coefficient look better. For instance:
16229  * say you have $`a x + 0.1 y \leq r`$ and $`y`$ has only an upper bound, $`y \leq b`$,
16230  * then you can't really remove $`y`$. However, you could aggregate it with $`0.9 \cdot (y \leq b)`$ to get
16231  * $`a x + y \leq r + 0.9 b`$, which has better numerics (and hopefully still cuts the point... actually, if for the point you want to separate, $`y^* = b`$, then the violation is the same)
16232  */
16233 
16234  for( pos = 0; pos < 2; ++pos )
16235  {
16236  var = rowprep->vars[pos ? rowprep->nvars-1 : maxcoefidx];
16237  coef = rowprep->coefs[pos ? rowprep->nvars-1 : maxcoefidx];
16238  lb = SCIPvarGetLbLocal(var);
16239  ub = SCIPvarGetUbLocal(var);
16240  ref = SCIPgetSolVal(scip, sol, var);
16241  assert(coef != 0.0);
16242 
16243  /* make sure reference point is something reasonable within the bounds, preferable the value from the solution */
16244  if( SCIPisInfinity(scip, REALABS(ref)) )
16245  ref = 0.0;
16246  ref = MAX(lb, MIN(ub, ref));
16247 
16248  /* check whether we can eliminate coef*var from rowprep and how much we would loose w.r.t. ref(x) */
16249  if( ((coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT)) )
16250  {
16251  /* we would need to aggregate with -coef*var <= -coef*lb(x) */
16252  if( SCIPisInfinity(scip, -lb) )
16253  loss[pos] = SCIP_INVALID;
16254  else
16255  loss[pos] = REALABS(coef) * (ref - lb);
16256  }
16257  else
16258  {
16259  assert((coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT));
16260  /* we would need to aggregate with -coef*var >= -coef*ub(x) */
16261  if( SCIPisInfinity(scip, ub) )
16262  loss[pos] = SCIP_INVALID;
16263  else
16264  loss[pos] = REALABS(coef) * (ub - ref);
16265  }
16266  assert(loss[pos] >= 0.0); /* assuming SCIP_INVALID >= 0 */
16267 
16268  SCIPdebugMsg(scip, "aggregating %g*<%s> %c= ... with <%s>[%g] %c= %g looses %g\n",
16269  coef, SCIPvarGetName(var), rowprep->sidetype == SCIP_SIDETYPE_RIGHT ? '<' : '>',
16270  SCIPvarGetName(var), ref,
16271  ((coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT)) ? '>' : '<',
16272  ((coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT)) ? lb : ub, loss[pos]);
16273  }
16274 
16275  /*lint --e{777} */
16276  if( loss[0] == SCIP_INVALID && loss[1] == SCIP_INVALID )
16277  break; /* cannot eliminate coefficient */
16278 
16279  /* select position with smaller loss */
16280  pos = (loss[1] == SCIP_INVALID || loss[1] > loss[0]) ? 0 : 1;
16281 
16282  /* now do the actual elimination */
16283  var = rowprep->vars[pos ? rowprep->nvars-1 : maxcoefidx];
16284  coef = rowprep->coefs[pos ? rowprep->nvars-1 : maxcoefidx];
16285 
16286  /* eliminate coef*var from rowprep: increase side */
16287  if( ((coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT)) )
16288  {
16289  /* we aggregate with -coef*var <= -coef*lb(x) */
16290  assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
16291  SCIPaddRowprepConstant(rowprep, coef * SCIPvarGetLbLocal(var));
16292  rowprep->local |= SCIPisGT(scip, SCIPvarGetLbLocal(var), SCIPvarGetLbGlobal(var));
16293  }
16294  else
16295  {
16296  assert((coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT));
16297  /* we aggregate with -coef*var >= -coef*ub(x) */
16298  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
16299  SCIPaddRowprepConstant(rowprep, coef * SCIPvarGetUbLocal(var));
16300  rowprep->local |= SCIPisLT(scip, SCIPvarGetUbLocal(var), SCIPvarGetUbGlobal(var));
16301  }
16302 
16303  /* eliminate coef*var from rowprep: remove coef */
16304  if( pos == 0 )
16305  {
16306  /* set first term to zero */
16307  rowprep->coefs[maxcoefidx] = 0.0;
16308 
16309  /* update index */
16310  ++maxcoefidx;
16311 
16312  /* update maxcoef */
16313  maxcoef = REALABS(rowprep->coefs[maxcoefidx]);
16314  }
16315  else
16316  {
16317  /* forget last term */
16318  --rowprep->nvars;
16319 
16320  /* update mincoef */
16321  mincoef = REALABS(rowprep->coefs[rowprep->nvars-1]);
16322  }
16323  }
16324 
16325  /* if maximal coefs were removed, then there are now 0's in the beginning of the coefs array
16326  * -> move all remaining coefs and vars up front
16327  */
16328  if( maxcoefidx > 0 )
16329  {
16330  int i;
16331  for( i = maxcoefidx; i < rowprep->nvars; ++i )
16332  {
16333  rowprep->vars[i-maxcoefidx] = rowprep->vars[i];
16334  rowprep->coefs[i-maxcoefidx] = rowprep->coefs[i];
16335  }
16336  rowprep->nvars -= maxcoefidx;
16337  }
16338 }
16339 
16340 
16341 /** scales up rowprep if it seems useful */
16342 static
16344  SCIP* scip, /**< SCIP data structure */
16345  SCIP_ROWPREP* rowprep, /**< rowprep to be improve */
16346  SCIP_Real* viol, /**< violation of cut in sol (input and output) */
16347  SCIP_Real minviol /**< minimal violation we try to achieve */
16348  )
16349 {
16350  SCIP_Real scalefactor;
16351  SCIP_Real mincoef;
16352  SCIP_Real maxcoef;
16353 
16354  assert(scip != NULL);
16355  assert(rowprep != NULL);
16356  assert(viol != NULL);
16357 
16358  /* if violation is very small than better don't scale up */
16359  if( *viol < ROWPREP_SCALEUP_VIOLNONZERO )
16360  return;
16361 
16362  /* if violation is already above minviol, then nothing to do */
16363  if( *viol >= minviol )
16364  return;
16365 
16366  /* if violation is sufficiently positive (>10*eps), but has not reached minviol,
16367  * then consider scaling up to reach approx MINVIOLFACTOR*minviol
16368  */
16369  scalefactor = ROWPREP_SCALEUP_MINVIOLFACTOR * minviol / *viol;
16370 
16371  /* scale by approx. scalefactor, if minimal coef is not so large yet and maximal coef and rhs don't get huge by doing so (or have been so before) */
16372  mincoef = rowprep->nvars > 0 ? REALABS(rowprep->coefs[rowprep->nvars-1]) : 1.0;
16373  maxcoef = rowprep->nvars > 0 ? REALABS(rowprep->coefs[0]) : 1.0;
16374  if( mincoef < ROWPREP_SCALEUP_MAXMINCOEF && scalefactor * maxcoef < ROWPREP_SCALEUP_MAXMAXCOEF && scalefactor * REALABS(rowprep->side) < ROWPREP_SCALEUP_MAXSIDE )
16375  {
16376  int scaleexp;
16377 
16378  /* SCIPinfoMessage(scip, NULL, "scale up by ~%g, viol=%g: ", scalefactor, myviol);
16379  SCIPprintRowprep(scip, rowprep, NULL); */
16380 
16381  /* SCIPscaleRowprep returns the actually applied scale factor */
16382  scaleexp = SCIPscaleRowprep(rowprep, scalefactor);
16383  *viol = ldexp(*viol, scaleexp);
16384 
16385  /* SCIPinfoMessage(scip, NULL, "scaled up by %g, viol=%g: ", ldexp(1.0, scaleexp), myviol);
16386  SCIPprintRowprep(scip, rowprep, NULL); */
16387  }
16388 }
16389 
16390 /** scales down rowprep if it improves coefs and keeps rowprep violated */
16391 static
16393  SCIP* scip, /**< SCIP data structure */
16394  SCIP_ROWPREP* rowprep, /**< rowprep to be improve */
16395  SCIP_Real* viol, /**< violation of cut in sol (input and output) */
16396  SCIP_Real minviol /**< minimal violation we try to keep */
16397  )
16398 {
16399  SCIP_Real scalefactor;
16400 
16401  /* if maxcoef < ROWPREP_SCALEDOWN_MINMAXCOEF (or no terms), then don't consider scaling down */
16402  if( rowprep->nvars == 0 || REALABS(rowprep->coefs[0]) < ROWPREP_SCALEDOWN_MINMAXCOEF )
16403  return;
16404 
16405  /* consider scaling down so that maxcoef ~ 10 */
16406  scalefactor = 10.0 / REALABS(rowprep->coefs[0]);
16407 
16408  /* if minimal violation would be lost by scaling down, then increase scalefactor such that minviol is still reached */
16409  if( *viol > minviol && scalefactor * *viol < minviol )
16410  {
16411  assert(minviol > 0.0); /* since viol >= 0, the if-condition should ensure that minviol > 0 */
16412  assert(*viol > 0.0); /* since minviol > 0, the if-condition ensures viol > 0 */
16413  scalefactor = ROWPREP_SCALEUP_MINVIOLFACTOR * minviol / *viol;
16414  }
16415 
16416  /* scale by approx. scalefactor if scaling down and minimal coef does not get too small
16417  * myviol < minviol (-> scalefactor > 1) or mincoef < feastol before scaling is possible, in which case we also don't scale down
16418  */
16419  if( scalefactor < 1.0 && scalefactor * REALABS(rowprep->coefs[rowprep->nvars-1]) > ROWPREP_SCALEDOWN_MINCOEF )
16420  {
16421  int scaleexp;
16422 
16423  /* SCIPinfoMessage(scip, NULL, "scale down by ~%g, viol=%g: ", scalefactor, myviol);
16424  SCIPprintRowprep(scip, rowprep, NULL); */
16425 
16426  scaleexp = SCIPscaleRowprep(rowprep, scalefactor);
16427  *viol = ldexp(*viol, scaleexp);
16428 
16429  /* SCIPinfoMessage(scip, NULL, "scaled down by %g, viol=%g: ", ldexp(1.0, scaleexp), myviol);
16430  SCIPprintRowprep(scip, rowprep, NULL); */
16431  }
16432 }
16433 
16434 /** rounds almost integral coefs to integrals, thereby trying to relax the cut */
16435 static
16437  SCIP* scip, /**< SCIP data structure */
16438  SCIP_ROWPREP* rowprep, /**< rowprep to be improve */
16439  SCIP_Real* viol /**< violation of cut in sol (input), set to SCIP_INVALID if some coef changed */
16440  )
16441 {
16442  SCIP_Real coef;
16443  SCIP_Real roundcoef;
16444  int i;
16445 
16446  assert(scip != NULL);
16447  assert(rowprep != NULL);
16448  assert(viol != NULL);
16449 
16450  /* Coefficients smaller than epsilon are rounded to 0.0 when added to row and
16451  * coefficients very close to integral values are rounded to integers when added to LP.
16452  * Both cases can be problematic if variable value is very large (bad numerics).
16453  * Thus, we anticipate by rounding coef here, but also modify constant so that cut is still valid (if possible),
16454  * i.e., bound coef[i]*x by round(coef[i])*x + (coef[i]-round(coef[i])) * bound(x).
16455  * Or in other words, we aggregate with the variable bound.
16456  *
16457  * If the required bound of x is not finite, then only round coef (introduces an error).
16458  * @TODO If only the opposite bound is available, then one could move the coefficient
16459  * away from the closest integer so that the SCIP_ROW won't try to round it.
16460  */
16461  for( i = 0; i < rowprep->nvars; ++i )
16462  {
16463  coef = rowprep->coefs[i];
16464  roundcoef = SCIPround(scip, coef);
16465  if( coef != roundcoef && SCIPisEQ(scip, coef, roundcoef) ) /*lint !e777*/
16466  {
16467  SCIP_Real xbnd;
16468  SCIP_VAR* var;
16469 
16470  var = rowprep->vars[i];
16471  if( rowprep->sidetype == SCIP_SIDETYPE_RIGHT )
16472  if( rowprep->local )
16473  xbnd = coef > roundcoef ? SCIPvarGetLbLocal(var) : SCIPvarGetUbLocal(var);
16474  else
16475  xbnd = coef > roundcoef ? SCIPvarGetLbGlobal(var) : SCIPvarGetUbGlobal(var);
16476  else
16477  if( rowprep->local )
16478  xbnd = coef > roundcoef ? SCIPvarGetUbLocal(var) : SCIPvarGetLbLocal(var);
16479  else
16480  xbnd = coef > roundcoef ? SCIPvarGetUbGlobal(var) : SCIPvarGetLbGlobal(var);
16481 
16482  if( !SCIPisInfinity(scip, REALABS(xbnd)) )
16483  {
16484  /* if there is a bound, then relax row side so rounding coef will not introduce an error */
16485  SCIPdebugMsg(scip, "var <%s> [%g,%g] has almost integral coef %.20g, round coefficient to %g and add constant %g\n",
16486  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), coef, roundcoef, (coef-roundcoef) * xbnd);
16487  SCIPaddRowprepConstant(rowprep, (coef-roundcoef) * xbnd);
16488  }
16489  else
16490  {
16491  /* if there is no bound, then we make the coef integral, too, even though this will introduce an error
16492  * however, SCIP_ROW would do this anyway, but doing this here might eliminate some epsilon coefs (so they don't determine mincoef below)
16493  * and helps to get a more accurate row violation value
16494  */
16495  SCIPdebugMsg(scip, "var <%s> [%g,%g] has almost integral coef %.20g, round coefficient to %g without relaxing side (!)\n",
16496  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), coef, roundcoef);
16497  }
16498  rowprep->coefs[i] = roundcoef;
16499  *viol = SCIP_INVALID;
16500  }
16501  }
16502 
16503  /* forget about coefs that became exactly zero by the above step */
16504  while( rowprep->nvars > 0 && rowprep->coefs[rowprep->nvars-1] == 0.0 )
16505  --rowprep->nvars;
16506 }
16507 
16508 /** relaxes almost zero side */
16509 static
16510 void rowprepCleanupSide(
16511  SCIP* scip, /**< SCIP data structure */
16512  SCIP_ROWPREP* rowprep, /**< rowprep to be improve */
16513  SCIP_Real* viol /**< violation of cut in sol (input), set to SCIP_INVALID if some coef changed */
16514  )
16515 {
16516  /* SCIP_ROW handling will replace a side close to 0 by 0.0, even if that makes the row more restrictive
16517  * we thus relax the side here so that it will either be 0 now or will not be rounded to 0 later
16518  */
16519  if( !SCIPisZero(scip, rowprep->side) )
16520  return;
16521 
16522  if( rowprep->side > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT )
16523  rowprep->side = 1.1*SCIPepsilon(scip);
16524  else if( rowprep->side < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT )
16525  rowprep->side = -1.1*SCIPepsilon(scip);
16526  else
16527  rowprep->side = 0.0;
16528 
16529  *viol = SCIP_INVALID;
16530 }
16531 
16532 /* Cleans up and attempts to improve rowprep
16533  *
16534  * Drops small or large coefficients if coefrange is too large, if this can be done by relaxing the cut.
16535  * Scales coefficients and side up to reach minimal violation, if possible.
16536  * Scaling is omitted if violation is very small (ROWPREP_SCALEUP_VIOLNONZERO) or
16537  * maximal coefficient would become huge (ROWPREP_SCALEUP_MAXMAXCOEF).
16538  * Scales coefficients and side down if they are large and if the minimal violation is still reached.
16539  * Rounds coefficients close to integral values to integrals, if this can be done by relaxing the cut.
16540  * Rounds side within epsilon of 0 to 0.0 or +/-1.1*epsilon, whichever relaxes the cut least.
16541  *
16542  * After return, the terms in the rowprep will be sorted by absolute value of coefficient, in decreasing order.
16543  */
16545  SCIP* scip, /**< SCIP data structure */
16546  SCIP_ROWPREP* rowprep, /**< rowprep to be cleaned */
16547  SCIP_SOL* sol, /**< solution that we try to cut off, or NULL for LP solution */
16548  SCIP_Real maxcoefrange, /**< maximal allowed coefficients range */
16549  SCIP_Real minviol, /**< minimal absolute violation the row should achieve (w.r.t. sol) */
16550  SCIP_Real* coefrange, /**< buffer to store coefrange of cleaned up cut, or NULL if not of interest */
16551  SCIP_Real* viol /**< buffer to store absolute violation of cleaned up cut in sol, or NULL if not of interest */
16552  )
16553 {
16554  SCIP_Real myviol;
16555 #ifdef SCIP_DEBUG
16556  SCIP_Real mincoef = 1.0;
16557  SCIP_Real maxcoef = 1.0;
16558 #endif
16559 
16560  assert(maxcoefrange > 1.0); /* not much interesting otherwise */
16561 
16562  /* sort term by absolute value of coef. */
16563  SCIP_CALL( rowprepCleanupSortTerms(scip, rowprep) );
16564 
16565 #ifdef SCIP_DEBUG
16566  if( rowprep->nvars > 0 )
16567  {
16568  maxcoef = REALABS(rowprep->coefs[0]);
16569  mincoef = REALABS(rowprep->coefs[rowprep->nvars-1]);
16570  }
16571 
16572  SCIPinfoMessage(scip, NULL, "starting cleanup, coefrange %g: ", maxcoef/mincoef);
16573  SCIPprintRowprep(scip, rowprep, NULL);
16574 #endif
16575 
16576  /* improve coefficient range by aggregating out variables */
16577  rowprepCleanupImproveCoefrange(scip, rowprep, sol, maxcoefrange);
16578 
16579  /* get current violation in sol */
16580  myviol = SCIPgetRowprepViolation(scip, rowprep, sol);
16581  assert(myviol >= 0.0);
16582 
16583 #ifdef SCIP_DEBUG
16584  if( rowprep->nvars > 0 )
16585  {
16586  maxcoef = REALABS(rowprep->coefs[0]);
16587  mincoef = REALABS(rowprep->coefs[rowprep->nvars-1]);
16588  }
16589 
16590  SCIPinfoMessage(scip, NULL, "improved coefrange to %g, viol %g: ", maxcoef / mincoef, myviol);
16591  SCIPprintRowprep(scip, rowprep, NULL);
16592 #endif
16593 
16594  /* if there is interest in achieving some minimal violation, then possibly scale up to increase violation, updates myviol */
16595  if( minviol > 0.0 )
16596  {
16597  /* first, try to achieve scip's minefficacy (typically 1e-4) */
16598  if( SCIPgetSepaMinEfficacy(scip) > minviol )
16599  rowprepCleanupScaleup(scip, rowprep, &myviol, SCIPgetSepaMinEfficacy(scip));
16600  /* in case scip minefficacy could not be reached or was smaller than minviol, try with the given minviol */
16601  rowprepCleanupScaleup(scip, rowprep, &myviol, minviol);
16602  }
16603 
16604  /* scale down to improve numerics, updates myviol */
16605  rowprepCleanupScaledown(scip, rowprep, &myviol, MAX(SCIPgetSepaMinEfficacy(scip), minviol)); /*lint !e666*/
16606 
16607 #ifdef SCIP_DEBUG
16608  SCIPinfoMessage(scip, NULL, "applied scaling, viol %g: ", myviol);
16609  SCIPprintRowprep(scip, rowprep, NULL);
16610 #endif
16611 
16612  /* turn almost-integral coefs to integral values, may set myviol to SCIP_INVALID */
16613  rowprepCleanupIntegralCoefs(scip, rowprep, &myviol);
16614 
16615  /* relax almost-zero side, may set myviol to SCIP_INVALID */
16616  rowprepCleanupSide(scip, rowprep, &myviol);
16617 
16618 #ifdef SCIP_DEBUG
16619  SCIPinfoMessage(scip, NULL, "adjusted almost-integral coefs and sides, viol %g: ", myviol);
16620  SCIPprintRowprep(scip, rowprep, NULL);
16621 #endif
16622 
16623  /* compute final coefrange, if requested by caller */
16624  if( coefrange != NULL )
16625  {
16626  if( rowprep->nvars > 0 )
16627  *coefrange = REALABS(rowprep->coefs[0]) / REALABS(rowprep->coefs[rowprep->nvars-1]);
16628  else
16629  *coefrange = 1.0;
16630  }
16631 
16632  /* If we updated myviol correctly, then it should coincide with freshly computed violation.
16633  * I leave this assert off for now, since getting the tolerance in the EQ correctly is not trivial. We recompute viol below anyway.
16634  */
16635  /* assert(myviol == SCIP_INVALID || SCIPisEQ(scip, myviol, SCIPgetRowprepViolation(scip, rowprep, sol))); */
16636 
16637  /* compute final violation, if requested by caller */
16638  if( viol != NULL ) /*lint --e{777} */
16639  *viol = myviol == SCIP_INVALID ? SCIPgetRowprepViolation(scip, rowprep, sol) : myviol;
16640 
16641  return SCIP_OKAY;
16642 }
16643 
16644 /** scales a rowprep
16645  *
16646  * @return Exponent of actually applied scaling factor, if written as 2^x.
16647  */
16648 int SCIPscaleRowprep(
16649  SCIP_ROWPREP* rowprep, /**< rowprep to be scaled */
16650  SCIP_Real factor /**< suggested scale factor */
16651  )
16652 {
16653  double v;
16654  int expon;
16655  int i;
16656 
16657  assert(rowprep != NULL);
16658  assert(factor > 0.0);
16659 
16660  /* write factor as v*2^expon with v in [0.5,1) */
16661  v = frexp(factor, &expon);
16662  /* adjust to v'*2^expon with v' in (0.5,1] by v'=v if v > 0.5, v'=1 if v=0.5 */
16663  if( v == 0.5 )
16664  --expon;
16665 
16666  /* multiply each coefficient by 2^expon */
16667  for( i = 0; i < rowprep->nvars; ++i )
16668  rowprep->coefs[i] = ldexp(rowprep->coefs[i], expon);
16669 
16670  /* multiply side by 2^expon */
16671  rowprep->side = ldexp(rowprep->side, expon);
16672 
16673  return expon;
16674 }
16675 
16676 /** generates a SCIP_ROW from a rowprep */
16678  SCIP* scip, /**< SCIP data structure */
16679  SCIP_ROW** row, /**< buffer to store pointer to new row */
16680  SCIP_ROWPREP* rowprep, /**< rowprep to be turned into a row */
16681  SCIP_CONSHDLR* conshdlr /**< constraint handler */
16682  )
16683 {
16684  assert(scip != NULL);
16685  assert(row != NULL);
16686  assert(rowprep != NULL);
16687 
16688  SCIP_CALL( SCIPcreateEmptyRowCons(scip, row, conshdlr, rowprep->name,
16689  rowprep->sidetype == SCIP_SIDETYPE_LEFT ? rowprep->side : -SCIPinfinity(scip),
16690  rowprep->sidetype == SCIP_SIDETYPE_RIGHT ? rowprep->side : SCIPinfinity(scip),
16691  rowprep->local && (SCIPgetDepth(scip) > 0), FALSE, TRUE) );
16692 
16693  SCIP_CALL( SCIPaddVarsToRow(scip, *row, rowprep->nvars, rowprep->vars, rowprep->coefs) );
16694 
16695  return SCIP_OKAY;
16696 }
16697 
16698 /** generates a SCIP_ROW from a rowprep */
16700  SCIP* scip, /**< SCIP data structure */
16701  SCIP_ROW** row, /**< buffer to store pointer to new row */
16702  SCIP_ROWPREP* rowprep, /**< rowprep to be turned into a row */
16703  SCIP_SEPA* sepa /**< separator */
16704  )
16705 {
16706  assert(scip != NULL);
16707  assert(row != NULL);
16708  assert(rowprep != NULL);
16709 
16710  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, row, sepa, rowprep->name,
16711  rowprep->sidetype == SCIP_SIDETYPE_LEFT ? rowprep->side : -SCIPinfinity(scip),
16712  rowprep->sidetype == SCIP_SIDETYPE_RIGHT ? rowprep->side : SCIPinfinity(scip),
16713  rowprep->local && (SCIPgetDepth(scip) > 0), FALSE, TRUE) );
16714 
16715  SCIP_CALL( SCIPaddVarsToRow(scip, *row, rowprep->nvars, rowprep->vars, rowprep->coefs) );
16716 
16717  return SCIP_OKAY;
16718 }
SCIP_RETCODE SCIPaddLinearCoefsToNlRow(SCIP *scip, SCIP_NLROW *nlrow, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip.c:32414
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:52
static void rowprepCleanupImproveCoefrange(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Real maxcoefrange)
SCIP_VAR ** SCIPgetLinearVarsQuadratic(SCIP *scip, SCIP_CONS *cons)
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip.h:22604
SCIP_RETCODE SCIPchgSquareCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_RETCODE SCIPincludeConshdlrQuadratic(SCIP *scip)
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
void SCIPintervalDivScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
int SCIPgetNIntVars(SCIP *scip)
Definition: scip.c:11902
SCIP_RETCODE SCIPchgBilinCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Real coef)
static SCIP_Bool conshdlrdataHasUpgrade(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), const char *conshdlrname)
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:47363
SCIP_Bool SCIPisIpoptAvailableIpopt(void)
#define ROWPREP_SCALEUP_VIOLNONZERO
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip.h:22593
static SCIP_RETCODE mergeAndCleanLinearVars(SCIP *scip, SCIP_CONS *cons)
static SCIP_Bool generateCutLTIgenMulCoeff(SCIP *scip, SCIP_Real x1, SCIP_Real y1_, SCIP_Real x2, SCIP_Real y2, SCIP_Bool whichuse, SCIP_Real *cx, SCIP_Real *cy, SCIP_Real *cw)
SCIP_Real SCIPvarGetWorstBoundLocal(SCIP_VAR *var)
Definition: var.c:17375
void SCIPintervalMulSup(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSDATA **consdata, SCIP_Real lhs, SCIP_Real rhs, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadvars, SCIP_QUADVARTERM *quadvarterms, int nbilinterms, SCIP_BILINTERM *bilinterms, SCIP_Bool capturevars)
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip.c:6291
void * SCIPhashmapEntryGetImage(SCIP_HASHMAPENTRY *entry)
Definition: misc.c:3172
static SCIP_RETCODE propagateBoundsQuadVar(SCIP *scip, SCIP_CONS *cons, SCIP_Real intervalinfty, SCIP_VAR *var, SCIP_Real a, SCIP_INTERVAL b, SCIP_INTERVAL rhs, SCIP_RESULT *result, int *nchgbds)
static SCIP_RETCODE freeAllBilinearTerms(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **conss, int nconss)
SCIP_EXPRGRAPH * SCIPgetExprgraphNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr)
static SCIP_DECL_CONSENFOPS(consEnfopsQuadratic)
SCIP_RETCODE SCIPincludeNonlinconsUpgrade(SCIP *scip, SCIP_DECL_NONLINCONSUPGD((*nonlinconsupgd)), SCIP_DECL_EXPRGRAPHNODEREFORM((*nodereform)), int priority, SCIP_Bool active, const char *conshdlrname)
#define ROWPREP_SCALEDOWN_MINCOEF
static void consdataMoveLinearVar(SCIP_CONSDATA *consdata, int oldpos, int newpos)
SCIP_Real SCIPfeastol(SCIP *scip)
Definition: scip.c:46443
SCIP_Bool SCIPconsIsEnabled(SCIP_CONS *cons)
Definition: cons.c:8083
SCIP_Bool SCIPintervalIsEmpty(SCIP_Real infinity, SCIP_INTERVAL operand)
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip.h:22587
static SCIP_RETCODE consdataSortBilinTerms(SCIP *scip, SCIP_CONSDATA *consdata)
primal heuristic that tries a given solution
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition: scip.c:31233
SCIP_RETCODE SCIPaddQuadVarQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real lincoef, SCIP_Real sqrcoef)
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_VAR * var2
static void rowprepCleanupScaleup(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_Real *viol, SCIP_Real minviol)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47298
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition: scip.c:41404
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip.c:821
#define MAXDNOM
#define SCIP_EVENTTYPE_VARFIXED
Definition: type_event.h:58
#define GAUGESCALE
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8245
SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition: var.c:17068
SCIP_RETCODE SCIPincSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real incval)
Definition: scip.c:38868
static SCIP_RETCODE separatePoint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_Real minefficacy, SCIP_Bool inenforcement, SCIP_RESULT *result, SCIP_Real *bestefficacy)
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip.c:6314
#define CONSHDLR_PRESOLTIMING
static SCIP_DECL_CONSSEPASOL(consSepasolQuadratic)
void SCIPaddConstantQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_Real constant)
static SCIP_RETCODE consdataEnsureQuadVarTermsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num)
static SCIP_DECL_CONSINITSOL(consInitsolQuadratic)
Constraint handler for variable bound constraints .
SCIP_Bool SCIPisRelEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47674
int SCIPgetNAllBilinearTermsQuadratic(SCIP *scip)
SCIP_RETCODE SCIPaddSquareCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
static SCIP_RETCODE propagateBoundsBilinearTerm(SCIP *scip, SCIP_CONS *cons, SCIP_Real intervalinfty, SCIP_VAR *x, SCIP_Real xsqrcoef, SCIP_Real xlincoef, SCIP_VAR *y, SCIP_Real ysqrcoef, SCIP_Real ylincoef, SCIP_Real bilincoef, SCIP_INTERVAL rhs, SCIP_RESULT *result, int *nchgbds)
#define ROWPREP_SCALEDOWN_MINMAXCOEF
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip.c:41226
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip.c:6604
SCIP_RETCODE SCIPchgRhsQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_Real rhs)
int SCIPexprgraphGetNodeNChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12947
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition: scip.h:22622
SCIP_Real SCIPintervalNegateReal(SCIP_Real x)
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17276
SCIP_RETCODE SCIPincludeQuadconsUpgrade(SCIP *scip, SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), int priority, SCIP_Bool active, const char *conshdlrname)
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip.c:6544
static SCIP_DECL_SORTINDCOMP(quadVarTermComp)
#define SCIP_MAXSTRLEN
Definition: def.h:259
static SCIP_RETCODE replaceQuadVarTermPos(SCIP *scip, SCIP_CONS *cons, int pos, SCIP_VAR *var, SCIP_Real coef, SCIP_Real offset)
#define SCIP_DECL_CONSINITPRE(x)
Definition: type_cons.h:140
#define CONSHDLR_DELAYPROP
SCIP_Bool SCIPvarIsInitial(SCIP_VAR *var)
Definition: var.c:16863
SCIP_VAR * var1
void SCIPsortPtrPtrReal(void **ptrarray1, void **ptrarray2, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPaddRowprepTerms(SCIP *scip, SCIP_ROWPREP *rowprep, int nvars, SCIP_VAR **vars, SCIP_Real *coefs)
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip.c:6036
#define SCIPallocClearBlockMemoryArray(scip, ptr, num)
Definition: scip.h:22591
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:28400
static SCIP_RETCODE getImpliedBounds(SCIP *scip, SCIP_VAR *x, SCIP_Bool xval, SCIP_VAR *y, SCIP_INTERVAL *resultant)
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:12663
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip.c:46813
SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
Definition: var.c:17056
int SCIProwGetNNonz(SCIP_ROW *row)
Definition: lp.c:16405
SCIP_RETCODE SCIPcleanupRowprep(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Real maxcoefrange, SCIP_Real minviol, SCIP_Real *coefrange, SCIP_Real *viol)
#define CONSHDLR_PROPFREQ
SCIP_Real inequnderest[6]
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:47088
#define INTERIOR_EPS
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17332
static SCIP_DECL_CONSSEPALP(consSepalpQuadratic)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47015
internal methods for NLPI solver interfaces
SCIP_RETCODE SCIPaddRowprepTerm(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_VAR *var, SCIP_Real coef)
static SCIP_RETCODE lockLinearVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_Bool local
SCIP_Bool SCIPconsIsAdded(SCIP_CONS *cons)
Definition: cons.c:8355
SCIP_RETCODE SCIPnlpiCreateProblem(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM **problem, const char *name)
Definition: nlpi.c:211
static SCIP_RETCODE catchVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons)
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip.c:8611
SCIP_NLPSOLSTAT SCIPgetNLPSolstat(SCIP *scip)
Definition: scip.c:31616
const char * SCIProwGetName(SCIP_ROW *row)
Definition: lp.c:16543
SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
Definition: scip.c:18957
static void consdataUpdateLinearActivityUbChange(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real coef, SCIP_Real oldbnd, SCIP_Real newbnd)
static SCIP_RETCODE dropLinearVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons, int linvarpos)
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip.c:18766
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:16842
static SCIP_RETCODE addQuadVarTerm(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real lincoef, SCIP_Real sqrcoef)
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:47387
SCIP_RETCODE SCIPnlpiGetSolution(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem, SCIP_Real **primalvalues, SCIP_Real **consdualvalues, SCIP_Real **varlbdualvalues, SCIP_Real **varubdualvalues, SCIP_Real *objval)
Definition: nlpi.c:537
SCIP_Real SCIPvarGetBestBoundLocal(SCIP_VAR *var)
Definition: var.c:17362
SCIP_Real SCIPdualfeastol(SCIP *scip)
Definition: scip.c:46471
static SCIP_DECL_CONSENABLE(consEnableQuadratic)
static SCIP_RETCODE generateCut(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Real *ref, SCIP_SOL *sol, SCIP_SIDETYPE violside, SCIP_ROW **row, SCIP_Real *efficacy, SCIP_Bool checkcurvmultivar, SCIP_Real minefficacy)
static void consdataUpdateLinearActivityLbChange(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real coef, SCIP_Real oldbnd, SCIP_Real newbnd)
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47350
static SCIP_DECL_NONLINCONSUPGD(nonlinconsUpgdQuadratic)
#define CONSHDLR_MAXPREROUNDS
SCIP_RETCODE SCIPchgLinearCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
void SCIPintervalSetRoundingMode(SCIP_ROUNDMODE roundmode)
SCIP_SIDETYPE sidetype
static SCIP_DECL_CONSEXITPRE(consExitpreQuadratic)
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4485
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:16484
#define FALSE
Definition: def.h:64
SCIP_Real SCIPadjustedVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real ub)
Definition: scip.c:21985
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:2793
#define INITLPMAXVARVAL
static SCIP_RETCODE evaluateGauge(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *refsol, SCIP_Real *gaugeval, SCIP_Bool *success)
static SCIP_RETCODE storeAllBilinearTerms(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **conss, int nconss)
static SCIP_RETCODE presolveSolve(SCIP *scip, SCIP_CONS *cons, SCIP_RESULT *result, SCIP_Bool *redundant, int *naggrvars)
SCIP_RETCODE SCIPnlpiAddConstraints(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem, int nconss, const SCIP_Real *lhss, const SCIP_Real *rhss, const int *nlininds, int *const *lininds, SCIP_Real *const *linvals, const int *nquadelems, SCIP_QUADELEM *const *quadelems, int *const *exprvaridxs, SCIP_EXPRTREE *const *exprtrees, const char **names)
Definition: nlpi.c:268
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:10289
int SCIPgetSubscipDepth(SCIP *scip)
Definition: scip.c:3542
SCIP_RETCODE SCIPincludeConshdlrBasic(SCIP *scip, SCIP_CONSHDLR **conshdlrptr, const char *name, const char *desc, int enfopriority, int chckpriority, int eagerfreq, SCIP_Bool needscons, SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition: scip.c:5894
SCIP_Real * SCIPgetLinearCoefsNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPinfinity(SCIP *scip)
Definition: scip.c:47028
#define CONSHDLR_SEPAPRIORITY
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 TRUE
Definition: def.h:63
#define SCIPdebug(x)
Definition: pub_message.h:74
SCIP_RETCODE SCIPunmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:28630
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
SCIP_RETCODE SCIPsolveNLP(SCIP *scip)
Definition: scip.c:31593
static SCIP_RETCODE generateCutConvex(SCIP *scip, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_Real *ref, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
SCIP_RETCODE SCIPaddVarLocks(SCIP *scip, SCIP_VAR *var, int nlocksdown, int nlocksup)
Definition: scip.c:21660
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8265
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition: type_timing.h:45
static void consdataFindUnlockedLinearVar(SCIP *scip, SCIP_CONSDATA *consdata)
static void checkCurvatureEasy(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *determined, SCIP_Bool checkmultivariate)
void SCIPintervalSetBounds(SCIP_INTERVAL *resultant, SCIP_Real inf, SCIP_Real sup)
SCIP_Real SCIPgetRhsNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8295
SCIP_RETCODE SCIPcreateConsBasicQuadratic2(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadvarterms, SCIP_QUADVARTERM *quadvarterms, int nbilinterms, SCIP_BILINTERM *bilinterms, SCIP_Real lhs, SCIP_Real rhs)
void SCIPsortDownIntInt(int *intarray1, int *intarray2, int len)
static GRAPHNODE ** active
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:22639
static SCIP_RETCODE removeBilinearTermsPos(SCIP *scip, SCIP_CONS *cons, int nterms, int *termposs)
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip.h:22602
void SCIPaddBilinLinearization(SCIP *scip, SCIP_Real bilincoef, SCIP_Real refpointx, SCIP_Real refpointy, SCIP_Real *lincoefx, SCIP_Real *lincoefy, SCIP_Real *linconstant, SCIP_Bool *success)
Definition: scip.c:33409
#define SCIPdebugMessage
Definition: pub_message.h:77
SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
Definition: scip.c:5948
SCIP_Real SCIPselectSimpleValue(SCIP_Real lb, SCIP_Real ub, SCIP_Longint maxdnom)
Definition: misc.c:9126
static SCIP_RETCODE presolveTryAddAND(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *naddconss)
SCIP_EVENTHDLR * SCIPfindEventhdlr(SCIP *scip, const char *name)
Definition: scip.c:8741
Constraint handler for AND constraints, .
SCIP_RETCODE SCIPwriteVarsPolynomial(SCIP *scip, FILE *file, SCIP_VAR ***monomialvars, SCIP_Real **monomialexps, SCIP_Real *monomialcoefs, int *monomialnvars, int nmonomials, SCIP_Bool type)
Definition: scip.c:17909
static SCIP_RETCODE mergeAndCleanBilinearTerms(SCIP *scip, SCIP_CONS *cons)
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2931
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46963
static SCIP_RETCODE chgLinearCoefPos(SCIP *scip, SCIP_CONS *cons, int pos, SCIP_Real newcoef)
static SCIP_RETCODE propagateBoundsCons(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_RESULT *result, int *nchgbds, SCIP_Bool *redundant)
SCIP_RETCODE SCIPcreateLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip.c:37920
static SCIP_DECL_CONSENFOLP(consEnfolpQuadratic)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip.h:22632
SCIP_Real SCIPadjustedVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real lb)
Definition: scip.c:21953
SCIP_Bool SCIPvarIsRemovable(SCIP_VAR *var)
Definition: var.c:16873
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip.h:22585
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:83
static SCIP_RETCODE dropQuadVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons, int quadvarpos)
SCIP_RETCODE SCIPcreateConsBasicQuadratic(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadterms, SCIP_VAR **quadvars1, SCIP_VAR **quadvars2, SCIP_Real *quadcoefs, SCIP_Real lhs, SCIP_Real rhs)
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8255
#define SCIP_EVENTTYPE_BOUNDCHANGED
Definition: type_event.h:108
void SCIPcomputeBilinEnvelope2(SCIP *scip, SCIP_Real bilincoef, SCIP_Real lbx, SCIP_Real ubx, SCIP_Real refpointx, SCIP_Real lby, SCIP_Real uby, SCIP_Real refpointy, SCIP_Bool overestimate, SCIP_Real xcoef1, SCIP_Real ycoef1, SCIP_Real constant1, SCIP_Real xcoef2, SCIP_Real ycoef2, SCIP_Real constant2, SCIP_Real *RESTRICT lincoefx, SCIP_Real *RESTRICT lincoefy, SCIP_Real *RESTRICT linconstant, SCIP_Bool *RESTRICT success)
Definition: scip.c:33899
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip.c:6337
static SCIP_RETCODE registerBranchingCandidatesViolation(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, int *nnotify)
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip.c:1267
#define SCIPdebugMsgPrint
Definition: scip.h:456
#define ROWPREP_SCALEUP_MAXMAXCOEF
#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
static void consdataUpdateLinearActivity(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real intervalinfty)
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip.c:6521
SCIP_Real SCIPgetLhsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8047
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip.c:1343
int SCIPgetNContVars(SCIP *scip)
Definition: scip.c:11992
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: scip.c:27584
SCIP_Real SCIPepsilon(SCIP *scip)
Definition: scip.c:46415
static SCIP_RETCODE lockQuadraticVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
#define SCIP_PRESOLTIMING_FAST
Definition: type_timing.h:43
SCIP_RETCODE SCIPaddLinearVarQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
void SCIPintervalSolveUnivariateQuadExpression(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL rhs)
SCIP_RETCODE SCIPcreateConsQuadratic(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadterms, SCIP_VAR **quadvars1, SCIP_VAR **quadvars2, SCIP_Real *quadcoefs, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable)
static SCIP_RETCODE unlockQuadraticVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
SCIP_Bool SCIPisRelGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47713
int SCIPgetNQuadVarTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPconsIsOriginal(SCIP_CONS *cons)
Definition: cons.c:8285
int SCIPnlrowGetNQuadElems(SCIP_NLROW *nlrow)
Definition: nlp.c:3322
SCIP_RETCODE SCIPcreateConsVarbound(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *var, SCIP_VAR *vbdvar, SCIP_Real vbdcoef, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
#define SCIP_EVENTTYPE_LBCHANGED
Definition: type_event.h:104
SCIP_Bool SCIPisRelLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47687
static SCIP_RETCODE generateCutNonConvex(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_Real *ref, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
const char * SCIPgetProbName(SCIP *scip)
Definition: scip.c:10891
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3025
static SCIP_RETCODE registerBranchingCandidatesGap(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, int *nnotify)
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)
int SCIPgetNBilinTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPnlpiSolve(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem)
Definition: nlpi.c:497
SCIP_RETCODE SCIPheurPassSolTrySol(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *sol)
Definition: heur_trysol.c:236
SCIP_EXPROP SCIPexprgraphGetNodeOperator(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13007
static SCIP_RETCODE consdataSortQuadVarTerms(SCIP *scip, SCIP_CONSDATA *consdata)
#define CONSHDLR_EAGERFREQ
SCIP_RETCODE SCIPnlpiAddVars(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem, int nvars, const SCIP_Real *lbs, const SCIP_Real *ubs, const char **varnames)
Definition: nlpi.c:250
SCIP_RETCODE SCIPchgVarType(SCIP *scip, SCIP_VAR *var, SCIP_VARTYPE vartype, SCIP_Bool *infeasible)
Definition: scip.c:25479
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17286
void SCIPcomputeBilinEnvelope1(SCIP *scip, SCIP_Real bilincoef, SCIP_Real lbx, SCIP_Real ubx, SCIP_Real refpointx, SCIP_Real lby, SCIP_Real uby, SCIP_Real refpointy, SCIP_Bool overestimate, SCIP_Real xcoef, SCIP_Real ycoef, SCIP_Real constant, SCIP_Real *RESTRICT lincoefx, SCIP_Real *RESTRICT lincoefy, SCIP_Real *RESTRICT linconstant, SCIP_Bool *RESTRICT success)
Definition: scip.c:33665
SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITSOL((*consinitsol)))
Definition: scip.c:6157
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip.h:22599
SCIP_Bool SCIPisConcaveQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Real coef
Definition: type_expr.h:102
#define SCIP_EVENTTYPE_SOLFOUND
Definition: type_event.h:127
void SCIPfreeRowprep(SCIP *scip, SCIP_ROWPREP **rowprep)
SCIP_Real inf
Definition: intervalarith.h:39
SCIP_RETCODE SCIPchgLhsQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_Real lhs)
static SCIP_RETCODE checkCurvature(SCIP *scip, SCIP_CONS *cons, SCIP_Bool checkmultivariate)
SCIP_Real SCIPeventGetNewbound(SCIP_EVENT *event)
Definition: event.c:1162
SCIP_RETCODE SCIPcreateSolCopy(SCIP *scip, SCIP_SOL **sol, SCIP_SOL *sourcesol)
Definition: scip.c:38168
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
Definition: scip.c:1054
SCIP_Bool SCIPconsIsLocked(SCIP_CONS *cons)
Definition: cons.c:8325
SCIP_VAR ** SCIPnlrowGetQuadVars(SCIP_NLROW *nlrow)
Definition: nlp.c:3285
static SCIP_RETCODE presolveTryAddLinearReform(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *naddconss)
static SCIP_RETCODE generateCutFactorableDo(SCIP *scip, SCIP_CONS *cons, SCIP_Real *ref, SCIP_Real multleft, SCIP_Real *coefleft, SCIP_Real multright, SCIP_Real *coefright, SCIP_Real rightminactivity, SCIP_Real rightmaxactivity, SCIP_Real rhs, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
void SCIPmarkRowNotRemovableLocal(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30835
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip.c:6060
SCIP_RETCODE SCIPaddLinearConsToNlpHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_Bool addcombconss, SCIP_Bool addcontconss)
Definition: heur_subnlp.c:2391
static SCIP_DECL_CONSEXIT(consExitQuadratic)
const char * SCIPheurGetName(SCIP_HEUR *heur)
Definition: heur.c:1198
struct SCIP_QuadVarEventData SCIP_QUADVAREVENTDATA
SCIP_Bool SCIPintervalIsEntire(SCIP_Real infinity, SCIP_INTERVAL operand)
SCIP_Bool SCIPisRelGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47726
static void getIneqViol(SCIP_VAR *x, SCIP_VAR *y, SCIP_Real xcoef, SCIP_Real ycoef, SCIP_Real constant, SCIP_Real *viol1, SCIP_Real *viol2)
void SCIPaddBilinMcCormick(SCIP *scip, SCIP_Real bilincoef, SCIP_Real lbx, SCIP_Real ubx, SCIP_Real refpointx, SCIP_Real lby, SCIP_Real uby, SCIP_Real refpointy, SCIP_Bool overestimate, SCIP_Real *lincoefx, SCIP_Real *lincoefy, SCIP_Real *linconstant, SCIP_Bool *success)
Definition: scip.c:33456
SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
Definition: scip.c:8225
SCIP_RETCODE SCIPfindQuadVarTermQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, int *pos)
SCIP_RETCODE SCIPensureRowprepSize(SCIP *scip, SCIP_ROWPREP *rowprep, int size)
static void propagateBoundsGetQuadActivity(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real intervalinfty, SCIP_Real *minquadactivity, SCIP_Real *maxquadactivity, int *minactivityinf, int *maxactivityinf, SCIP_INTERVAL *quadactcontr)
static SCIP_RETCODE addLinearizationCuts(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *ref, SCIP_Bool *separatedlpsol, SCIP_Real minefficacy)
SCIP_RETCODE SCIPcreateConsAnd(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *resvar, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: cons_and.c:4968
#define SCIPerrorMessage
Definition: pub_message.h:45
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4113
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:12591
interval arithmetics for provable bounds
static SCIP_RETCODE removeFixedVariables(SCIP *scip, SCIP_CONS *cons)
int SCIPhashmapGetNEntries(SCIP_HASHMAP *hashmap)
Definition: misc.c:3143
void SCIPintervalSetEmpty(SCIP_INTERVAL *resultant)
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_Real SCIPgetRowprepViolation(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol)
SCIP_HASHMAPENTRY * SCIPhashmapGetEntry(SCIP_HASHMAP *hashmap, int entryidx)
Definition: misc.c:3151
void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46976
SCIP_RETCODE SCIPaddConsLocal(SCIP *scip, SCIP_CONS *cons, SCIP_NODE *validnode)
Definition: scip.c:13216
SCIP_RETCODE SCIPaddNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition: scip.c:31484
SCIP_VAR ** vars
enum SCIP_NlpSolStat SCIP_NLPSOLSTAT
Definition: type_nlpi.h:69
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:13297
SCIP_Real SCIPintervalGetInf(SCIP_INTERVAL interval)
static SCIP_RETCODE computeViolation(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *solviolbounds)
static SCIP_DECL_CONSDELETE(consDeleteQuadratic)
static SCIP_DECL_CONSPARSE(consParseQuadratic)
SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
Definition: lp.c:16593
SCIP_RETCODE SCIPreleaseNlRow(SCIP *scip, SCIP_NLROW **nlrow)
Definition: scip.c:32299
static SCIP_RETCODE presolveUpgrade(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Bool *upgraded, int *nupgdconss, int *naddconss, SCIP_PRESOLTIMING presoltiming)
static SCIP_RETCODE presolveDisaggregateMarkComponent(SCIP *scip, SCIP_CONSDATA *consdata, int quadvaridx, SCIP_HASHMAP *var2component, int componentnr, int *componentsize)
SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: scip.c:19311
static SCIP_RETCODE catchQuadVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons, int quadvarpos)
SCIP_Real * SCIPgetCoefsLinearVarsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIPInterval sqrt(const SCIPInterval &x)
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip.h:22633
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip.c:46731
int SCIPgetLinvarMayDecreaseQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcheckCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool checkintegrality, SCIP_Bool checklprows, SCIP_Bool printreason, SCIP_RESULT *result)
Definition: scip.c:28690
SCIP_Bool SCIPsortedvecFindPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void *val, int len, int *pos)
void SCIPhashmapEntrySetImage(SCIP_HASHMAPENTRY *entry, void *image)
Definition: misc.c:3192
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:21788
static SCIP_DECL_CONSCHECK(consCheckQuadratic)
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:7986
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8205
#define SCIP_EVENTTYPE_IMPLADDED
Definition: type_event.h:71
static SCIP_DECL_CONSPRESOL(consPresolQuadratic)
void SCIPaddRowprepSide(SCIP_ROWPREP *rowprep, SCIP_Real side)
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:155
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16662
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip.c:6085
static SCIP_DECL_CONSTRANS(consTransQuadratic)
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:2826
constraint handler for quadratic constraints
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4133
SCIP_RETCODE SCIPcreateRowprep(SCIP *scip, SCIP_ROWPREP **rowprep, SCIP_SIDETYPE sidetype, SCIP_Bool local)
#define CONSHDLR_CHECKPRIORITY
SCIP_RETCODE SCIPmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:28602
static SCIP_RETCODE registerBranchingCandidates(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, int *nnotify)
SCIP_HEUR * SCIPsolGetHeur(SCIP_SOL *sol)
Definition: sol.c:2548
SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:39041
int SCIPgetNNlpis(SCIP *scip)
Definition: scip.c:9602
#define REALABS(x)
Definition: def.h:173
SCIP_RETCODE SCIPsetNLPInitialGuessSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:31561
SCIP_RETCODE SCIPgetNlRowQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_NLROW **nlrow)
SCIP_RETCODE SCIPcreateChild(SCIP *scip, SCIP_NODE **node, SCIP_Real nodeselprio, SCIP_Real estimate)
Definition: scip.c:37577
SCIP_QUADELEM * SCIPnlrowGetQuadElems(SCIP_NLROW *nlrow)
Definition: nlp.c:3332
SCIP_Real SCIPgetSepaMinEfficacy(SCIP *scip)
Definition: scip.c:7583
#define SCIP_CALL(x)
Definition: def.h:350
unsigned int SCIP_PRESOLTIMING
Definition: type_timing.h:52
#define CONSHDLR_ENFOPRIORITY
SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
Definition: var.c:17080
SCIP_Real sup
Definition: intervalarith.h:40
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47324
void SCIPintervalSet(SCIP_INTERVAL *resultant, SCIP_Real value)
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:16494
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip.c:1360
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8225
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip.c:34661
static void rowprepCleanupScaledown(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_Real *viol, SCIP_Real minviol)
#define SCIPdebugGetSolVal(scip, var, val)
Definition: debug.h:262
static SCIP_RETCODE rowprepCleanupSortTerms(SCIP *scip, SCIP_ROWPREP *rowprep)
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:50
SCIP_BILINTERM * SCIPgetBilinTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
#define SCIP_EVENTTYPE_BOUNDTIGHTENED
Definition: type_event.h:106
SCIP_RETCODE LapackDsyev(SCIP_Bool computeeigenvectors, int N, SCIP_Real *a, SCIP_Real *w)
SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
Definition: lp.c:16430
SCIP_NLPSOLSTAT SCIPnlpiGetSolstat(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem)
Definition: nlpi.c:511
SCIP_RETCODE SCIPnlpiSetObjective(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem, int nlins, const int *lininds, const SCIP_Real *linvals, int nquadelems, const SCIP_QUADELEM *quadelems, const int *exprvaridxs, const SCIP_EXPRTREE *exprtree, const SCIP_Real constant)
Definition: nlpi.c:300
#define SCIP_EVENTTYPE_UBCHANGED
Definition: type_event.h:105
SCIP_Bool SCIPhasPrimalRay(SCIP *scip)
Definition: scip.c:41075
void SCIPaddSquareSecant(SCIP *scip, SCIP_Real sqrcoef, SCIP_Real lb, SCIP_Real ub, SCIP_Real refpoint, SCIP_Real *lincoef, SCIP_Real *linconstant, SCIP_Bool *success)
Definition: scip.c:33359
int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4515
static SCIP_RETCODE consdataEnsureAdjBilinSize(SCIP *scip, SCIP_QUADVARTERM *quadvarterm, int num)
SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
Definition: scip.c:47051
static SCIP_RETCODE proposeFeasibleSolution(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool *success)
SCIP_Real SCIPgetRhsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPexprgraphGetNodeQuadraticConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13110
SCIP_RETCODE SCIPgetViolationQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *violation)
SCIP_Bool SCIPvarIsOriginal(SCIP_VAR *var)
Definition: var.c:16791
SCIP_RETCODE SCIPaddBilinTermQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Real coef)
SCIP_RETCODE SCIPnlpiFreeProblem(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM **problem)
Definition: nlpi.c:224
Ipopt NLP interface.
static SCIP_RETCODE computeInteriorPoint(SCIP *scip, SCIP_CONS *cons, char method, SCIP_Bool *success)
static SCIP_RETCODE propagateBoundsTightenVarUb(SCIP *scip, SCIP_CONS *cons, SCIP_Real intervalinfty, SCIP_VAR *var, SCIP_Real bnd, SCIP_RESULT *result, int *nchgbds)
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip.h:22620
SCIP_Real * SCIProwGetVals(SCIP_ROW *row)
Definition: lp.c:16440
SCIP_BOUNDTYPE * SCIPvarGetImplTypes(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17586
#define CONSHDLR_NEEDSCONS
static unsigned int nextPowerOf2(unsigned int v)
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:982
static SCIP_DECL_CONSINITLP(consInitlpQuadratic)
SCIP_Real side
#define SCIP_Bool
Definition: def.h:61
static SCIP_DECL_CONSFREE(consFreeQuadratic)
SCIP_RETCODE SCIPcatchEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip.c:41158
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip.c:29293
static SCIP_RETCODE presolveDisaggregate(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *naddconss)
SCIP_Bool SCIPexprgraphAreAllNodeChildrenVars(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14611
static void rowprepCleanupIntegralCoefs(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_Real *viol)
#define CONSHDLR_DELAYSEPA
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyQuadratic)
static SCIP_RETCODE registerBranchingCandidatesCentrality(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, int *nnotify)
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:959
static SCIP_RETCODE computeGauge(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons)
static SCIP_RETCODE generateCutFactorable(SCIP *scip, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_Real *ref, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip.c:30402
SCIP_Real SCIPgetLhsNonlinear(SCIP *scip, SCIP_CONS *cons)
#define NONLINCONSUPGD_PRIORITY
int SCIPgetDepth(SCIP *scip)
Definition: scip.c:43045
SCIP_RETCODE SCIPnlpiSetIntPar(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem, SCIP_NLPPARAM type, int ival)
Definition: nlpi.c:636
SCIP_Real SCIPlpfeastol(SCIP *scip)
Definition: scip.c:46457
constraint handler for nonlinear constraints
int SCIPvarGetNImpls(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17554
void SCIPintervalSolveBivariateQuadExpressionAllScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_Real ax, SCIP_Real ay, SCIP_Real axy, SCIP_Real bx, SCIP_Real by, SCIP_INTERVAL rhs, SCIP_INTERVAL xbnds, SCIP_INTERVAL ybnds)
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip.c:29091
void SCIPmergeRowprepTerms(SCIP *scip, SCIP_ROWPREP *rowprep)
int SCIPvarGetNLocksUp(SCIP_VAR *var)
Definition: var.c:3217
#define MAX(x, y)
Definition: tclique_def.h:75
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:10082
SCIP_NLPTERMSTAT SCIPnlpiGetTermstat(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem)
Definition: nlpi.c:523
static SCIP_RETCODE sortAllBilinTerms(SCIP *scip, SCIP_BILINTERM *bilinterms, int nbilinterms, SCIP_CONS **bilinconss, int *bilinposs)
static SCIP_DECL_CONSEXITSOL(consExitsolQuadratic)
static SCIP_RETCODE replaceByLinearConstraints(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool *addedcons, SCIP_Bool *reduceddom, SCIP_Bool *infeasible)
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:34772
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8006
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11353
methods for debugging
static SCIP_RETCODE generateCutLTI(SCIP *scip, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_Real *ref, SCIP_SOL *sol, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
SCIP_RETCODE SCIPcreateEmptyRowSepa(SCIP *scip, SCIP_ROW **row, SCIP_SEPA *sepa, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip.c:30431
static void consdataSortLinearVars(SCIP_CONSDATA *consdata)
SCIP_RETCODE SCIPsetConshdlrDisable(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDISABLE((*consdisable)))
Definition: scip.c:6452
SCIP_RETCODE SCIPdropEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip.c:41192
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip.c:38535
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8185
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8155
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17124
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip.c:41272
SCIP_RETCODE SCIPcreateVar(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_DECL_VARCOPY((*varcopy)), SCIP_VARDATA *vardata)
Definition: scip.c:17619
SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
Definition: scip.c:37272
void SCIPintervalAdd(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_Real SCIPintervalGetSup(SCIP_INTERVAL interval)
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:116
#define ROWPREP_SCALEUP_MAXSIDE
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:21714
static SCIP_Real getInteriority(SCIP *scip, SCIP_Real lbx, SCIP_Real ubx, SCIP_Real refx, SCIP_Real lby, SCIP_Real uby, SCIP_Real refy)
SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:38994
#define infty2infty(infty1, infty2, val)
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip.c:6498
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata)
Constraint handler for linear constraints in their most general form, .
static SCIP_RETCODE createNlRow(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisCutApplicable(SCIP *scip, SCIP_ROW *cut)
Definition: scip.c:34618
int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition: var.c:17044
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
Definition: scip.c:47039
SCIP_Real * SCIPvarGetImplBounds(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17600
#define CONSHDLR_NAME
#define BMSclearMemory(ptr)
Definition: memory.h:111
#define SCIP_EVENTTYPE_GBDCHANGED
Definition: type_event.h:103
static SCIP_Bool consdataCheckBilinTermsSort(SCIP_CONSDATA *consdata)
SCIP_RETCODE SCIPgetRowprepRowCons(SCIP *scip, SCIP_ROW **row, SCIP_ROWPREP *rowprep, SCIP_CONSHDLR *conshdlr)
char name[SCIP_MAXSTRLEN]
SCIP_RETCODE SCIPsetConshdlrEnable(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENABLE((*consenable)))
Definition: scip.c:6429
void * SCIPexprgraphGetNodeVar(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13039
int SCIPgetNBinVars(SCIP *scip)
Definition: scip.c:11857
SCIP_Bool SCIPisLinearLocalQuadratic(SCIP *scip, SCIP_CONS *cons)
static void generateCutLTIcomputeCoefs(SCIP *scip, SCIP_Real xl, SCIP_Real xu, SCIP_Real x0, SCIP_Real yl, SCIP_Real yu, SCIP_Real y0_, SCIP_Real wl, SCIP_Real wu, SCIP_Real w0, SCIP_Real *cx, SCIP_Real *cy, SCIP_Real *cw, SCIP_Real *c0, SCIP_Bool *success)
static SCIP_DECL_CONSENFORELAX(consEnforelaxQuadratic)
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip.c:35836
static SCIP_Bool generateCutLTIfindIntersection(SCIP *scip, SCIP_Real x0, SCIP_Real y0_, SCIP_Real x1, SCIP_Real y1_, SCIP_Real wl, SCIP_Real wu, SCIP_Real *xl, SCIP_Real *yl, SCIP_Real *xu, SCIP_Real *yu)
SCIP_Real * SCIPexprgraphGetNodeQuadraticLinearCoefs(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13122
#define ROWPREP_SCALEUP_MINVIOLFACTOR
int SCIPgetNVars(SCIP *scip)
Definition: scip.c:11812
SCIP_RETCODE SCIPcheckCurvatureQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPnodeGetEstimate(SCIP_NODE *node)
Definition: tree.c:7372
void SCIPenableNLP(SCIP *scip)
Definition: scip.c:31218
SCIP_Bool SCIPinDive(SCIP *scip)
Definition: scip.c:35802
static SCIP_RETCODE registerLargeRelaxValueVariableForBranching(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_VAR **brvar)
SCIP_QUADVAREVENTDATA * eventdata
SCIP_VAR ** SCIPvarGetImplVars(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17571
SCIP_RETCODE SCIPcreateConsLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip.c:6229
enum SCIP_ExprCurv SCIP_EXPRCURV
Definition: type_expr.h:93
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip.c:30540
int SCIPgetLinvarMayIncreaseQuadratic(SCIP *scip, SCIP_CONS *cons)
int SCIPgetNLinearVarsQuadratic(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE addBilinearTerm(SCIP *scip, SCIP_CONS *cons, int var1pos, int var2pos, SCIP_Real coef)
SCIP_RETCODE SCIPcreateNLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip.c:37948
static void consdataMoveQuadVarTerm(SCIP_CONSDATA *consdata, int oldpos, int newpos)
int SCIPvarGetNLocksDown(SCIP_VAR *var)
Definition: var.c:3162
void SCIPsort(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
Definition: misc.c:5081
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47002
SCIP_RETCODE SCIPcopyRowprep(SCIP *scip, SCIP_ROWPREP **target, SCIP_ROWPREP *source)
static SCIP_RETCODE consdataCreateEmpty(SCIP *scip, SCIP_CONSDATA **consdata)
static SCIP_DECL_CONSGETNVARS(consGetNVarsQuadratic)
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
Definition: scip.c:47112
SCIP_RETCODE SCIPaddCharParam(SCIP *scip, const char *name, const char *desc, char *valueptr, SCIP_Bool isadvanced, char defaultvalue, const char *allowedvalues, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:4349
SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
Definition: lp.c:16254
int SCIPgetNLinearVarsNonlinear(SCIP *scip, SCIP_CONS *cons)
void SCIPfreeParseVarsPolynomialData(SCIP *scip, SCIP_VAR ****monomialvars, SCIP_Real ***monomialexps, SCIP_Real **monomialcoefs, int **monomialnvars, int nmonomials)
Definition: scip.c:18676
SCIP_RETCODE SCIPgetVarCopy(SCIP *sourcescip, SCIP *targetscip, SCIP_VAR *sourcevar, SCIP_VAR **targetvar, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global, SCIP_Bool *success)
Definition: scip.c:1920
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:11492
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8016
#define CONSHDLR_DESC
SCIP_RETCODE SCIPsetConshdlrInit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINIT((*consinit)))
Definition: scip.c:6109
SCIP_Real SCIPintervalQuadUpperBound(SCIP_Real infinity, SCIP_Real a, SCIP_INTERVAL b_, SCIP_INTERVAL x)
SCIP_RETCODE SCIPsetConshdlrExit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXIT((*consexit)))
Definition: scip.c:6133
static SCIP_RETCODE dropVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons)
static SCIP_DECL_CONSGETVARS(consGetVarsQuadratic)
#define SCIP_EVENTTYPE_FORMAT
Definition: type_event.h:135
static void rowprepCleanupSide(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_Real *viol)
static SCIP_DECL_CONSCOPY(consCopyQuadratic)
static SCIP_DECL_CONSINIT(consInitQuadratic)
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip.c:27761
static SCIP_RETCODE unlockLinearVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
void SCIPintervalSetRoundingModeUpwards(void)
static SCIP_RETCODE computeReferencePointProjection(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *refsol, SCIP_Real *ref)
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip.c:6253
NLP local search primal heuristic using sub-SCIPs.
static SCIP_RETCODE generateCutSol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_SOL *refsol, SCIP_SIDETYPE violside, SCIP_ROW **row, SCIP_Real *efficacy, SCIP_Bool checkcurvmultivar, SCIP_Real minefficacy, char mode)
void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition: scip.c:13790
SCIP_Real SCIPgetRowLPFeasibility(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30977
SCIP_RETCODE SCIPgetFeasibilityQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *feasibility)
SCIP_RETCODE SCIPsortQuadVarTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPeventGetOldbound(SCIP_EVENT *event)
Definition: event.c:1138
int SCIPscaleRowprep(SCIP_ROWPREP *rowprep, SCIP_Real factor)
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:47375
void SCIPsortDownRealRealPtr(SCIP_Real *realarray1, SCIP_Real *realarray2, void **ptrarray, int len)
SCIP_RETCODE SCIPgetNLPFracVars(SCIP *scip, SCIP_VAR ***fracvars, SCIP_Real **fracvarssol, SCIP_Real **fracvarsfrac, int *nfracvars, int *npriofracvars)
Definition: scip.c:31736
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:16781
SCIP_RETCODE SCIPaggregateVars(SCIP *scip, SCIP_VAR *varx, SCIP_VAR *vary, SCIP_Real scalarx, SCIP_Real scalary, SCIP_Real rhs, SCIP_Bool *infeasible, SCIP_Bool *redundant, SCIP_Bool *aggregated)
Definition: scip.c:25684
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:18732
#define SCIP_Real
Definition: def.h:149
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8235
SCIP_RETCODE SCIPaddVarsToRow(SCIP *scip, SCIP_ROW *row, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip.c:30694
SCIP_RETCODE SCIPaddToNlpiProblemQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *nlpiprob, SCIP_HASHMAP *scipvar2nlpivar, SCIP_Bool names)
SCIP_VAR ** SCIPgetLinearVarsNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip.c:1145
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip.c:6567
void SCIPintervalMulScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
SCIP_Bool SCIPhaveVarsCommonClique(SCIP *scip, SCIP_VAR *var1, SCIP_Bool value1, SCIP_VAR *var2, SCIP_Bool value2, SCIP_Bool regardimplics)
Definition: scip.c:24963
static SCIP_RETCODE computeReferencePointGauge(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *refsol, SCIP_Real *ref, SCIP_Bool *success)
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8175
static SCIP_RETCODE checkFactorable(SCIP *scip, SCIP_CONS *cons)
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12957
#define SCIP_INVALID
Definition: def.h:169
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8165
void SCIPsortPtrReal(void **ptrarray, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip.c:31160
void SCIPsortInt(int *intarray, int len)
static SCIP_RETCODE propagateBoundsTightenVarLb(SCIP *scip, SCIP_CONS *cons, SCIP_Real intervalinfty, SCIP_VAR *var, SCIP_Real bnd, SCIP_RESULT *result, int *nchgbds)
SCIP_RETCODE SCIPcreateConsQuadratic2(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadvarterms, SCIP_QUADVARTERM *quadvarterms, int nbilinterms, SCIP_BILINTERM *bilinterms, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable)
static SCIP_RETCODE delLinearCoefPos(SCIP *scip, SCIP_CONS *cons, int pos)
#define SCIP_Longint
Definition: def.h:134
static SCIP_RETCODE consdataEnsureBilinSize(SCIP *scip, SCIP_CONSDATA *consdata, int num)
SCIP_RETCODE SCIPaddQuadVarLinearCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_BOUNDTYPE SCIPvarGetBestBoundType(SCIP_VAR *var)
Definition: var.c:17388
SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:38740
#define SCIPdebugAddSolVal(scip, var, val)
Definition: debug.h:261
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:16827
static SCIP_DECL_CONSLOCK(consLockQuadratic)
SCIP_RETCODE SCIPcreateConsBounddisjunction(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_BOUNDTYPE *boundtypes, SCIP_Real *bounds, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPparseVarsPolynomial(SCIP *scip, const char *str, SCIP_VAR ****monomialvars, SCIP_Real ***monomialexps, SCIP_Real **monomialcoefs, int **monomialnvars, int *nmonomials, char **endptr, SCIP_Bool *success)
Definition: scip.c:18324
int SCIP_ROUNDMODE
Definition: intervalarith.h:46
void SCIPintervalMulInf(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
void SCIPintervalSub(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:47076
SCIP_Real ineqoverest[6]
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46989
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:49
static SCIP_DECL_EVENTEXEC(processVarEvent)
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17342
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip.h:22605
static SCIP_RETCODE addLinearCoef(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
static SCIP_RETCODE presolveDisaggregateMergeComponents(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_HASHMAP *var2component, int nvars, int *ncomponents, int *componentssize)
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:16804
SCIP_RETCODE SCIPupdateStartpointHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *solcand, SCIP_Real violation)
Definition: heur_subnlp.c:2425
SCIP_Bool SCIPconsIsMarkedPropagate(SCIP_CONS *cons)
Definition: cons.c:8195
#define CONSHDLR_PROP_TIMING
#define SCIP_DECL_QUADCONSUPGD(x)
static SCIP_DECL_CONSPROP(consPropQuadratic)
SCIP_Real * coefs
SCIP_NLPI ** SCIPgetNlpis(SCIP *scip)
Definition: scip.c:9589
static SCIP_RETCODE delQuadVarTermPos(SCIP *scip, SCIP_CONS *cons, int pos)
SCIP_Real SCIPgetUpperbound(SCIP *scip)
Definition: scip.c:43426
static SCIP_DECL_CONSPRINT(consPrintQuadratic)
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:2874
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:112
SCIP_Bool SCIPisSumLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47210
#define ROWPREP_SCALEUP_MAXMINCOEF
#define CONSHDLR_SEPAFREQ
static SCIP_RETCODE computeED(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons)
SCIP_QUADVARTERM * SCIPgetQuadVarTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcreateNlRow(SCIP *scip, SCIP_NLROW **nlrow, const char *name, SCIP_Real constant, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadvars, SCIP_VAR **quadvars, int nquadelems, SCIP_QUADELEM *quadelems, SCIP_EXPRTREE *expression, SCIP_Real lhs, SCIP_Real rhs, SCIP_EXPRCURV curvature)
Definition: scip.c:32191
static SCIP_RETCODE propagateBounds(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_RESULT *result, int *nchgbds)
int SCIPexprgraphGetNodeQuadraticNQuadElements(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13146
SCIP_EXPRGRAPHNODE * SCIPgetExprgraphNodeNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
Definition: scip.c:47161
void SCIPprintRowprep(SCIP *scip, SCIP_ROWPREP *rowprep, FILE *file)
constraint handler for bound disjunction constraints
void SCIPintervalAddScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip.c:6181
SCIP_Longint SCIPgetNLPs(SCIP *scip)
Definition: scip.c:42314
#define SCIPABORT()
Definition: def.h:322
static void updateBilinearRelaxation(SCIP *scip, SCIP_VAR *RESTRICT x, SCIP_VAR *RESTRICT y, SCIP_Real bilincoef, SCIP_SIDETYPE violside, SCIP_Real refx, SCIP_Real refy, SCIP_Real *RESTRICT ineqs, int nineqs, SCIP_Real mccormickval, SCIP_Real *RESTRICT bestcoefx, SCIP_Real *RESTRICT bestcoefy, SCIP_Real *RESTRICT bestconst, SCIP_Real *RESTRICT bestval, SCIP_Bool *success)
SCIP_Real SCIPround(SCIP *scip, SCIP_Real val)
Definition: scip.c:47173
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:16853
static SCIP_RETCODE consdataFindQuadVarTerm(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR *var, int *pos)
SCIP_ROUNDMODE SCIPintervalGetRoundingMode(void)
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition: misc.c:8448
SCIP_RETCODE SCIPgetRowprepRowSepa(SCIP *scip, SCIP_ROW **row, SCIP_ROWPREP *rowprep, SCIP_SEPA *sepa)
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip.c:38911
static SCIP_RETCODE mergeAndCleanQuadVarTerms(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisInRestart(SCIP *scip)
Definition: scip.c:17582
SCIP_SOL * SCIPeventGetSol(SCIP_EVENT *event)
Definition: event.c:1223
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
#define SCIPduplicateBlockMemory(scip, ptr, source)
Definition: scip.h:22597
SCIP_Bool SCIPisRelLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47700
static SCIP_RETCODE consdataEnsureLinearVarsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num)
static SCIP_RETCODE enforceConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_Bool solinfeasible, SCIP_RESULT *result)
void SCIPintervalSetRoundingModeDownwards(void)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
Definition: scip.c:47149
static SCIP_RETCODE computeViolations(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool *solviolbounds, SCIP_CONS **maxviolcon)
SCIP_Bool SCIPisConvexQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPgetPrimalRayVal(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:41093
static SCIP_DECL_CONSDISABLE(consDisableQuadratic)
SCIP_RETCODE SCIPgetActivityQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *activity)
static SCIP_Bool hasQuadvarHpProperty(SCIP *scip, SCIP_CONSDATA *consdata, int idx)
SCIP_Bool SCIPintervalIsSubsetEQ(SCIP_Real infinity, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
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 SCIP_RETCODE processCut(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Real efficacy, SCIP_Real minefficacy, SCIP_Bool inenforcement, SCIP_Real *bestefficacy, SCIP_RESULT *result)
void SCIPintervalSolveUnivariateQuadExpressionPositive(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL rhs)
int SCIPgetNSepaRounds(SCIP *scip)
Definition: scip.c:42884
static SCIP_RETCODE catchLinearVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons, int linvarpos)
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:16949
void SCIPaddSquareLinearization(SCIP *scip, SCIP_Real sqrcoef, SCIP_Real refpoint, SCIP_Bool isint, SCIP_Real *lincoef, SCIP_Real *linconstant, SCIP_Bool *success)
Definition: scip.c:33291
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip.h:22624
uint64_t SCIP_EVENTTYPE
Definition: type_event.h:134
SCIP_RETCODE SCIPnlpiSetRealPar(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem, SCIP_NLPPARAM type, SCIP_Real dval)
Definition: nlpi.c:671
void SCIPaddRowprepConstant(SCIP_ROWPREP *rowprep, SCIP_Real constant)
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip.c:5994
static SCIP_RETCODE generateCutUnboundedLP(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_ROW **row, SCIP_Real *rowrayprod, SCIP_Bool checkcurvmultivar)
void SCIPintervalQuad(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_Real sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL xrng)
enum SCIP_SideType SCIP_SIDETYPE
Definition: type_lp.h:58
SCIP_QUADELEM * SCIPexprgraphGetNodeQuadraticQuadElements(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13134