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-2020 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 visit scipopt.org. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file cons_quadratic.c
17  * @ingroup DEFPLUGINS_CONS
18  * @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$
19  * @author Stefan Vigerske
20  * @author Benjamin Mueller
21  * @author Felipe Serrano
22  *
23  * @todo SCIP might fix linear variables on +/- infinity; remove them in presolve and take care later
24  * @todo round constraint sides to integers if all coefficients and variables are (impl.) integer
25  * @todo constraints in one variable should be replaced by linear or bounddisjunction constraint
26  * @todo check if some quadratic terms appear in several constraints and try to simplify (e.g., nous1)
27  * @todo skip separation in enfolp if for current LP (check LP id) was already separated
28  * @todo watch unbounded variables to enable/disable propagation
29  * @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
30  * @todo underestimate for multivariate concave quadratic terms as in cons_nonlinear
31  */
32 
33 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
34 
35 #define SCIP_PRIVATE_ROWPREP
36 
37 #include "blockmemshell/memory.h"
38 #include <ctype.h>
39 #include "nlpi/nlpi.h"
40 #include "nlpi/nlpi_ipopt.h"
41 #include "nlpi/pub_expr.h"
42 #include "nlpi/type_expr.h"
43 #include "scip/cons_and.h"
45 #include "scip/cons_linear.h"
46 #include "scip/cons_nonlinear.h"
47 #include "scip/cons_quadratic.h"
48 #include "scip/cons_varbound.h"
49 #include "scip/debug.h"
50 #include "scip/heur_subnlp.h"
51 #include "scip/heur_trysol.h"
52 #include "scip/intervalarith.h"
53 #include "scip/pub_cons.h"
54 #include "scip/pub_event.h"
55 #include "scip/pub_heur.h"
56 #include "scip/pub_lp.h"
57 #include "scip/pub_message.h"
58 #include "scip/pub_misc.h"
59 #include "scip/pub_misc_sort.h"
60 #include "scip/pub_nlp.h"
61 #include "scip/pub_sol.h"
62 #include "scip/pub_tree.h"
63 #include "scip/pub_var.h"
64 #include "scip/scip_branch.h"
65 #include "scip/scip_cons.h"
66 #include "scip/scip_copy.h"
67 #include "scip/scip_cut.h"
68 #include "scip/scip_event.h"
69 #include "scip/scip_general.h"
70 #include "scip/scip_heur.h"
71 #include "scip/scip_lp.h"
72 #include "scip/scip_mem.h"
73 #include "scip/scip_message.h"
74 #include "scip/scip_nlp.h"
75 #include "scip/scip_nonlinear.h"
76 #include "scip/scip_numerics.h"
77 #include "scip/scip_param.h"
78 #include "scip/scip_prob.h"
79 #include "scip/scip_probing.h"
80 #include "scip/scip_sepa.h"
81 #include "scip/scip_sol.h"
82 #include "scip/scip_solve.h"
83 #include "scip/scip_solvingstats.h"
84 #include "scip/scip_tree.h"
85 #include "scip/scip_var.h"
86 #include <string.h>
87 
88 /* Inform compiler that this code accesses the floating-point environment, so that
89  * certain optimizations should be omitted (http://www.cplusplus.com/reference/cfenv/FENV_ACCESS/).
90  * Not supported by Clang (gives warning) and GCC (silently), at the moment.
91  */
92 #if defined(__INTEL_COMPILER) || defined(_MSC_VER)
93 #pragma fenv_access (on)
94 #elif defined __GNUC__
95 #pragma STDC FENV_ACCESS ON
96 #endif
97 
98 /* constraint handler properties */
99 #define CONSHDLR_NAME "quadratic"
100 #define CONSHDLR_DESC "quadratic constraints of the form lhs <= b' x + x' A x <= rhs"
101 #define CONSHDLR_SEPAPRIORITY 10 /**< priority of the constraint handler for separation */
102 #define CONSHDLR_ENFOPRIORITY -50 /**< priority of the constraint handler for constraint enforcing */
103 #define CONSHDLR_CHECKPRIORITY -4000000 /**< priority of the constraint handler for checking feasibility */
104 #define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
105 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
106 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
107  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
108 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
109 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
110 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
111 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
113 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP /**< propagation timing mask of the constraint handler */
114 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS /**< presolving timing of the constraint handler (fast, medium, or exhaustive) */
116 #define MAXDNOM 10000LL /**< maximal denominator for simple rational fixed values */
117 #define NONLINCONSUPGD_PRIORITY 40000 /**< priority of upgrading nonlinear constraints */
118 #define INITLPMAXVARVAL 1000.0 /**< maximal absolute value of variable for still generating a linearization cut at that point in initlp */
120 /* Activating this define enables reformulation of bilinear terms x*y with implications from x to y into linear terms.
121  * 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,
122  * then the implication may not be enforced in a solution.
123  * This issue need to be fixed before this feature can be enabled.
124  */
125 /* #define CHECKIMPLINBILINEAR */
126 
127 /* enable new propagation for bivariate quadratic terms */
128 #define PROPBILINNEW
130 /* epsilon for differentiating between a boundary and interior point */
131 #define INTERIOR_EPS 1e-1
133 /* scaling factor for gauge function */
134 #define GAUGESCALE 0.99999
136 #define ROWPREP_SCALEUP_VIOLNONZERO (10.0*SCIPepsilon(scip)) /**< minimal violation for considering up-scaling of rowprep (we want to avoid upscaling very small violations) */
137 #define ROWPREP_SCALEUP_MINVIOLFACTOR 2.0 /**< scale up will target a violation of ~MINVIOLFACTOR*minviol, where minviol is given by caller */
138 #define ROWPREP_SCALEUP_MAXMINCOEF (1.0 / SCIPfeastol(scip)) /**< scale up only if min. coef is below this number (before scaling) */
139 #define ROWPREP_SCALEUP_MAXMAXCOEF SCIPgetHugeValue(scip) /**< scale up only if max. coef will not exceed this number by scaling */
140 #define ROWPREP_SCALEUP_MAXSIDE SCIPgetHugeValue(scip) /**< scale up only if side will not exceed this number by scaling */
141 #define ROWPREP_SCALEDOWN_MINMAXCOEF (1.0 / SCIPfeastol(scip)) /**< scale down if max. coef is at least this number (before scaling) */
142 #define ROWPREP_SCALEDOWN_MINCOEF SCIPfeastol(scip) /**< scale down only if min. coef does not drop below this number by scaling */
144 /*
145  * Data structures
146  */
147 
148 /** eventdata for variable bound change events in quadratic constraints */
149 struct SCIP_QuadVarEventData
150 {
151  SCIP_CONS* cons; /**< the constraint */
152  int varidx; /**< the index of the variable which bound change is caught, positive for linear variables, negative for quadratic variables */
153  int filterpos; /**< position of eventdata in SCIP's event filter */
154 };
155 
156 /** Data of a quadratic constraint. */
157 struct SCIP_ConsData
158 {
159  SCIP_Real lhs; /**< left hand side of constraint */
160  SCIP_Real rhs; /**< right hand side of constraint */
161 
162  int nlinvars; /**< number of linear variables */
163  int linvarssize; /**< length of linear variable arrays */
164  SCIP_VAR** linvars; /**< linear variables */
165  SCIP_Real* lincoefs; /**< coefficients of linear variables */
166  SCIP_QUADVAREVENTDATA** lineventdata; /**< eventdata for bound change of linear variable */
167 
168  int nquadvars; /**< number of variables in quadratic terms */
169  int quadvarssize; /**< length of quadratic variable terms arrays */
170  SCIP_QUADVARTERM* quadvarterms; /**< array with quadratic variable terms */
171 
172  int nbilinterms; /**< number of bilinear terms */
173  int bilintermssize; /**< length of bilinear term arrays */
174  SCIP_BILINTERM* bilinterms; /**< bilinear terms array */
175  int* bilintermsidx; /**< unique index of each bilinear term xy in the bilinestimators array of the constraint handler data */
176 
177  SCIP_NLROW* nlrow; /**< a nonlinear row representation of this constraint */
178 
179  unsigned int linvarssorted:1; /**< are the linear variables already sorted? */
180  unsigned int linvarsmerged:1; /**< are equal linear variables already merged? */
181  unsigned int quadvarssorted:1; /**< are the quadratic variables already sorted? */
182  unsigned int quadvarsmerged:1; /**< are equal quadratic variables already merged? */
183  unsigned int bilinsorted:1; /**< are the bilinear terms already sorted? */
184  unsigned int bilinmerged:1; /**< are equal bilinear terms (and bilinear terms with zero coefficient) already merged? */
185 
186  unsigned int isconvex:1; /**< is quadratic function is convex ? */
187  unsigned int isconcave:1; /**< is quadratic function is concave ? */
188  unsigned int iscurvchecked:1; /**< is quadratic function checked on convexity or concavity ? */
189  unsigned int isremovedfixings:1; /**< did we removed fixed/aggr/multiaggr variables ? */
190  unsigned int ispropagated:1; /**< was the constraint propagated with respect to the current bounds ? */
191  unsigned int ispresolved:1; /**< did we checked for possibilities of upgrading or implicit integer variables ? */
192  unsigned int initialmerge:1; /**< did we perform an initial merge and clean in presolving yet ? */
193 #ifdef CHECKIMPLINBILINEAR
194  unsigned int isimpladded:1; /**< has there been an implication added for a binary variable in a bilinear term? */
195 #endif
196  unsigned int isgaugeavailable:1; /**< is the gauge function computed? */
197  unsigned int isedavailable:1; /**< is the eigen decomposition of A available? */
198 
199  SCIP_Real minlinactivity; /**< sum of minimal activities of all linear terms with finite minimal activity */
200  SCIP_Real maxlinactivity; /**< sum of maximal activities of all linear terms with finite maximal activity */
201  int minlinactivityinf; /**< number of linear terms with infinite minimal activity */
202  int maxlinactivityinf; /**< number of linear terms with infinity maximal activity */
203  SCIP_INTERVAL quadactivitybounds; /**< bounds on the activity of the quadratic term, if up to date, otherwise empty interval */
204  SCIP_Real activity; /**< activity of quadratic function w.r.t. current solution */
205  SCIP_Real lhsviol; /**< violation of lower bound by current solution (used temporarily inside constraint handler) */
206  SCIP_Real rhsviol; /**< violation of lower bound by current solution (used temporarily inside constraint handler) */
207 
208  int linvar_maydecrease; /**< index of a variable in linvars that may be decreased without making any other constraint infeasible, or -1 if none */
209  int linvar_mayincrease; /**< index of a variable in linvars that may be increased without making any other constraint infeasible, or -1 if none */
210 
211  SCIP_VAR** sepaquadvars; /**< variables corresponding to quadvarterms to use in separation, only available in solving stage */
212  int* sepabilinvar2pos; /**< position of second variable in bilinear terms to use in separation, only available in solving stage */
213  SCIP_Real lincoefsmin; /**< minimal absolute value of coefficients in linear part, only available in solving stage */
214  SCIP_Real lincoefsmax; /**< maximal absolute value of coefficients in linear part, only available in solving stage */
215 
216  SCIP_Real* factorleft; /**< coefficients of left factor if constraint function is factorable */
217  SCIP_Real* factorright; /**< coefficients of right factor if constraint function is factorable */
218 
219  SCIP_Real* gaugecoefs; /**< coefficients of the gauge function */
220  SCIP_Real gaugeconst; /**< constant of the gauge function */
221  SCIP_Real* interiorpoint; /**< interior point of the region defined by the convex function */
222  SCIP_Real interiorpointval; /**< function value at interior point */
223 
224  SCIP_Real* eigenvalues; /**< eigenvalues of A */
225  SCIP_Real* eigenvectors; /**< orthonormal eigenvectors of A; if A = P D P^T, then eigenvectors is P^T */
226  SCIP_Real* bp; /**< stores b * P where b are the linear coefficients of the quadratic vars */
227  SCIP_Real maxnonconvexity; /**< nonconvexity measure: estimate on largest absolute value of nonconvex eigenvalues */
228 
229  SCIP_Bool isdisaggregated; /**< has the constraint already been disaggregated? if might happen that more disaggreation would be potentially
230  possible, but we reached the maximum number of sparsity components during presolveDisaggregate() */
231 };
232 
233 /** quadratic constraint update method */
235 {
236  SCIP_DECL_QUADCONSUPGD((*quadconsupgd)); /**< method to call for upgrading quadratic constraint */
237  int priority; /**< priority of upgrading method */
238  SCIP_Bool active; /**< is upgrading enabled */
239 };
240 typedef struct SCIP_QuadConsUpgrade SCIP_QUADCONSUPGRADE; /**< quadratic constraint update method */
242 /** structure to store everything needed for using linear inequalities to improve upon the McCormick relaxation */
243 struct BilinearEstimator
244 {
245  SCIP_VAR* x; /**< first variable */
246  SCIP_VAR* y; /**< second variable */
247  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 */
248  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 */
249  SCIP_Real maxnonconvexity; /**< estimate on largest absolute value of nonconvex eigenvalues of all quadratic constraint containing xy */
250  int ninequnderest; /**< total number of inequalities for underestimating xy */
251  int nineqoverest; /**< total number of inequalities for overestimating xy */
252  int nunderest; /**< number of constraints that require to underestimate xy */
253  int noverest; /**< number of constraints that require to overestimate xy */
255  SCIP_Real lastimprfac; /**< last achieved improvement factor */
256 };
257 typedef struct BilinearEstimator BILINESTIMATOR;
259 /** constraint handler data */
260 struct SCIP_ConshdlrData
261 {
262  int replacebinaryprodlength; /**< length of linear term which when multiplied with a binary variable is replaced by an auxiliary variable and an equivalent linear formulation */
263  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 */
264  SCIP_Bool binreforminitial; /**< whether to make constraints added due to replacing products with binary variables initial */
265  SCIP_Bool binreformbinaryonly;/**< whether to consider only binary variables when reformulating products with binary variables */
266  SCIP_Real binreformmaxcoef; /**< factor on 1/feastol to limit coefficients and coef range in linear constraints created by binary reformulation */
267  SCIP_Real cutmaxrange; /**< maximal range (maximal coef / minimal coef) of a cut in order to be added to LP */
268  SCIP_Bool linearizeheursol; /**< whether linearizations of convex quadratic constraints should be added to cutpool when some heuristics finds a new solution */
269  SCIP_Bool checkcurvature; /**< whether functions should be checked for convexity/concavity */
270  SCIP_Bool checkfactorable; /**< whether functions should be checked to be factorable */
271  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) */
272  SCIP_Bool linfeasshift; /**< whether to make solutions in check feasible if possible */
273  int maxdisaggrsize; /**< maximum number of components when disaggregating a quadratic constraint (<= 1: off) */
274  char disaggrmergemethod; /**< method on merging blocks in disaggregation */
275  int maxproprounds; /**< limit on number of propagation rounds for a single constraint within one round of SCIP propagation during solve */
276  int maxproproundspresolve; /**< limit on number of propagation rounds for a single constraint within one presolving round */
277  SCIP_Real sepanlpmincont; /**< minimal required fraction of continuous variables in problem to use solution of NLP relaxation in root for separation */
278  SCIP_Bool enfocutsremovable; /**< are cuts added during enforcement removable from the LP in the same node? */
279  SCIP_Bool gaugecuts; /**< should convex quadratics generated strong cuts via gauge function? */
280  SCIP_Bool projectedcuts; /**< should convex quadratics generated strong cuts via projections? */
281  char interiorcomputation;/**< how the interior point should be computed: 'a'ny point per constraint, 'm'ost interior per constraint */
282  char branchscoring; /**< method to use to compute score of branching candidates */
283  int enfolplimit; /**< maximum number of enforcement round before declaring the LP relaxation
284  * infeasible (-1: no limit); WARNING: if this parameter is not set to -1,
285  * SCIP might declare sub-optimal solutions optimal or feasible instances
286  * infeasible; thus, the result returned by SCIP might be incorrect!
287  */
288  SCIP_HEUR* subnlpheur; /**< a pointer to the subnlp heuristic, if available */
289  SCIP_HEUR* trysolheur; /**< a pointer to the trysol heuristic, if available */
290  SCIP_EVENTHDLR* eventhdlr; /**< our handler for variable bound change events */
291  int newsoleventfilterpos; /**< filter position of new solution event handler, if caught */
292  SCIP_Bool sepanlp; /**< where linearization of the NLP relaxation solution added? */
293  SCIP_NODE* lastenfonode; /**< the node for which enforcement was called the last time (and some constraint was violated) */
294  int nenforounds; /**< counter on number of enforcement rounds for the current node */
295  SCIP_QUADCONSUPGRADE** quadconsupgrades; /**< quadratic constraint upgrade methods for specializing quadratic constraints */
296  int quadconsupgradessize; /**< size of quadconsupgrade array */
297  int nquadconsupgrades; /**< number of quadratic constraint upgrade methods */
298 
299  BILINESTIMATOR* bilinestimators; /**< array containing all required information for using stronger estimators for each bilinear term in all quadratic constraints */
300  int nbilinterms; /**< number of bilinear terms in all quadratic constraints */
301 
302  SCIP_Bool usebilinineqbranch; /**< should linear inequalities be considered when computing the branching scores for bilinear terms? */
303  SCIP_Bool storedbilinearterms; /**< did we already try to store all bilinear terms? */
304 
305  SCIP_Real minscorebilinterms; /**< minimal required score in order to use linear inequalities for tighter bilinear relaxations */
306  SCIP_Real mincurvcollectbilinterms;/**< minimal curvature of constraints to be considered when returning bilinear terms to other plugins */
307  int bilinineqmaxseparounds; /**< maximum number of separation rounds to use linear inequalities for the bilinear term relaxation in a local node */
308 };
309 
310 
311 /*
312  * local methods for managing quadratic constraint update methods
313  */
314 
315 
316 /** checks whether a quadratic constraint upgrade method has already be registered */
317 static
319  SCIP* scip, /**< SCIP data structure */
320  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
321  SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), /**< method to call for upgrading quadratic constraint */
322  const char* conshdlrname /**< name of the constraint handler */
323  )
324 {
325  int i;
326 
327  assert(scip != NULL);
328  assert(conshdlrdata != NULL);
329  assert(quadconsupgd != NULL);
330  assert(conshdlrname != NULL);
331 
332  for( i = conshdlrdata->nquadconsupgrades - 1; i >= 0; --i )
333  {
334  if( conshdlrdata->quadconsupgrades[i]->quadconsupgd == quadconsupgd )
335  {
336  SCIPwarningMessage(scip, "Try to add already known upgrade message for constraint handler <%s>.\n", conshdlrname);
337  return TRUE;
338  }
339  }
340 
341  return FALSE;
342 }
343 
344 /*
345  * Local methods
346  */
347 
348 /** translate from one value of infinity to another
349  *
350  * if val is >= infty1, then give infty2, else give val
351  */
352 #define infty2infty(infty1, infty2, val) ((val) >= (infty1) ? (infty2) : (val))
354 /** catches variable bound change events on a linear variable in a quadratic constraint */
355 static
357  SCIP* scip, /**< SCIP data structure */
358  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
359  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
360  int linvarpos /**< position of variable in linear variables array */
361  )
362 {
363  SCIP_CONSDATA* consdata;
364  SCIP_QUADVAREVENTDATA* eventdata;
365  SCIP_EVENTTYPE eventtype;
366 
367  assert(scip != NULL);
368  assert(eventhdlr != NULL);
369  assert(cons != NULL);
370 
371  consdata = SCIPconsGetData(cons);
372  assert(consdata != NULL);
373 
374  assert(linvarpos >= 0);
375  assert(linvarpos < consdata->nlinvars);
376  assert(consdata->lineventdata != NULL);
377 
378  SCIP_CALL( SCIPallocBlockMemory(scip, &eventdata) );
379 
380  eventdata->cons = cons;
381  eventdata->varidx = linvarpos;
382 
384  if( !SCIPisInfinity(scip, consdata->rhs) )
385  {
386  /* if right hand side is finite, then a tightening in the lower bound of coef*linvar is of interest
387  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
388  if( consdata->lincoefs[linvarpos] > 0.0 )
389  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
390  else
391  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
392  }
393  if( !SCIPisInfinity(scip, -consdata->lhs) )
394  {
395  /* if left hand side is finite, then a tightening in the upper bound of coef*linvar is of interest
396  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
397  if( consdata->lincoefs[linvarpos] > 0.0 )
398  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
399  else
400  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
401  }
402 
403  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->linvars[linvarpos], eventtype, eventhdlr, (SCIP_EVENTDATA*)eventdata, &eventdata->filterpos) );
404 
405  consdata->lineventdata[linvarpos] = eventdata;
406 
407  /* invalidate activity information
408  * NOTE: It could happen that a constraint gets temporary deactivated and some variable bounds change. In this case
409  * we do not recognize those bound changes with the variable events and thus we have to recompute the activities.
410  */
411  consdata->minlinactivity = SCIP_INVALID;
412  consdata->maxlinactivity = SCIP_INVALID;
413  consdata->minlinactivityinf = -1;
414  consdata->maxlinactivityinf = -1;
415 
416  return SCIP_OKAY;
417 }
418 
419 /** drops variable bound change events on a linear variable in a quadratic constraint */
420 static
422  SCIP* scip, /**< SCIP data structure */
423  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
424  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
425  int linvarpos /**< position of variable in linear variables array */
426  )
427 {
428  SCIP_CONSDATA* consdata;
429  SCIP_EVENTTYPE eventtype;
430 
431  assert(scip != NULL);
432  assert(eventhdlr != NULL);
433  assert(cons != NULL);
434 
435  consdata = SCIPconsGetData(cons);
436  assert(consdata != NULL);
437 
438  assert(linvarpos >= 0);
439  assert(linvarpos < consdata->nlinvars);
440  assert(consdata->lineventdata != NULL);
441  assert(consdata->lineventdata[linvarpos] != NULL);
442  assert(consdata->lineventdata[linvarpos]->cons == cons);
443  assert(consdata->lineventdata[linvarpos]->varidx == linvarpos);
444  assert(consdata->lineventdata[linvarpos]->filterpos >= 0);
445 
447  if( !SCIPisInfinity(scip, consdata->rhs) )
448  {
449  /* if right hand side is finite, then a tightening in the lower bound of coef*linvar is of interest
450  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
451  if( consdata->lincoefs[linvarpos] > 0.0 )
452  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
453  else
454  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
455  }
456  if( !SCIPisInfinity(scip, -consdata->lhs) )
457  {
458  /* if left hand side is finite, then a tightening in the upper bound of coef*linvar is of interest
459  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
460  if( consdata->lincoefs[linvarpos] > 0.0 )
461  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
462  else
463  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
464  }
465 
466  SCIP_CALL( SCIPdropVarEvent(scip, consdata->linvars[linvarpos], eventtype, eventhdlr, (SCIP_EVENTDATA*)consdata->lineventdata[linvarpos], consdata->lineventdata[linvarpos]->filterpos) );
467 
468  SCIPfreeBlockMemory(scip, &consdata->lineventdata[linvarpos]); /*lint !e866 */
469 
470  return SCIP_OKAY;
471 }
472 
473 /** catches variable bound change events on a quadratic variable in a quadratic constraint */
474 static
476  SCIP* scip, /**< SCIP data structure */
477  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
478  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
479  int quadvarpos /**< position of variable in quadratic variables array */
480  )
481 {
482  SCIP_CONSDATA* consdata;
483  SCIP_QUADVAREVENTDATA* eventdata;
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 
497  SCIP_CALL( SCIPallocBlockMemory(scip, &eventdata) );
498 
500 #ifdef CHECKIMPLINBILINEAR
501  eventtype |= SCIP_EVENTTYPE_IMPLADDED;
502 #endif
503  eventdata->cons = cons;
504  eventdata->varidx = -quadvarpos-1;
505  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->quadvarterms[quadvarpos].var, eventtype, eventhdlr, (SCIP_EVENTDATA*)eventdata, &eventdata->filterpos) );
506 
507  consdata->quadvarterms[quadvarpos].eventdata = eventdata;
508 
509  /* invalidate activity information
510  * NOTE: It could happen that a constraint gets temporary deactivated and some variable bounds change. In this case
511  * we do not recognize those bound changes with the variable events and thus we have to recompute the activities.
512  */
513  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
514 
515  return SCIP_OKAY;
516 }
517 
518 /** catches variable bound change events on a quadratic variable in a quadratic constraint */
519 static
521  SCIP* scip, /**< SCIP data structure */
522  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
523  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
524  int quadvarpos /**< position of variable in quadratic variables array */
525  )
526 {
527  SCIP_CONSDATA* consdata;
528  SCIP_EVENTTYPE eventtype;
529 
530  assert(scip != NULL);
531  assert(eventhdlr != NULL);
532  assert(cons != NULL);
533 
534  consdata = SCIPconsGetData(cons);
535  assert(consdata != NULL);
536 
537  assert(quadvarpos >= 0);
538  assert(quadvarpos < consdata->nquadvars);
539  assert(consdata->quadvarterms[quadvarpos].eventdata != NULL);
540  assert(consdata->quadvarterms[quadvarpos].eventdata->cons == cons);
541  assert(consdata->quadvarterms[quadvarpos].eventdata->varidx == -quadvarpos-1);
542  assert(consdata->quadvarterms[quadvarpos].eventdata->filterpos >= 0);
543 
545 #ifdef CHECKIMPLINBILINEAR
546  eventtype |= SCIP_EVENTTYPE_IMPLADDED;
547 #endif
548 
549  SCIP_CALL( SCIPdropVarEvent(scip, consdata->quadvarterms[quadvarpos].var, eventtype, eventhdlr, (SCIP_EVENTDATA*)consdata->quadvarterms[quadvarpos].eventdata, consdata->quadvarterms[quadvarpos].eventdata->filterpos) );
550 
551  SCIPfreeBlockMemory(scip, &consdata->quadvarterms[quadvarpos].eventdata);
552 
553  return SCIP_OKAY;
554 }
555 
556 /** catch variable events */
557 static
559  SCIP* scip, /**< SCIP data structure */
560  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
561  SCIP_CONS* cons /**< constraint for which to catch bound change events */
562  )
563 {
564  SCIP_CONSDATA* consdata;
565  SCIP_VAR* var;
566  int i;
567 
568  assert(scip != NULL);
569  assert(cons != NULL);
570  assert(eventhdlr != NULL);
571 
572  consdata = SCIPconsGetData(cons);
573  assert(consdata != NULL);
574  assert(consdata->lineventdata == NULL);
575 
576  /* we will update isremovedfixings, so reset it to TRUE first */
577  consdata->isremovedfixings = TRUE;
578 
579  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize) );
580  for( i = 0; i < consdata->nlinvars; ++i )
581  {
582  SCIP_CALL( catchLinearVarEvents(scip, eventhdlr, cons, i) );
583 
584  var = consdata->linvars[i];
585  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var)
586  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
587  }
588 
589  for( i = 0; i < consdata->nquadvars; ++i )
590  {
591  assert(consdata->quadvarterms[i].eventdata == NULL);
592 
593  SCIP_CALL( catchQuadVarEvents(scip, eventhdlr, cons, i) );
594 
595  var = consdata->quadvarterms[i].var;
596  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var)
597  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
598  }
599 
600  consdata->ispropagated = FALSE;
601 
602  return SCIP_OKAY;
603 }
604 
605 /** drop variable events */
606 static
608  SCIP* scip, /**< SCIP data structure */
609  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
610  SCIP_CONS* cons /**< constraint for which to drop bound change events */
611  )
612 {
613  SCIP_CONSDATA* consdata;
614  int i;
615 
616  assert(scip != NULL);
617  assert(eventhdlr != NULL);
618  assert(cons != NULL);
619 
620  consdata = SCIPconsGetData(cons);
621  assert(consdata != NULL);
622 
623  if( consdata->lineventdata != NULL )
624  {
625  for( i = 0; i < consdata->nlinvars; ++i )
626  {
627  if( consdata->lineventdata[i] != NULL )
628  {
629  SCIP_CALL( dropLinearVarEvents(scip, eventhdlr, cons, i) );
630  }
631  }
632  SCIPfreeBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize);
633  }
634 
635  for( i = 0; i < consdata->nquadvars; ++i )
636  {
637  if( consdata->quadvarterms[i].eventdata != NULL )
638  {
639  SCIP_CALL( dropQuadVarEvents(scip, eventhdlr, cons, i) );
640  }
641  }
642 
643  return SCIP_OKAY;
644 }
645 
646 /** locks a linear variable in a constraint */
647 static
649  SCIP* scip, /**< SCIP data structure */
650  SCIP_CONS* cons, /**< constraint where to lock a variable */
651  SCIP_VAR* var, /**< variable to lock */
652  SCIP_Real coef /**< coefficient of variable in constraint */
653  )
654 {
655  SCIP_CONSDATA* consdata;
656 
657  assert(scip != NULL);
658  assert(cons != NULL);
659  assert(var != NULL);
660  assert(coef != 0.0);
661 
662  consdata = SCIPconsGetData(cons);
663  assert(consdata != NULL);
664 
665  if( coef > 0.0 )
666  {
667  SCIP_CALL( SCIPlockVarCons(scip, var, cons, !SCIPisInfinity(scip, -consdata->lhs), !SCIPisInfinity(scip, consdata->rhs)) );
668  }
669  else
670  {
671  SCIP_CALL( SCIPlockVarCons(scip, var, cons, !SCIPisInfinity(scip, consdata->rhs), !SCIPisInfinity(scip, -consdata->lhs)) );
672  }
673 
674  return SCIP_OKAY;
675 }
676 
677 /** unlocks a linear 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  SCIP_Real coef /**< coefficient of variable in constraint */
684  )
685 {
686  SCIP_CONSDATA* consdata;
687 
688  assert(scip != NULL);
689  assert(cons != NULL);
690  assert(var != NULL);
691  assert(coef != 0.0);
692 
693  consdata = SCIPconsGetData(cons);
694  assert(consdata != NULL);
695 
696  if( coef > 0.0 )
697  {
698  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, !SCIPisInfinity(scip, -consdata->lhs), !SCIPisInfinity(scip, consdata->rhs)) );
699  }
700  else
701  {
702  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, !SCIPisInfinity(scip, consdata->rhs), !SCIPisInfinity(scip, -consdata->lhs)) );
703  }
704 
705  return SCIP_OKAY;
706 }
707 
708 /** locks a quadratic variable in a constraint */
709 static
711  SCIP* scip, /**< SCIP data structure */
712  SCIP_CONS* cons, /**< constraint where to lock a variable */
713  SCIP_VAR* var /**< variable to lock */
714  )
715 {
716  SCIP_CALL( SCIPlockVarCons(scip, var, cons, TRUE, TRUE) );
717 
718  return SCIP_OKAY;
719 }
720 
721 /** unlocks a quadratic variable in a constraint */
722 static
724  SCIP* scip, /**< SCIP data structure */
725  SCIP_CONS* cons, /**< constraint where to unlock a variable */
726  SCIP_VAR* var /**< variable to unlock */
727  )
728 {
729  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, TRUE) );
730 
731  return SCIP_OKAY;
732 }
733 
734 /** computes the minimal and maximal activity for the linear part in a constraint data
735  *
736  * Only sums up terms that contribute finite values.
737  * Gives the number of terms that contribute infinite values.
738  * Only computes those activities where the corresponding side of the constraint is finite.
739  */
740 static
742  SCIP* scip, /**< SCIP data structure */
743  SCIP_CONSDATA* consdata, /**< constraint data */
744  SCIP_Real intervalinfty /**< infinity value used in interval operations */
745  )
746 { /*lint --e{666}*/
747  SCIP_ROUNDMODE prevroundmode;
748  int i;
749  SCIP_Real bnd;
750 
751  assert(scip != NULL);
752  assert(consdata != NULL);
753 
754  /* if variable bounds are not strictly consistent, then the activity update methods may yield inconsistent activities
755  * in this case, we also recompute the activities
756  */
757  if( consdata->minlinactivity != SCIP_INVALID && consdata->maxlinactivity != SCIP_INVALID && /*lint !e777 */
758  (consdata->minlinactivityinf > 0 || consdata->maxlinactivityinf > 0 || consdata->minlinactivity <= consdata->maxlinactivity) )
759  {
760  /* activities should be up-to-date */
761  assert(consdata->minlinactivityinf >= 0);
762  assert(consdata->maxlinactivityinf >= 0);
763  return;
764  }
765 
766  consdata->minlinactivityinf = 0;
767  consdata->maxlinactivityinf = 0;
768 
769  /* if lhs is -infinite, then we do not compute a maximal activity, so we set it to infinity
770  * if rhs is infinite, then we do not compute a minimal activity, so we set it to -infinity
771  */
772  consdata->minlinactivity = SCIPisInfinity(scip, consdata->rhs) ? -intervalinfty : 0.0;
773  consdata->maxlinactivity = SCIPisInfinity(scip, -consdata->lhs) ? intervalinfty : 0.0;
774 
775  if( consdata->nlinvars == 0 )
776  return;
777 
778  /* if the activities computed here should be still up-to-date after bound changes,
779  * variable events need to be caught */
780  assert(consdata->lineventdata != NULL);
781 
782  prevroundmode = SCIPintervalGetRoundingMode();
783 
784  if( !SCIPisInfinity(scip, consdata->rhs) )
785  {
786  /* compute minimal activity only if there is a finite right hand side */
788 
789  for( i = 0; i < consdata->nlinvars; ++i )
790  {
791  assert(consdata->lineventdata[i] != NULL);
792  if( consdata->lincoefs[i] >= 0.0 )
793  {
794  bnd = MIN(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
795  if( SCIPisInfinity(scip, -bnd) )
796  {
797  ++consdata->minlinactivityinf;
798  continue;
799  }
800  assert(!SCIPisInfinity(scip, bnd)); /* do not like variables that are fixed at +infinity */
801  }
802  else
803  {
804  bnd = MAX(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
805  if( SCIPisInfinity(scip, bnd) )
806  {
807  ++consdata->minlinactivityinf;
808  continue;
809  }
810  assert(!SCIPisInfinity(scip, -bnd)); /* do not like variables that are fixed at -infinity */
811  }
812  consdata->minlinactivity += consdata->lincoefs[i] * bnd;
813  }
814  }
815 
816  if( !SCIPisInfinity(scip, -consdata->lhs) )
817  {
818  /* compute maximal activity only if there is a finite left hand side */
820 
821  for( i = 0; i < consdata->nlinvars; ++i )
822  {
823  assert(consdata->lineventdata[i] != NULL);
824  if( consdata->lincoefs[i] >= 0.0 )
825  {
826  bnd = MAX(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
827  if( SCIPisInfinity(scip, bnd) )
828  {
829  ++consdata->maxlinactivityinf;
830  continue;
831  }
832  assert(!SCIPisInfinity(scip, -bnd)); /* do not like variables that are fixed at -infinity */
833  }
834  else
835  {
836  bnd = MIN(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
837  if( SCIPisInfinity(scip, -bnd) )
838  {
839  ++consdata->maxlinactivityinf;
840  continue;
841  }
842  assert(!SCIPisInfinity(scip, bnd)); /* do not like variables that are fixed at +infinity */
843  }
844  consdata->maxlinactivity += consdata->lincoefs[i] * bnd;
845  }
846  }
847 
848  SCIPintervalSetRoundingMode(prevroundmode);
849 
850  assert(consdata->minlinactivityinf > 0 || consdata->maxlinactivityinf > 0 || consdata->minlinactivity <= consdata->maxlinactivity);
851 }
852 
853 /** update the linear activities after a change in the lower bound of a variable */
854 static
856  SCIP* scip, /**< SCIP data structure */
857  SCIP_CONSDATA* consdata, /**< constraint data */
858  SCIP_Real coef, /**< coefficient of variable in constraint */
859  SCIP_Real oldbnd, /**< previous lower bound of variable */
860  SCIP_Real newbnd /**< new lower bound of variable */
861  )
862 {
863  SCIP_ROUNDMODE prevroundmode;
864 
865  assert(scip != NULL);
866  assert(consdata != NULL);
867  /* we can't deal with lower bounds at infinity */
868  assert(!SCIPisInfinity(scip, oldbnd));
869  assert(!SCIPisInfinity(scip, newbnd));
870 
871  /* @todo since we check the linear activity for consistency later anyway, we may skip changing the rounding mode here */
872 
873  /* assume lhs <= a*x + y <= rhs, then the following bound changes can be deduced:
874  * a > 0: y <= rhs - a*lb(x), y >= lhs - a*ub(x)
875  * a < 0: y <= rhs - a*ub(x), y >= lhs - a*lb(x)
876  */
877 
878  if( coef > 0.0 )
879  {
880  /* we should only be called if rhs is finite */
881  assert(!SCIPisInfinity(scip, consdata->rhs));
882 
883  /* we have no min activities computed so far, so cannot update */
884  if( consdata->minlinactivity == SCIP_INVALID ) /*lint !e777 */
885  return;
886 
887  prevroundmode = SCIPintervalGetRoundingMode();
889 
890  /* update min activity */
891  if( SCIPisInfinity(scip, -oldbnd) )
892  {
893  --consdata->minlinactivityinf;
894  assert(consdata->minlinactivityinf >= 0);
895  }
896  else
897  {
898  SCIP_Real minuscoef;
899  minuscoef = -coef;
900  consdata->minlinactivity += minuscoef * oldbnd;
901  }
902 
903  if( SCIPisInfinity(scip, -newbnd) )
904  {
905  ++consdata->minlinactivityinf;
906  }
907  else
908  {
909  consdata->minlinactivity += coef * newbnd;
910  }
911 
912  SCIPintervalSetRoundingMode(prevroundmode);
913  }
914  else
915  {
916  /* we should only be called if lhs is finite */
917  assert(!SCIPisInfinity(scip, -consdata->lhs));
918 
919  /* we have no max activities computed so far, so cannot update */
920  if( consdata->maxlinactivity == SCIP_INVALID ) /*lint !e777 */
921  return;
922 
923  prevroundmode = SCIPintervalGetRoundingMode();
925 
926  /* update max activity */
927  if( SCIPisInfinity(scip, -oldbnd) )
928  {
929  --consdata->maxlinactivityinf;
930  assert(consdata->maxlinactivityinf >= 0);
931  }
932  else
933  {
934  SCIP_Real minuscoef;
935  minuscoef = -coef;
936  consdata->maxlinactivity += minuscoef * oldbnd;
937  }
938 
939  if( SCIPisInfinity(scip, -newbnd) )
940  {
941  ++consdata->maxlinactivityinf;
942  }
943  else
944  {
945  consdata->maxlinactivity += coef * newbnd;
946  }
947 
948  SCIPintervalSetRoundingMode(prevroundmode);
949  }
950 }
951 
952 /** update the linear activities after a change in the upper bound of a variable */
953 static
955  SCIP* scip, /**< SCIP data structure */
956  SCIP_CONSDATA* consdata, /**< constraint data */
957  SCIP_Real coef, /**< coefficient of variable in constraint */
958  SCIP_Real oldbnd, /**< previous lower bound of variable */
959  SCIP_Real newbnd /**< new lower bound of variable */
960  )
961 {
962  SCIP_ROUNDMODE prevroundmode;
963 
964  assert(scip != NULL);
965  assert(consdata != NULL);
966  /* we can't deal with upper bounds at -infinity */
967  assert(!SCIPisInfinity(scip, -oldbnd));
968  assert(!SCIPisInfinity(scip, -newbnd));
969 
970  /* @todo since we check the linear activity for consistency later anyway, we may skip changing the rounding mode here */
971 
972  /* assume lhs <= a*x + y <= rhs, then the following bound changes can be deduced:
973  * a > 0: y <= rhs - a*lb(x), y >= lhs - a*ub(x)
974  * a < 0: y <= rhs - a*ub(x), y >= lhs - a*lb(x)
975  */
976 
977  if( coef > 0.0 )
978  {
979  /* we should only be called if lhs is finite */
980  assert(!SCIPisInfinity(scip, -consdata->lhs));
981 
982  /* we have no max activities computed so far, so cannot update */
983  if( consdata->maxlinactivity == SCIP_INVALID ) /*lint !e777 */
984  return;
985 
986  prevroundmode = SCIPintervalGetRoundingMode();
988 
989  /* update max activity */
990  if( SCIPisInfinity(scip, oldbnd) )
991  {
992  --consdata->maxlinactivityinf;
993  assert(consdata->maxlinactivityinf >= 0);
994  }
995  else
996  {
997  SCIP_Real minuscoef;
998  minuscoef = -coef;
999  consdata->maxlinactivity += minuscoef * oldbnd;
1000  }
1001 
1002  if( SCIPisInfinity(scip, newbnd) )
1003  {
1004  ++consdata->maxlinactivityinf;
1005  }
1006  else
1007  {
1008  consdata->maxlinactivity += coef * newbnd;
1009  }
1010 
1011  SCIPintervalSetRoundingMode(prevroundmode);
1012  }
1013  else
1014  {
1015  /* we should only be called if rhs is finite */
1016  assert(!SCIPisInfinity(scip, consdata->rhs));
1017 
1018  /* we have no min activities computed so far, so cannot update */
1019  if( consdata->minlinactivity == SCIP_INVALID ) /*lint !e777 */
1020  return;
1021 
1022  prevroundmode = SCIPintervalGetRoundingMode();
1024 
1025  /* update min activity */
1026  if( SCIPisInfinity(scip, oldbnd) )
1027  {
1028  --consdata->minlinactivityinf;
1029  assert(consdata->minlinactivityinf >= 0);
1030  }
1031  else
1032  {
1033  SCIP_Real minuscoef;
1034  minuscoef = -coef;
1035  consdata->minlinactivity += minuscoef * oldbnd;
1036  }
1037 
1038  if( SCIPisInfinity(scip, newbnd) )
1039  {
1040  ++consdata->minlinactivityinf;
1041  }
1042  else
1043  {
1044  consdata->minlinactivity += coef * newbnd;
1045  }
1046 
1047  SCIPintervalSetRoundingMode(prevroundmode);
1048  }
1049 }
1050 
1051 /** returns whether a quadratic variable domain can be reduced to its lower or upper bound; this is the case if the
1052  * quadratic variable is in just one single quadratic constraint and (sqrcoef > 0 and LHS = -infinity), or
1053  * (sqrcoef < 0 and RHS = +infinity) hold
1054  */
1055 static
1057  SCIP* scip, /**< SCIP data structure */
1058  SCIP_CONSDATA* consdata, /**< constraint data */
1059  int idx /**< index of quadratic variable */
1060  )
1061 {
1062  SCIP_VAR* var;
1063  SCIP_Real quadcoef;
1064  SCIP_Bool haslhs;
1065  SCIP_Bool hasrhs;
1066 
1067  assert(scip != NULL);
1068  assert(consdata != NULL);
1069  assert(idx >= 0 && idx < consdata->nquadvars);
1070 
1071  var = consdata->quadvarterms[idx].var;
1072  assert(var != NULL);
1073 
1074  quadcoef = consdata->quadvarterms[idx].sqrcoef;
1075  haslhs = !SCIPisInfinity(scip, -consdata->lhs);
1076  hasrhs = !SCIPisInfinity(scip, consdata->rhs);
1077 
1080  && SCIPvarGetType(var) != SCIP_VARTYPE_BINARY && ((quadcoef < 0.0 && !haslhs) || (quadcoef > 0.0 && !hasrhs));
1081 }
1082 
1083 /** processes variable fixing or bound change event */
1084 static
1085 SCIP_DECL_EVENTEXEC(processVarEvent)
1087  SCIP_CONS* cons;
1088  SCIP_CONSDATA* consdata;
1089  SCIP_EVENTTYPE eventtype;
1090  int varidx;
1091 
1092  assert(scip != NULL);
1093  assert(event != NULL);
1094  assert(eventdata != NULL);
1095  assert(eventhdlr != NULL);
1096 
1097  cons = ((SCIP_QUADVAREVENTDATA*)eventdata)->cons;
1098  assert(cons != NULL);
1099  consdata = SCIPconsGetData(cons);
1100  assert(consdata != NULL);
1101 
1102  varidx = ((SCIP_QUADVAREVENTDATA*)eventdata)->varidx;
1103  assert(varidx < 0 || varidx < consdata->nlinvars);
1104  assert(varidx >= 0 || -varidx-1 < consdata->nquadvars);
1105 
1106  eventtype = SCIPeventGetType(event);
1107 
1108  /* process local bound changes */
1109  if( eventtype & SCIP_EVENTTYPE_BOUNDCHANGED )
1110  {
1111  if( varidx < 0 )
1112  {
1113  /* mark activity bounds for quad term as not up to date anymore */
1114  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
1115  }
1116  else
1117  {
1118  /* update activity bounds for linear terms */
1119  if( eventtype & SCIP_EVENTTYPE_LBCHANGED )
1120  consdataUpdateLinearActivityLbChange(scip, consdata, consdata->lincoefs[varidx], SCIPeventGetOldbound(event), SCIPeventGetNewbound(event));
1121  else
1122  consdataUpdateLinearActivityUbChange(scip, consdata, consdata->lincoefs[varidx], SCIPeventGetOldbound(event), SCIPeventGetNewbound(event));
1123  }
1124 
1125  if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
1126  {
1127  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
1128  consdata->ispropagated = FALSE;
1129  }
1130  }
1131 
1132  /* process global bound changes */
1133  if( eventtype & SCIP_EVENTTYPE_GBDCHANGED )
1134  {
1135  SCIP_VAR* var;
1136 
1137  var = varidx < 0 ? consdata->quadvarterms[-varidx-1].var : consdata->linvars[varidx];
1138  assert(var != NULL);
1139 
1140  if( varidx < 0 )
1141  {
1142  SCIP_QUADVARTERM* quadvarterm;
1143 
1144  quadvarterm = &consdata->quadvarterms[-varidx-1];
1145 
1146  /* 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()
1147  * we currently do this only if the binary variable does not show up in any bilinear terms
1148  */
1150  quadvarterm->sqrcoef != 0.0 && quadvarterm->nadjbilin == 0 )
1151  {
1152  consdata->quadvarsmerged = FALSE;
1153  consdata->initialmerge = FALSE;
1154  }
1155  }
1156 
1157  if( SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
1158  consdata->isremovedfixings = FALSE;
1159  }
1160 
1161  /* process variable fixing event */
1162  if( eventtype & SCIP_EVENTTYPE_VARFIXED )
1163  {
1164  consdata->isremovedfixings = FALSE;
1165  }
1166 
1167 #ifdef CHECKIMPLINBILINEAR
1168  if( eventtype & SCIP_EVENTTYPE_IMPLADDED )
1169  {
1170  assert(varidx < 0); /* we catch impladded events only for quadratic variables */
1171  /* 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 */
1172  if( SCIPvarIsBinary(SCIPeventGetVar(event)) && consdata->quadvarterms[-varidx-1].nadjbilin > 0 )
1173  consdata->isimpladded = TRUE;
1174  }
1175 #endif
1176 
1177  return SCIP_OKAY;
1178 }
1179 
1180 /** ensures, that linear vars and coefs arrays can store at least num entries */
1181 static
1183  SCIP* scip, /**< SCIP data structure */
1184  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1185  int num /**< minimum number of entries to store */
1186  )
1187 {
1188  assert(scip != NULL);
1189  assert(consdata != NULL);
1190  assert(consdata->nlinvars <= consdata->linvarssize);
1191 
1192  if( num > consdata->linvarssize )
1193  {
1194  int newsize;
1195 
1196  newsize = SCIPcalcMemGrowSize(scip, num);
1197  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->linvars, consdata->linvarssize, newsize) );
1198  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->lincoefs, consdata->linvarssize, newsize) );
1199  if( consdata->lineventdata != NULL )
1200  {
1201  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize, newsize) );
1202  }
1203  consdata->linvarssize = newsize;
1204  }
1205  assert(num <= consdata->linvarssize);
1206 
1207  return SCIP_OKAY;
1208 }
1209 
1210 /** ensures, that quadratic variable terms array can store at least num entries */
1211 static
1213  SCIP* scip, /**< SCIP data structure */
1214  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1215  int num /**< minimum number of entries to store */
1216  )
1217 {
1218  assert(scip != NULL);
1219  assert(consdata != NULL);
1220  assert(consdata->nquadvars <= consdata->quadvarssize);
1221 
1222  if( num > consdata->quadvarssize )
1223  {
1224  int newsize;
1225 
1226  newsize = SCIPcalcMemGrowSize(scip, num);
1227  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->quadvarterms, consdata->quadvarssize, newsize) );
1228  consdata->quadvarssize = newsize;
1229  }
1230  assert(num <= consdata->quadvarssize);
1231 
1232  return SCIP_OKAY;
1233 }
1234 
1235 /** ensures, that adjacency array can store at least num entries */
1236 static
1238  SCIP* scip, /**< SCIP data structure */
1239  SCIP_QUADVARTERM* quadvarterm, /**< quadratic variable term */
1240  int num /**< minimum number of entries to store */
1241  )
1242 {
1243  assert(scip != NULL);
1244  assert(quadvarterm != NULL);
1245  assert(quadvarterm->nadjbilin <= quadvarterm->adjbilinsize);
1246 
1247  if( num > quadvarterm->adjbilinsize )
1248  {
1249  int newsize;
1250 
1251  newsize = SCIPcalcMemGrowSize(scip, num);
1252  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &quadvarterm->adjbilin, quadvarterm->adjbilinsize, newsize) );
1253  quadvarterm->adjbilinsize = newsize;
1254  }
1255  assert(num <= quadvarterm->adjbilinsize);
1256 
1257  return SCIP_OKAY;
1258 }
1259 
1260 /** ensures, that bilinear term arrays can store at least num entries */
1261 static
1263  SCIP* scip, /**< SCIP data structure */
1264  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1265  int num /**< minimum number of entries to store */
1266  )
1267 {
1268  assert(scip != NULL);
1269  assert(consdata != NULL);
1270  assert(consdata->nbilinterms <= consdata->bilintermssize);
1271 
1272  if( num > consdata->bilintermssize )
1273  {
1274  int newsize;
1275 
1276  newsize = SCIPcalcMemGrowSize(scip, num);
1277  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->bilinterms, consdata->bilintermssize, newsize) );
1278  consdata->bilintermssize = newsize;
1279  }
1280  assert(num <= consdata->bilintermssize);
1281 
1282  return SCIP_OKAY;
1283 }
1284 
1285 /** creates empty constraint data structure */
1286 static
1288  SCIP* scip, /**< SCIP data structure */
1289  SCIP_CONSDATA** consdata /**< a buffer to store pointer to new constraint data */
1290  )
1291 {
1292  assert(scip != NULL);
1293  assert(consdata != NULL);
1294 
1295  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1296  BMSclearMemory(*consdata);
1297 
1298  (*consdata)->lhs = -SCIPinfinity(scip);
1299  (*consdata)->rhs = SCIPinfinity(scip);
1300 
1301  (*consdata)->linvarssorted = TRUE;
1302  (*consdata)->linvarsmerged = TRUE;
1303  (*consdata)->quadvarssorted = TRUE;
1304  (*consdata)->quadvarsmerged = TRUE;
1305  (*consdata)->bilinsorted = TRUE;
1306  (*consdata)->bilinmerged = TRUE;
1307 
1308  (*consdata)->isremovedfixings = TRUE;
1309  (*consdata)->ispropagated = TRUE;
1310  (*consdata)->initialmerge = FALSE;
1311 
1312  (*consdata)->linvar_maydecrease = -1;
1313  (*consdata)->linvar_mayincrease = -1;
1314 
1315  (*consdata)->minlinactivity = SCIP_INVALID;
1316  (*consdata)->maxlinactivity = SCIP_INVALID;
1317  (*consdata)->minlinactivityinf = -1;
1318  (*consdata)->maxlinactivityinf = -1;
1319 
1320  (*consdata)->isgaugeavailable = FALSE;
1321  (*consdata)->isedavailable = FALSE;
1322 
1323  return SCIP_OKAY;
1324 }
1325 
1326 /** creates constraint data structure */
1327 static
1329  SCIP* scip, /**< SCIP data structure */
1330  SCIP_CONSDATA** consdata, /**< a buffer to store pointer to new constraint data */
1331  SCIP_Real lhs, /**< left hand side of constraint */
1332  SCIP_Real rhs, /**< right hand side of constraint */
1333  int nlinvars, /**< number of linear variables */
1334  SCIP_VAR** linvars, /**< array of linear variables */
1335  SCIP_Real* lincoefs, /**< array of coefficients of linear variables */
1336  int nquadvars, /**< number of quadratic variables */
1337  SCIP_QUADVARTERM* quadvarterms, /**< array of quadratic variable terms */
1338  int nbilinterms, /**< number of bilinear terms */
1339  SCIP_BILINTERM* bilinterms, /**< array of bilinear terms */
1340  SCIP_Bool capturevars /**< whether we should capture variables */
1341  )
1342 {
1343  int i;
1344 
1345  assert(scip != NULL);
1346  assert(consdata != NULL);
1347 
1348  assert(nlinvars == 0 || linvars != NULL);
1349  assert(nlinvars == 0 || lincoefs != NULL);
1350  assert(nquadvars == 0 || quadvarterms != NULL);
1351  assert(nbilinterms == 0 || bilinterms != NULL);
1352 
1353  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1354  BMSclearMemory(*consdata);
1355 
1356  (*consdata)->minlinactivity = SCIP_INVALID;
1357  (*consdata)->maxlinactivity = SCIP_INVALID;
1358  (*consdata)->minlinactivityinf = -1;
1359  (*consdata)->maxlinactivityinf = -1;
1360 
1361  (*consdata)->lhs = lhs;
1362  (*consdata)->rhs = rhs;
1363 
1364  if( nlinvars > 0 )
1365  {
1366  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->linvars, linvars, nlinvars) );
1367  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->lincoefs, lincoefs, nlinvars) );
1368  (*consdata)->nlinvars = nlinvars;
1369  (*consdata)->linvarssize = nlinvars;
1370 
1371  if( capturevars )
1372  for( i = 0; i < nlinvars; ++i )
1373  {
1374  SCIP_CALL( SCIPcaptureVar(scip, linvars[i]) );
1375  }
1376  }
1377  else
1378  {
1379  (*consdata)->linvarssorted = TRUE;
1380  (*consdata)->linvarsmerged = TRUE;
1381  (*consdata)->minlinactivity = 0.0;
1382  (*consdata)->maxlinactivity = 0.0;
1383  (*consdata)->minlinactivityinf = 0;
1384  (*consdata)->maxlinactivityinf = 0;
1385  }
1386 
1387  if( nquadvars > 0 )
1388  {
1389  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->quadvarterms, quadvarterms, nquadvars) );
1390 
1391  for( i = 0; i < nquadvars; ++i )
1392  {
1393  (*consdata)->quadvarterms[i].eventdata = NULL;
1394  if( quadvarterms[i].nadjbilin )
1395  {
1396  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->quadvarterms[i].adjbilin, quadvarterms[i].adjbilin, quadvarterms[i].nadjbilin) );
1397  (*consdata)->quadvarterms[i].adjbilinsize = quadvarterms[i].nadjbilin;
1398  }
1399  else
1400  {
1401  assert((*consdata)->quadvarterms[i].nadjbilin == 0);
1402  (*consdata)->quadvarterms[i].adjbilin = NULL;
1403  (*consdata)->quadvarterms[i].adjbilinsize = 0;
1404  }
1405  if( capturevars )
1406  {
1407  SCIP_CALL( SCIPcaptureVar(scip, quadvarterms[i].var) );
1408  }
1409  }
1410 
1411  (*consdata)->nquadvars = nquadvars;
1412  (*consdata)->quadvarssize = nquadvars;
1413  SCIPintervalSetEmpty(&(*consdata)->quadactivitybounds);
1414  }
1415  else
1416  {
1417  (*consdata)->quadvarssorted = TRUE;
1418  (*consdata)->quadvarsmerged = TRUE;
1419  SCIPintervalSet(&(*consdata)->quadactivitybounds, 0.0);
1420  }
1421 
1422  if( nbilinterms > 0 )
1423  {
1424  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->bilinterms, bilinterms, nbilinterms) );
1425  (*consdata)->nbilinterms = nbilinterms;
1426  (*consdata)->bilintermssize = nbilinterms;
1427  }
1428  else
1429  {
1430  (*consdata)->bilinsorted = TRUE;
1431  (*consdata)->bilinmerged = TRUE;
1432  }
1433 
1434  (*consdata)->linvar_maydecrease = -1;
1435  (*consdata)->linvar_mayincrease = -1;
1436 
1437  (*consdata)->activity = SCIP_INVALID;
1438  (*consdata)->lhsviol = SCIPisInfinity(scip, -lhs) ? 0.0 : SCIP_INVALID;
1439  (*consdata)->rhsviol = SCIPisInfinity(scip, rhs) ? 0.0 : SCIP_INVALID;
1440 
1441  (*consdata)->isgaugeavailable = FALSE;
1442 
1443  return SCIP_OKAY;
1444 }
1445 
1446 /** frees constraint data structure */
1447 static
1449  SCIP* scip, /**< SCIP data structure */
1450  SCIP_CONSDATA** consdata /**< pointer to constraint data to free */
1451  )
1452 {
1453  int i;
1454 
1455  assert(scip != NULL);
1456  assert(consdata != NULL);
1457  assert(*consdata != NULL);
1458 
1459  /* free sepa arrays, may exists if constraint is deleted in solving stage */
1460  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->sepaquadvars, (*consdata)->nquadvars);
1461  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->sepabilinvar2pos, (*consdata)->nbilinterms);
1462 
1463  /* release linear variables and free linear part */
1464  if( (*consdata)->linvarssize > 0 )
1465  {
1466  for( i = 0; i < (*consdata)->nlinvars; ++i )
1467  {
1468  assert((*consdata)->lineventdata == NULL || (*consdata)->lineventdata[i] == NULL); /* variable events should have been dropped earlier */
1469  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->linvars[i]) );
1470  }
1471  SCIPfreeBlockMemoryArray(scip, &(*consdata)->linvars, (*consdata)->linvarssize);
1472  SCIPfreeBlockMemoryArray(scip, &(*consdata)->lincoefs, (*consdata)->linvarssize);
1473  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->lineventdata, (*consdata)->linvarssize);
1474  }
1475  assert((*consdata)->linvars == NULL);
1476  assert((*consdata)->lincoefs == NULL);
1477  assert((*consdata)->lineventdata == NULL);
1478 
1479  /* release quadratic variables and free quadratic variable term part */
1480  for( i = 0; i < (*consdata)->nquadvars; ++i )
1481  {
1482  assert((*consdata)->quadvarterms[i].eventdata == NULL); /* variable events should have been dropped earlier */
1483  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->quadvarterms[i].adjbilin, (*consdata)->quadvarterms[i].adjbilinsize);
1484  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->quadvarterms[i].var) );
1485  }
1486  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->quadvarterms, (*consdata)->quadvarssize);
1487 
1488  /* free bilinear terms */
1489  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bilinterms, (*consdata)->bilintermssize);
1490 
1491  /* free nonlinear row representation */
1492  if( (*consdata)->nlrow != NULL )
1493  {
1494  SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
1495  }
1496 
1497  /* free interior point information, may exists if constraint is deleted in solving stage */
1498  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->interiorpoint, (*consdata)->nquadvars);
1499  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->gaugecoefs, (*consdata)->nquadvars);
1500 
1501  /* free eigen decomposition information */
1502  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->eigenvalues, (*consdata)->nquadvars);
1503  if( (*consdata)->eigenvectors != NULL ) /* explicit check on NULL to avoid runtime warning if nquadvars^2 > int_max */
1504  SCIPfreeBlockMemoryArray(scip, &(*consdata)->eigenvectors, (int)((*consdata)->nquadvars*(*consdata)->nquadvars));
1505  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bp, (*consdata)->nquadvars);
1506 
1507  /* free unique indices of bilinear terms array */
1508  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bilintermsidx, (*consdata)->nbilinterms);
1509 
1510  SCIPfreeBlockMemory(scip, consdata);
1511  *consdata = NULL;
1512 
1513  return SCIP_OKAY;
1514 }
1515 
1516 /** sorts linear part of constraint data */
1517 static
1519  SCIP_CONSDATA* consdata /**< quadratic constraint data */
1520  )
1521 {
1522  assert(consdata != NULL);
1523 
1524  if( consdata->linvarssorted )
1525  return;
1526 
1527  if( consdata->nlinvars <= 1 )
1528  {
1529  consdata->linvarssorted = TRUE;
1530  return;
1531  }
1532 
1533  if( consdata->lineventdata == NULL )
1534  {
1535  SCIPsortPtrReal((void**)consdata->linvars, consdata->lincoefs, SCIPvarComp, consdata->nlinvars);
1536  }
1537  else
1538  {
1539  int i;
1540 
1541  SCIPsortPtrPtrReal((void**)consdata->linvars, (void**)consdata->lineventdata, consdata->lincoefs, SCIPvarComp, consdata->nlinvars);
1542 
1543  /* update variable indices in event data */
1544  for( i = 0; i < consdata->nlinvars; ++i )
1545  if( consdata->lineventdata[i] != NULL )
1546  consdata->lineventdata[i]->varidx = i;
1547  }
1548 
1549  consdata->linvarssorted = TRUE;
1550 }
1551 
1552 #ifdef SCIP_DISABLED_CODE /* no-one needs this routine currently */
1553 /** returns the position of variable in the linear coefficients array of a constraint, or -1 if not found */
1554 static
1555 int consdataFindLinearVar(
1556  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1557  SCIP_VAR* var /**< variable to search for */
1558  )
1559 {
1560  int pos;
1561 
1562  assert(consdata != NULL);
1563  assert(var != NULL);
1564 
1565  if( consdata->nlinvars == 0 )
1566  return -1;
1567 
1568  consdataSortLinearVars(consdata);
1569 
1570  if( !SCIPsortedvecFindPtr((void**)consdata->linvars, SCIPvarComp, (void*)var, consdata->nlinvars, &pos) )
1571  pos = -1;
1572 
1573  return pos;
1574 }
1575 #endif
1576 
1577 /** index comparison method for quadratic variable terms: compares two indices of the quadratic variable set in the quadratic constraint */
1578 static
1579 SCIP_DECL_SORTINDCOMP(quadVarTermComp)
1580 { /*lint --e{715}*/
1581  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
1582 
1583  assert(consdata != NULL);
1584  assert(0 <= ind1 && ind1 < consdata->nquadvars);
1585  assert(0 <= ind2 && ind2 < consdata->nquadvars);
1586 
1587  return SCIPvarCompare(consdata->quadvarterms[ind1].var, consdata->quadvarterms[ind2].var);
1588 }
1589 
1590 /** sorting of quadratic variable terms */
1591 static
1593  SCIP* scip, /**< SCIP data structure */
1594  SCIP_CONSDATA* consdata /**< quadratic constraint data */
1595  )
1596 {
1597  int* perm;
1598  int i;
1599  int nexti;
1600  int v;
1601  SCIP_QUADVARTERM quadterm;
1602 
1603  assert(scip != NULL);
1604  assert(consdata != NULL);
1605 
1606  if( consdata->quadvarssorted )
1607  return SCIP_OKAY;
1608 
1609  if( consdata->nquadvars == 0 )
1610  {
1611  consdata->quadvarssorted = TRUE;
1612  return SCIP_OKAY;
1613  }
1614 
1615  /* get temporary memory to store the sorted permutation */
1616  SCIP_CALL( SCIPallocBufferArray(scip, &perm, consdata->nquadvars) );
1617 
1618  /* call bubble sort */
1619  SCIPsort(perm, quadVarTermComp, (void*)consdata, consdata->nquadvars);
1620 
1621  /* permute the quadratic variable terms according to the resulting permutation */
1622  for( v = 0; v < consdata->nquadvars; ++v )
1623  {
1624  if( perm[v] != v )
1625  {
1626  quadterm = consdata->quadvarterms[v];
1627 
1628  i = v;
1629  do
1630  {
1631  assert(0 <= perm[i] && perm[i] < consdata->nquadvars);
1632  assert(perm[i] != i);
1633  consdata->quadvarterms[i] = consdata->quadvarterms[perm[i]];
1634  if( consdata->quadvarterms[i].eventdata != NULL )
1635  {
1636  consdata->quadvarterms[i].eventdata->varidx = -i-1;
1637  }
1638  nexti = perm[i];
1639  perm[i] = i;
1640  i = nexti;
1641  }
1642  while( perm[i] != v );
1643  consdata->quadvarterms[i] = quadterm;
1644  if( consdata->quadvarterms[i].eventdata != NULL )
1645  {
1646  consdata->quadvarterms[i].eventdata->varidx = -i-1;
1647  }
1648  perm[i] = i;
1649  }
1650  }
1651  consdata->quadvarssorted = TRUE;
1652 
1653  /* free temporary memory */
1654  SCIPfreeBufferArray(scip, &perm);
1655 
1656  return SCIP_OKAY;
1657 }
1658 
1659 /** returns the position of variable in the quadratic variable terms array of a constraint, or -1 if not found */
1660 static
1662  SCIP* scip, /**< SCIP data structure */
1663  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1664  SCIP_VAR* var, /**< variable to search for */
1665  int* pos /**< buffer where to store position of var in quadvarterms array, or -1 if not found */
1666  )
1667 {
1668  int left;
1669  int right;
1670  int cmpres;
1671 
1672  assert(consdata != NULL);
1673  assert(var != NULL);
1674  assert(pos != NULL);
1675 
1676  if( consdata->nquadvars == 0 )
1677  {
1678  *pos = -1;
1679  return SCIP_OKAY;
1680  }
1681 
1682  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
1683 
1684  left = 0;
1685  right = consdata->nquadvars - 1;
1686  while( left <= right )
1687  {
1688  int middle;
1689 
1690  middle = (left+right)/2;
1691  assert(0 <= middle && middle < consdata->nquadvars);
1692 
1693  cmpres = SCIPvarCompare(var, consdata->quadvarterms[middle].var);
1694 
1695  if( cmpres < 0 )
1696  right = middle - 1;
1697  else if( cmpres > 0 )
1698  left = middle + 1;
1699  else
1700  {
1701  *pos = middle;
1702  return SCIP_OKAY;
1703  }
1704  }
1705  assert(left == right+1);
1706 
1707  *pos = -1;
1708 
1709  return SCIP_OKAY;
1710 }
1711 
1712 /** index comparison method for bilinear terms: compares two index pairs of the bilinear term set in the quadratic constraint */
1713 static
1714 SCIP_DECL_SORTINDCOMP(bilinTermComp)
1715 { /*lint --e{715}*/
1716  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
1717  int var1cmp;
1718 
1719  assert(consdata != NULL);
1720  assert(0 <= ind1 && ind1 < consdata->nbilinterms);
1721  assert(0 <= ind2 && ind2 < consdata->nbilinterms);
1722 
1723  var1cmp = SCIPvarCompare(consdata->bilinterms[ind1].var1, consdata->bilinterms[ind2].var1);
1724  if( var1cmp != 0 )
1725  return var1cmp;
1726 
1727  return SCIPvarCompare(consdata->bilinterms[ind1].var2, consdata->bilinterms[ind2].var2);
1728 }
1729 
1730 #ifndef NDEBUG
1731 /** checks if all bilinear terms are sorted correctly */
1732 static
1734  SCIP_CONSDATA* consdata
1735  )
1736 {
1737  int i;
1738 
1739  assert(consdata != NULL);
1740 
1741  /* nothing to check if the bilinear terms have not been sorted yet */
1742  if( !consdata->bilinsorted )
1743  return TRUE;
1744 
1745  for( i = 0; i < consdata->nbilinterms - 1; ++i )
1746  {
1747  if( bilinTermComp(consdata, i, i+1) > 0 )
1748  return FALSE;
1749  }
1750  return TRUE;
1751 }
1752 #endif
1753 
1754 /** sorting of bilinear terms */
1755 static
1757  SCIP* scip, /**< SCIP data structure */
1758  SCIP_CONSDATA* consdata /**< quadratic constraint data */
1759  )
1760 {
1761  int* perm;
1762  int* invperm;
1763  int i;
1764  int nexti;
1765  int v;
1766  SCIP_BILINTERM bilinterm;
1767 
1768  assert(scip != NULL);
1769  assert(consdata != NULL);
1770 
1771  if( consdata->bilinsorted )
1772  return SCIP_OKAY;
1773 
1774  if( consdata->nbilinterms == 0 )
1775  {
1776  consdata->bilinsorted = TRUE;
1777  return SCIP_OKAY;
1778  }
1779 
1780  /* get temporary memory to store the sorted permutation and the inverse permutation */
1781  SCIP_CALL( SCIPallocBufferArray(scip, &perm, consdata->nbilinterms) );
1782  SCIP_CALL( SCIPallocBufferArray(scip, &invperm, consdata->nbilinterms) );
1783 
1784  /* call bubble sort */
1785  SCIPsort(perm, bilinTermComp, (void*)consdata, consdata->nbilinterms);
1786 
1787  /* compute inverted permutation */
1788  for( v = 0; v < consdata->nbilinterms; ++v )
1789  {
1790  assert(0 <= perm[v] && perm[v] < consdata->nbilinterms);
1791  invperm[perm[v]] = v;
1792  }
1793 
1794  /* permute the bilinear terms according to the resulting permutation */
1795  for( v = 0; v < consdata->nbilinterms; ++v )
1796  {
1797  if( perm[v] != v )
1798  {
1799  bilinterm = consdata->bilinterms[v];
1800 
1801  i = v;
1802  do
1803  {
1804  assert(0 <= perm[i] && perm[i] < consdata->nbilinterms);
1805  assert(perm[i] != i);
1806  consdata->bilinterms[i] = consdata->bilinterms[perm[i]];
1807  nexti = perm[i];
1808  perm[i] = i;
1809  i = nexti;
1810  }
1811  while( perm[i] != v );
1812  consdata->bilinterms[i] = bilinterm;
1813  perm[i] = i;
1814  }
1815  }
1816 
1817  /* update the adjacency information in the quadratic variable terms */
1818  for( v = 0; v < consdata->nquadvars; ++v )
1819  for( i = 0; i < consdata->quadvarterms[v].nadjbilin; ++i )
1820  consdata->quadvarterms[v].adjbilin[i] = invperm[consdata->quadvarterms[v].adjbilin[i]];
1821 
1822  consdata->bilinsorted = TRUE;
1823  assert(consdataCheckBilinTermsSort(consdata));
1824 
1825  /* free temporary memory */
1826  SCIPfreeBufferArray(scip, &invperm);
1827  SCIPfreeBufferArray(scip, &perm);
1828 
1829  return SCIP_OKAY;
1830 }
1831 
1832 /** moves a linear variable from one position to another */
1833 static
1835  SCIP_CONSDATA* consdata, /**< constraint data */
1836  int oldpos, /**< position of variable that shall be moved */
1837  int newpos /**< new position of variable */
1838  )
1839 {
1840  assert(consdata != NULL);
1841  assert(oldpos >= 0);
1842  assert(oldpos < consdata->nlinvars);
1843  assert(newpos >= 0);
1844  assert(newpos < consdata->linvarssize);
1845 
1846  if( newpos == oldpos )
1847  return;
1848 
1849  consdata->linvars [newpos] = consdata->linvars [oldpos];
1850  consdata->lincoefs[newpos] = consdata->lincoefs[oldpos];
1851 
1852  if( consdata->lineventdata != NULL )
1853  {
1854  assert(newpos >= consdata->nlinvars || consdata->lineventdata[newpos] == NULL);
1855 
1856  consdata->lineventdata[newpos] = consdata->lineventdata[oldpos];
1857  consdata->lineventdata[newpos]->varidx = newpos;
1858 
1859  consdata->lineventdata[oldpos] = NULL;
1860  }
1861 
1862  consdata->linvarssorted = FALSE;
1863 }
1864 
1865 /** moves a quadratic variable from one position to another */
1866 static
1868  SCIP_CONSDATA* consdata, /**< constraint data */
1869  int oldpos, /**< position of variable that shall be moved */
1870  int newpos /**< new position of variable */
1871  )
1872 {
1873  assert(consdata != NULL);
1874  assert(oldpos >= 0);
1875  assert(oldpos < consdata->nquadvars);
1876  assert(newpos >= 0);
1877  assert(newpos < consdata->quadvarssize);
1878 
1879  if( newpos == oldpos )
1880  return;
1881 
1882  assert(newpos >= consdata->nquadvars || consdata->quadvarterms[newpos].eventdata == NULL);
1883 
1884  consdata->quadvarterms[newpos] = consdata->quadvarterms[oldpos];
1885 
1886  if( consdata->quadvarterms[newpos].eventdata != NULL )
1887  {
1888  consdata->quadvarterms[newpos].eventdata->varidx = -newpos-1;
1889  consdata->quadvarterms[oldpos].eventdata = NULL;
1890  }
1891 
1892  consdata->quadvarssorted = FALSE;
1893 }
1894 
1895 /** adds linear coefficient in quadratic constraint */
1896 static
1898  SCIP* scip, /**< SCIP data structure */
1899  SCIP_CONS* cons, /**< quadratic constraint */
1900  SCIP_VAR* var, /**< variable of constraint entry */
1901  SCIP_Real coef /**< coefficient of constraint entry */
1902  )
1903 {
1904  SCIP_CONSDATA* consdata;
1905  SCIP_Bool transformed;
1906 
1907  assert(scip != NULL);
1908  assert(cons != NULL);
1909  assert(var != NULL);
1910 
1911  /* ignore coefficient if it is nearly zero */
1912  if( SCIPisZero(scip, coef) )
1913  return SCIP_OKAY;
1914 
1915  consdata = SCIPconsGetData(cons);
1916  assert(consdata != NULL);
1917 
1918  /* are we in the transformed problem? */
1919  transformed = SCIPconsIsTransformed(cons);
1920 
1921  /* always use transformed variables in transformed constraints */
1922  if( transformed )
1923  {
1924  SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
1925  }
1926  assert(var != NULL);
1927  assert(transformed == SCIPvarIsTransformed(var));
1928 
1929  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars+1) );
1930  consdata->linvars [consdata->nlinvars] = var;
1931  consdata->lincoefs[consdata->nlinvars] = coef;
1932 
1933  ++consdata->nlinvars;
1934 
1935  /* catch variable events */
1936  if( SCIPconsIsEnabled(cons) )
1937  {
1938  SCIP_CONSHDLR* conshdlr;
1939  SCIP_CONSHDLRDATA* conshdlrdata;
1940 
1941  /* get event handler */
1942  conshdlr = SCIPconsGetHdlr(cons);
1943  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1944  assert(conshdlrdata != NULL);
1945  assert(conshdlrdata->eventhdlr != NULL);
1946 
1947  assert(consdata->lineventdata != NULL);
1948  consdata->lineventdata[consdata->nlinvars-1] = NULL;
1949 
1950  /* catch bound change events of variable */
1951  SCIP_CALL( catchLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, consdata->nlinvars-1) );
1952  }
1953 
1954  /* invalidate activity information */
1955  consdata->activity = SCIP_INVALID;
1956  consdata->minlinactivity = SCIP_INVALID;
1957  consdata->maxlinactivity = SCIP_INVALID;
1958  consdata->minlinactivityinf = -1;
1959  consdata->maxlinactivityinf = -1;
1960 
1961  /* invalidate nonlinear row */
1962  if( consdata->nlrow != NULL )
1963  {
1964  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1965  }
1966 
1967  /* install rounding locks for new variable */
1968  SCIP_CALL( lockLinearVariable(scip, cons, var, coef) );
1969 
1970  /* capture new variable */
1971  SCIP_CALL( SCIPcaptureVar(scip, var) );
1972 
1973  consdata->ispropagated = FALSE;
1974  consdata->ispresolved = FALSE;
1975  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var)
1976  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
1977  if( consdata->nlinvars == 1 )
1978  consdata->linvarssorted = TRUE;
1979  else
1980  consdata->linvarssorted = consdata->linvarssorted && (SCIPvarCompare(consdata->linvars[consdata->nlinvars-2], consdata->linvars[consdata->nlinvars-1]) == -1);
1981  /* always set too FALSE since the new linear variable should be checked if already existing as quad var term */
1982  consdata->linvarsmerged = FALSE;
1983 
1984  return SCIP_OKAY;
1985 }
1986 
1987 /** deletes linear coefficient at given position from quadratic constraint data */
1988 static
1990  SCIP* scip, /**< SCIP data structure */
1991  SCIP_CONS* cons, /**< quadratic constraint */
1992  int pos /**< position of coefficient to delete */
1993  )
1994 {
1995  SCIP_CONSDATA* consdata;
1996  SCIP_VAR* var;
1997  SCIP_Real coef;
1998 
1999  assert(scip != NULL);
2000  assert(cons != NULL);
2001 
2002  consdata = SCIPconsGetData(cons);
2003  assert(consdata != NULL);
2004  assert(0 <= pos && pos < consdata->nlinvars);
2005 
2006  var = consdata->linvars[pos];
2007  coef = consdata->lincoefs[pos];
2008  assert(var != NULL);
2009 
2010  /* remove rounding locks for deleted variable */
2011  SCIP_CALL( unlockLinearVariable(scip, cons, var, coef) );
2012 
2013  /* if we catch variable events, drop the events on the variable */
2014  if( consdata->lineventdata != NULL )
2015  {
2016  SCIP_CONSHDLR* conshdlr;
2017  SCIP_CONSHDLRDATA* conshdlrdata;
2018 
2019  /* get event handler */
2020  conshdlr = SCIPconsGetHdlr(cons);
2021  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2022  assert(conshdlrdata != NULL);
2023  assert(conshdlrdata->eventhdlr != NULL);
2024 
2025  /* drop bound change events of variable */
2026  SCIP_CALL( dropLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
2027  }
2028 
2029  /* release variable */
2030  SCIP_CALL( SCIPreleaseVar(scip, &consdata->linvars[pos]) );
2031 
2032  /* move the last variable to the free slot */
2033  consdataMoveLinearVar(consdata, consdata->nlinvars-1, pos);
2034 
2035  --consdata->nlinvars;
2036 
2037  /* invalidate activity */
2038  consdata->activity = SCIP_INVALID;
2039  consdata->minlinactivity = SCIP_INVALID;
2040  consdata->maxlinactivity = SCIP_INVALID;
2041  consdata->minlinactivityinf = -1;
2042  consdata->maxlinactivityinf = -1;
2043 
2044  /* invalidate nonlinear row */
2045  if( consdata->nlrow != NULL )
2046  {
2047  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2048  }
2049 
2050  consdata->ispropagated = FALSE;
2051  consdata->ispresolved = FALSE;
2052 
2053  return SCIP_OKAY;
2054 }
2055 
2056 /** changes linear coefficient value at given position of quadratic constraint */
2057 static
2059  SCIP* scip, /**< SCIP data structure */
2060  SCIP_CONS* cons, /**< quadratic constraint */
2061  int pos, /**< position of linear coefficient to change */
2062  SCIP_Real newcoef /**< new value of linear coefficient */
2063  )
2064 {
2065  SCIP_CONSHDLR* conshdlr;
2066  SCIP_CONSHDLRDATA* conshdlrdata;
2067  SCIP_CONSDATA* consdata;
2068  SCIP_VAR* var;
2069  SCIP_Real coef;
2070 
2071  assert(scip != NULL);
2072  assert(cons != NULL);
2074  assert(!SCIPisZero(scip, newcoef));
2075 
2076  conshdlrdata = NULL;
2077 
2078  consdata = SCIPconsGetData(cons);
2079  assert(consdata != NULL);
2080  assert(0 <= pos);
2081  assert(pos < consdata->nlinvars);
2082  assert(!SCIPisZero(scip, newcoef));
2083 
2084  var = consdata->linvars[pos];
2085  coef = consdata->lincoefs[pos];
2086  assert(var != NULL);
2087  assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
2088 
2089  /* invalidate activity */
2090  consdata->activity = SCIP_INVALID;
2091  consdata->minlinactivity = SCIP_INVALID;
2092  consdata->maxlinactivity = SCIP_INVALID;
2093  consdata->minlinactivityinf = -1;
2094  consdata->maxlinactivityinf = -1;
2095 
2096  /* invalidate nonlinear row */
2097  if( consdata->nlrow != NULL )
2098  {
2099  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2100  }
2101 
2102  /* if necessary, remove the rounding locks and event catching of the variable */
2103  if( newcoef * coef < 0.0 )
2104  {
2105  if( SCIPconsIsLocked(cons) )
2106  {
2107  assert(SCIPconsIsTransformed(cons));
2108 
2109  /* remove rounding locks for variable with old coefficient */
2110  SCIP_CALL( unlockLinearVariable(scip, cons, var, coef) );
2111  }
2112 
2113  if( consdata->lineventdata[pos] != NULL )
2114  {
2115  /* get event handler */
2116  conshdlr = SCIPconsGetHdlr(cons);
2117  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2118  assert(conshdlrdata != NULL);
2119  assert(conshdlrdata->eventhdlr != NULL);
2120 
2121  /* drop bound change events of variable */
2122  SCIP_CALL( dropLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
2123  }
2124  }
2125 
2126  /* change the coefficient */
2127  consdata->lincoefs[pos] = newcoef;
2128 
2129  /* if necessary, install the rounding locks and event catching of the variable again */
2130  if( newcoef * coef < 0.0 )
2131  {
2132  if( SCIPconsIsLocked(cons) )
2133  {
2134  /* install rounding locks for variable with new coefficient */
2135  SCIP_CALL( lockLinearVariable(scip, cons, var, newcoef) );
2136  }
2137 
2138  if( conshdlrdata != NULL )
2139  {
2140  assert(SCIPconsIsEnabled(cons));
2141 
2142  /* catch bound change events of variable */
2143  SCIP_CALL( catchLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
2144  }
2145  }
2146 
2147  consdata->ispropagated = FALSE;
2148  consdata->ispresolved = FALSE;
2149 
2150  return SCIP_OKAY;
2151 }
2152 
2153 /** adds quadratic variable term to quadratic constraint */
2154 static
2156  SCIP* scip, /**< SCIP data structure */
2157  SCIP_CONS* cons, /**< quadratic constraint */
2158  SCIP_VAR* var, /**< variable to add */
2159  SCIP_Real lincoef, /**< linear coefficient of variable */
2160  SCIP_Real sqrcoef /**< square coefficient of variable */
2161  )
2162 {
2163  SCIP_CONSDATA* consdata;
2164  SCIP_Bool transformed;
2165  SCIP_QUADVARTERM* quadvarterm;
2166 
2167  assert(scip != NULL);
2168  assert(cons != NULL);
2169  assert(var != NULL);
2170 
2171  consdata = SCIPconsGetData(cons);
2172  assert(consdata != NULL);
2173 
2174  /* are we in the transformed problem? */
2175  transformed = SCIPconsIsTransformed(cons);
2176 
2177  /* always use transformed variables in transformed constraints */
2178  if( transformed )
2179  {
2180  SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
2181  }
2182  assert(var != NULL);
2183  assert(transformed == SCIPvarIsTransformed(var));
2184 
2185  SCIP_CALL( consdataEnsureQuadVarTermsSize(scip, consdata, consdata->nquadvars+1) );
2186 
2187  quadvarterm = &consdata->quadvarterms[consdata->nquadvars];
2188  quadvarterm->var = var;
2189  quadvarterm->lincoef = lincoef;
2190  quadvarterm->sqrcoef = sqrcoef;
2191  quadvarterm->adjbilinsize = 0;
2192  quadvarterm->nadjbilin = 0;
2193  quadvarterm->adjbilin = NULL;
2194  quadvarterm->eventdata = NULL;
2195 
2196  ++consdata->nquadvars;
2197 
2198  /* capture variable */
2199  SCIP_CALL( SCIPcaptureVar(scip, var) );
2200 
2201  /* catch variable events, if we do so */
2202  if( SCIPconsIsEnabled(cons) )
2203  {
2204  SCIP_CONSHDLR* conshdlr;
2205  SCIP_CONSHDLRDATA* conshdlrdata;
2206 
2207  /* get event handler */
2208  conshdlr = SCIPconsGetHdlr(cons);
2209  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2210  assert(conshdlrdata != NULL);
2211  assert(conshdlrdata->eventhdlr != NULL);
2212 
2213  /* catch bound change events of variable */
2214  SCIP_CALL( catchQuadVarEvents(scip, conshdlrdata->eventhdlr, cons, consdata->nquadvars-1) );
2215  }
2216 
2217  /* invalidate activity information */
2218  consdata->activity = SCIP_INVALID;
2219  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2220 
2221  /* invalidate nonlinear row */
2222  if( consdata->nlrow != NULL )
2223  {
2224  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2225  }
2226 
2227  /* install rounding locks for new variable */
2228  SCIP_CALL( lockQuadraticVariable(scip, cons, var) );
2229 
2230  consdata->ispropagated = FALSE;
2231  consdata->ispresolved = FALSE;
2232  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var)
2233  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
2234  if( consdata->nquadvars == 1 )
2235  consdata->quadvarssorted = TRUE;
2236  else
2237  consdata->quadvarssorted = consdata->quadvarssorted &&
2238  (SCIPvarCompare(consdata->quadvarterms[consdata->nquadvars-2].var, consdata->quadvarterms[consdata->nquadvars-1].var) == -1);
2239  /* also set to FALSE if nquadvars == 1, since the new variable should be checked for linearity and other stuff in mergeAndClean ... */
2240  consdata->quadvarsmerged = FALSE;
2241 
2242  consdata->iscurvchecked = FALSE;
2243 
2244  return SCIP_OKAY;
2245 }
2246 
2247 /** deletes quadratic variable term at given position from quadratic constraint data */
2248 static
2250  SCIP* scip, /**< SCIP data structure */
2251  SCIP_CONS* cons, /**< quadratic constraint */
2252  int pos /**< position of term to delete */
2253  )
2254 {
2255  SCIP_CONSDATA* consdata;
2256  SCIP_VAR* var;
2257 
2258  assert(scip != NULL);
2259  assert(cons != NULL);
2260 
2261  consdata = SCIPconsGetData(cons);
2262  assert(consdata != NULL);
2263  assert(0 <= pos && pos < consdata->nquadvars);
2264 
2265  var = consdata->quadvarterms[pos].var;
2266  assert(var != NULL);
2267  assert(consdata->quadvarterms[pos].nadjbilin == 0);
2268 
2269  /* remove rounding locks for deleted variable */
2270  SCIP_CALL( unlockQuadraticVariable(scip, cons, var) );
2271 
2272  /* if we catch variable events, drop the events on the variable */
2273  if( consdata->quadvarterms[pos].eventdata != NULL )
2274  {
2275  SCIP_CONSHDLR* conshdlr;
2276  SCIP_CONSHDLRDATA* conshdlrdata;
2277 
2278  /* get event handler */
2279  conshdlr = SCIPconsGetHdlr(cons);
2280  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2281  assert(conshdlrdata != NULL);
2282  assert(conshdlrdata->eventhdlr != NULL);
2283 
2284  /* drop bound change events of variable */
2285  SCIP_CALL( dropQuadVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
2286  }
2287 
2288  /* release variable */
2289  SCIP_CALL( SCIPreleaseVar(scip, &consdata->quadvarterms[pos].var) );
2290 
2291  /* free adjacency array */
2292  SCIPfreeBlockMemoryArrayNull(scip, &consdata->quadvarterms[pos].adjbilin, consdata->quadvarterms[pos].adjbilinsize);
2293 
2294  /* move the last variable term to the free slot */
2295  consdataMoveQuadVarTerm(consdata, consdata->nquadvars-1, pos);
2296 
2297  --consdata->nquadvars;
2298 
2299  /* invalidate activity */
2300  consdata->activity = SCIP_INVALID;
2301  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2302 
2303  /* invalidate nonlinear row */
2304  if( consdata->nlrow != NULL )
2305  {
2306  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2307  }
2308 
2309  consdata->ispropagated = FALSE;
2310  consdata->ispresolved = FALSE;
2311  consdata->iscurvchecked = FALSE;
2312 
2313  return SCIP_OKAY;
2314 }
2315 
2316 /** replace variable in quadratic variable term at given position of quadratic constraint data
2317  *
2318  * Allows to replace x by coef*y+offset, thereby maintaining linear and square coefficients and bilinear terms.
2319  */
2320 static
2322  SCIP* scip, /**< SCIP data structure */
2323  SCIP_CONS* cons, /**< quadratic constraint */
2324  int pos, /**< position of term to replace */
2325  SCIP_VAR* var, /**< new variable */
2326  SCIP_Real coef, /**< linear coefficient of new variable */
2327  SCIP_Real offset /**< offset of new variable */
2328  )
2329 {
2330  SCIP_CONSDATA* consdata;
2331  SCIP_QUADVARTERM* quadvarterm;
2332  SCIP_EVENTHDLR* eventhdlr;
2333  SCIP_BILINTERM* bilinterm;
2334  SCIP_Real constant;
2335 
2336  int i;
2337  SCIP_VAR* var2;
2338 
2339  consdata = SCIPconsGetData(cons);
2340  assert(consdata != NULL);
2341  assert(pos >= 0);
2342  assert(pos < consdata->nquadvars);
2343 
2344  quadvarterm = &consdata->quadvarterms[pos];
2345 
2346  /* remove rounding locks for old variable */
2347  SCIP_CALL( unlockQuadraticVariable(scip, cons, quadvarterm->var) );
2348 
2349  /* if we catch variable events, drop the events on the old variable */
2350  if( quadvarterm->eventdata != NULL )
2351  {
2352  SCIP_CONSHDLR* conshdlr;
2353  SCIP_CONSHDLRDATA* conshdlrdata;
2354 
2355  /* get event handler */
2356  conshdlr = SCIPconsGetHdlr(cons);
2357  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2358  assert(conshdlrdata != NULL);
2359  assert(conshdlrdata->eventhdlr != NULL);
2360 
2361  eventhdlr = conshdlrdata->eventhdlr;
2362 
2363  /* drop bound change events of variable */
2364  SCIP_CALL( dropQuadVarEvents(scip, eventhdlr, cons, pos) );
2365  }
2366  else
2367  {
2368  eventhdlr = NULL;
2369  }
2370 
2371  /* compute constant and put into lhs/rhs */
2372  constant = quadvarterm->lincoef * offset + quadvarterm->sqrcoef * offset * offset;
2373  if( constant != 0.0 )
2374  {
2375  /* maintain constant part */
2376  if( !SCIPisInfinity(scip, -consdata->lhs) )
2377  consdata->lhs -= constant;
2378  if( !SCIPisInfinity(scip, consdata->rhs) )
2379  consdata->rhs -= constant;
2380  }
2381 
2382  /* update linear and square coefficient */
2383  quadvarterm->lincoef *= coef;
2384  quadvarterm->lincoef += 2.0 * quadvarterm->sqrcoef * coef * offset;
2385  quadvarterm->sqrcoef *= coef * coef;
2386 
2387  /* update bilinear terms */
2388  for( i = 0; i < quadvarterm->nadjbilin; ++i )
2389  {
2390  bilinterm = &consdata->bilinterms[quadvarterm->adjbilin[i]];
2391 
2392  if( bilinterm->var1 == quadvarterm->var )
2393  {
2394  bilinterm->var1 = var;
2395  var2 = bilinterm->var2;
2396  }
2397  else
2398  {
2399  assert(bilinterm->var2 == quadvarterm->var);
2400  bilinterm->var2 = var;
2401  var2 = bilinterm->var1;
2402  }
2403 
2404  if( var == var2 )
2405  {
2406  /* looks like we actually have a square term here */
2407  quadvarterm->lincoef += bilinterm->coef * offset;
2408  quadvarterm->sqrcoef += bilinterm->coef * coef;
2409  /* deleting bilinear terms is expensive, since it requires updating adjacency information
2410  * thus, for now we just set the coefficient to 0.0 and clear in later when the bilinear terms are merged */
2411  bilinterm->coef = 0.0;
2412  continue;
2413  }
2414 
2415  /* swap var1 and var2 if they are in wrong order */
2416  if( SCIPvarCompare(bilinterm->var1, bilinterm->var2) > 0 )
2417  {
2418  SCIP_VAR* tmp;
2419  tmp = bilinterm->var1;
2420  bilinterm->var1 = bilinterm->var2;
2421  bilinterm->var2 = tmp;
2422  }
2423  assert(SCIPvarCompare(bilinterm->var1, bilinterm->var2) == -1);
2424 
2425  if( offset != 0.0 )
2426  {
2427  /* need to find var2 and add offset*bilinterm->coef to linear coefficient */
2428  int var2pos;
2429 
2430  var2pos = 0;
2431  while( consdata->quadvarterms[var2pos].var != var2 )
2432  {
2433  ++var2pos;
2434  assert(var2pos < consdata->nquadvars);
2435  }
2436 
2437  consdata->quadvarterms[var2pos].lincoef += bilinterm->coef * offset;
2438  }
2439 
2440  bilinterm->coef *= coef;
2441  }
2442 
2443  /* release old variable */
2444  SCIP_CALL( SCIPreleaseVar(scip, &quadvarterm->var) );
2445 
2446  /* set new variable */
2447  quadvarterm->var = var;
2448 
2449  /* capture new variable */
2450  SCIP_CALL( SCIPcaptureVar(scip, quadvarterm->var) );
2451 
2452  /* catch variable events, if we do so */
2453  if( eventhdlr != NULL )
2454  {
2455  assert(SCIPconsIsEnabled(cons));
2456 
2457  /* catch bound change events of variable */
2458  SCIP_CALL( catchQuadVarEvents(scip, eventhdlr, cons, pos) );
2459  }
2460 
2461  /* invalidate activity information */
2462  consdata->activity = SCIP_INVALID;
2463  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2464 
2465  /* invalidate nonlinear row */
2466  if( consdata->nlrow != NULL )
2467  {
2468  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2469  }
2470 
2471  /* install rounding locks for new variable */
2472  SCIP_CALL( lockQuadraticVariable(scip, cons, var) );
2473 
2474  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var)
2475  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
2476  consdata->quadvarssorted = (consdata->nquadvars == 1);
2477  consdata->quadvarsmerged = FALSE;
2478  consdata->bilinsorted &= (quadvarterm->nadjbilin == 0); /*lint !e514*/
2479  consdata->bilinmerged &= (quadvarterm->nadjbilin == 0); /*lint !e514*/
2480 
2481  consdata->ispropagated = FALSE;
2482  consdata->ispresolved = FALSE;
2483  consdata->iscurvchecked = FALSE;
2484 
2485  return SCIP_OKAY;
2486 }
2487 
2488 /** adds a bilinear term to quadratic constraint */
2489 static
2491  SCIP* scip, /**< SCIP data structure */
2492  SCIP_CONS* cons, /**< quadratic constraint */
2493  int var1pos, /**< position of first variable in quadratic variables array */
2494  int var2pos, /**< position of second variable in quadratic variables array */
2495  SCIP_Real coef /**< coefficient of bilinear term */
2496  )
2497 {
2498  SCIP_CONSDATA* consdata;
2499  SCIP_BILINTERM* bilinterm;
2500 
2501  assert(scip != NULL);
2502  assert(cons != NULL);
2503 
2504  if( var1pos == var2pos )
2505  {
2506  SCIPerrorMessage("tried to add bilinear term where both variables are the same\n");
2507  return SCIP_INVALIDDATA;
2508  }
2509 
2510  consdata = SCIPconsGetData(cons);
2511  assert(consdata != NULL);
2512 
2513  /* check if the bilinear terms are sorted (disabled for big constraints as becoming expensive) */
2514  assert(consdata->nbilinterms > 10 || consdataCheckBilinTermsSort(consdata));
2515 
2516  assert(var1pos >= 0);
2517  assert(var1pos < consdata->nquadvars);
2518  assert(var2pos >= 0);
2519  assert(var2pos < consdata->nquadvars);
2520 
2521  SCIP_CALL( consdataEnsureBilinSize(scip, consdata, consdata->nbilinterms + 1) );
2522 
2523  bilinterm = &consdata->bilinterms[consdata->nbilinterms];
2524  if( SCIPvarCompare(consdata->quadvarterms[var1pos].var, consdata->quadvarterms[var2pos].var) < 0 )
2525  {
2526  bilinterm->var1 = consdata->quadvarterms[var1pos].var;
2527  bilinterm->var2 = consdata->quadvarterms[var2pos].var;
2528  }
2529  else
2530  {
2531  bilinterm->var1 = consdata->quadvarterms[var2pos].var;
2532  bilinterm->var2 = consdata->quadvarterms[var1pos].var;
2533  }
2534  bilinterm->coef = coef;
2535 
2536  if( bilinterm->var1 == bilinterm->var2 )
2537  {
2538  SCIPerrorMessage("tried to add bilinear term where both variables are the same, but appear at different positions in quadvarterms array\n");
2539  return SCIP_INVALIDDATA;
2540  }
2541  assert(SCIPvarCompare(bilinterm->var1, bilinterm->var2) == -1);
2542 
2543  SCIP_CALL( consdataEnsureAdjBilinSize(scip, &consdata->quadvarterms[var1pos], consdata->quadvarterms[var1pos].nadjbilin + 1) );
2544  SCIP_CALL( consdataEnsureAdjBilinSize(scip, &consdata->quadvarterms[var2pos], consdata->quadvarterms[var2pos].nadjbilin + 1) );
2545 
2546  consdata->quadvarterms[var1pos].adjbilin[consdata->quadvarterms[var1pos].nadjbilin] = consdata->nbilinterms;
2547  consdata->quadvarterms[var2pos].adjbilin[consdata->quadvarterms[var2pos].nadjbilin] = consdata->nbilinterms;
2548  ++consdata->quadvarterms[var1pos].nadjbilin;
2549  ++consdata->quadvarterms[var2pos].nadjbilin;
2550 
2551  ++consdata->nbilinterms;
2552 
2553  /* invalidate activity information */
2554  consdata->activity = SCIP_INVALID;
2555  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2556 
2557  /* invalidate nonlinear row */
2558  if( consdata->nlrow != NULL )
2559  {
2560  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2561  }
2562 
2563  consdata->ispropagated = FALSE;
2564  consdata->ispresolved = FALSE;
2565  if( consdata->nbilinterms == 1 )
2566  {
2567  consdata->bilinsorted = TRUE;
2568 
2569  /* we have to take care of the bilinear term in mergeAndCleanBilinearTerms() if the coefficient is zero */
2570  consdata->bilinmerged = !SCIPisZero(scip, consdata->bilinterms[0].coef);
2571  }
2572  else
2573  {
2574  consdata->bilinsorted = consdata->bilinsorted
2575  && (bilinTermComp(consdata, consdata->nbilinterms-2, consdata->nbilinterms-1) <= 0);
2576  consdata->bilinmerged = FALSE;
2577  }
2578 
2579  consdata->iscurvchecked = FALSE;
2580 
2581  /* check if the bilinear terms are sorted (disabled as expensive if big constraint) */
2582  assert(consdata->nbilinterms > 10 || consdataCheckBilinTermsSort(consdata));
2583 
2584  return SCIP_OKAY;
2585 }
2586 
2587 /** removes a set of bilinear terms and updates adjacency information in quad var terms
2588  *
2589  * Note: this function sorts the given array termposs.
2590  */
2591 static
2593  SCIP* scip, /**< SCIP data structure */
2594  SCIP_CONS* cons, /**< quadratic constraint */
2595  int nterms, /**< number of terms to delete */
2596  int* termposs /**< indices of terms to delete */
2597  )
2598 {
2599  SCIP_CONSDATA* consdata;
2600  int* newpos;
2601  int i;
2602  int j;
2603  int offset;
2604 
2605  assert(scip != NULL);
2606  assert(cons != NULL);
2607  assert(nterms == 0 || termposs != NULL);
2608 
2609  if( nterms == 0 )
2610  return SCIP_OKAY;
2611 
2612  consdata = SCIPconsGetData(cons);
2613  assert(consdata != NULL);
2614 
2615  SCIPsortInt(termposs, nterms);
2616 
2617  SCIP_CALL( SCIPallocBufferArray(scip, &newpos, consdata->nbilinterms) );
2618 
2619  i = 0;
2620  offset = 0;
2621  for( j = 0; j < consdata->nbilinterms; ++j )
2622  {
2623  /* if j'th term is deleted, increase offset and continue */
2624  if( i < nterms && j == termposs[i] )
2625  {
2626  ++offset;
2627  ++i;
2628  newpos[j] = -1;
2629  continue;
2630  }
2631 
2632  /* otherwise, move it forward and remember new position */
2633  if( offset > 0 )
2634  consdata->bilinterms[j-offset] = consdata->bilinterms[j];
2635  newpos[j] = j - offset;
2636  }
2637  assert(offset == nterms);
2638 
2639  /* update adjacency and activity information in quad var terms */
2640  for( i = 0; i < consdata->nquadvars; ++i )
2641  {
2642  offset = 0;
2643  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
2644  {
2645  assert(consdata->quadvarterms[i].adjbilin[j] < consdata->nbilinterms);
2646  if( newpos[consdata->quadvarterms[i].adjbilin[j]] == -1 )
2647  {
2648  /* corresponding bilinear term was deleted, thus increase offset */
2649  ++offset;
2650  }
2651  else
2652  {
2653  /* update index of j'th bilinear term and store at position j-offset */
2654  consdata->quadvarterms[i].adjbilin[j-offset] = newpos[consdata->quadvarterms[i].adjbilin[j]];
2655  }
2656  }
2657  consdata->quadvarterms[i].nadjbilin -= offset;
2658  /* some bilinear term was removed, so invalidate activity bounds */
2659  }
2660 
2661  consdata->nbilinterms -= nterms;
2662 
2663  SCIPfreeBufferArray(scip, &newpos);
2664 
2665  /* some quad vars may be linear now */
2666  consdata->quadvarsmerged = FALSE;
2667 
2668  consdata->ispropagated = FALSE;
2669  consdata->ispresolved = FALSE;
2670  consdata->iscurvchecked = FALSE;
2671 
2672  /* invalidate activity */
2673  consdata->activity = SCIP_INVALID;
2674  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2675 
2676  /* invalidate nonlinear row */
2677  if( consdata->nlrow != NULL )
2678  {
2679  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2680  }
2681 
2682  return SCIP_OKAY;
2683 }
2684 
2685 /** changes side of constraint and allow to change between finite and infinite
2686  *
2687  * takes care of updating events and locks of linear variables
2688  */
2689 static
2691  SCIP* scip, /**< SCIP data structure */
2692  SCIP_CONS* cons, /**< constraint */
2693  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
2694  SCIP_SIDETYPE side, /**< which side to change */
2695  SCIP_Real sideval /**< new value for side */
2696  )
2697 {
2698  SCIP_CONSDATA* consdata;
2699  int i;
2700 
2701  assert(scip != NULL);
2702  assert(cons != NULL);
2703  assert(!SCIPisInfinity(scip, side == SCIP_SIDETYPE_LEFT ? sideval : -sideval));
2704 
2705  consdata = SCIPconsGetData(cons);
2706  assert(consdata != NULL);
2707 
2708  /* if remaining finite or remaining infinite, then can just update the value */
2709  if( side == SCIP_SIDETYPE_LEFT )
2710  {
2711  if( SCIPisInfinity(scip, -consdata->lhs) == SCIPisInfinity(scip, -sideval) )
2712  {
2713  consdata->lhs = sideval;
2714  return SCIP_OKAY;
2715  }
2716  }
2717  else
2718  {
2719  if( SCIPisInfinity(scip, consdata->rhs) == SCIPisInfinity(scip, sideval) )
2720  {
2721  consdata->rhs = sideval;
2722  return SCIP_OKAY;
2723  }
2724  }
2725 
2726  /* catched boundchange events and locks for linear variables depends on whether side is finite, so first drop all */
2727  for( i = 0; i < consdata->nlinvars; ++i )
2728  {
2729  if( consdata->lineventdata != NULL && consdata->lineventdata[i] != NULL )
2730  {
2731  assert(SCIPconsIsEnabled(cons));
2732 
2733  SCIP_CALL( dropLinearVarEvents(scip, eventhdlr, cons, i) );
2734  }
2735 
2736  if( SCIPconsIsLocked(cons) )
2737  {
2738  assert(SCIPconsIsTransformed(cons));
2739 
2740  /* remove rounding locks for variable with old side */
2741  SCIP_CALL( unlockLinearVariable(scip, cons, consdata->linvars[i], consdata->lincoefs[i]) );
2742  }
2743  }
2744 
2745  if( side == SCIP_SIDETYPE_LEFT )
2746  consdata->lhs = sideval;
2747  else
2748  consdata->rhs = sideval;
2749 
2750  /* catch boundchange events and locks on variables again */
2751  for( i = 0; i < consdata->nlinvars; ++i )
2752  {
2753  if( consdata->lineventdata != NULL )
2754  {
2755  SCIP_CALL( catchLinearVarEvents(scip, eventhdlr, cons, i) );
2756  }
2757 
2758  if( SCIPconsIsLocked(cons) )
2759  {
2760  /* add rounding locks for variable with new side */
2761  SCIP_CALL( lockLinearVariable(scip, cons, consdata->linvars[i], consdata->lincoefs[i]) );
2762  }
2763  }
2764 
2765  return SCIP_OKAY;
2766 }
2767 
2768 /** merges quad var terms that correspond to the same variable and does additional cleanup
2769  *
2770  * If a quadratic variable terms is actually linear, makes a linear term out of it
2771  * also replaces squares of binary variables by the binary variables, i.e., adds sqrcoef to lincoef.
2772  */
2773 static
2775  SCIP* scip, /**< SCIP data structure */
2776  SCIP_CONS* cons /**< quadratic constraint */
2777  )
2778 {
2779  SCIP_QUADVARTERM* quadvarterm;
2780  SCIP_CONSDATA* consdata;
2781  int i;
2782  int j;
2783 
2784  assert(scip != NULL);
2785  assert(cons != NULL);
2786 
2787  consdata = SCIPconsGetData(cons);
2788 
2789  if( consdata->quadvarsmerged )
2790  return SCIP_OKAY;
2791 
2792  if( consdata->nquadvars == 0 )
2793  {
2794  consdata->quadvarsmerged = TRUE;
2795  return SCIP_OKAY;
2796  }
2797 
2798  i = 0;
2799  while( i < consdata->nquadvars )
2800  {
2801  /* make sure quad var terms are sorted (do this in every round, since we may move variables around) */
2802  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
2803 
2804  quadvarterm = &consdata->quadvarterms[i];
2805 
2806  for( j = i+1; j < consdata->nquadvars && consdata->quadvarterms[j].var == quadvarterm->var; ++j )
2807  {
2808  /* add quad var term j to current term i */
2809  quadvarterm->lincoef += consdata->quadvarterms[j].lincoef;
2810  quadvarterm->sqrcoef += consdata->quadvarterms[j].sqrcoef;
2811  if( consdata->quadvarterms[j].nadjbilin > 0 )
2812  {
2813  /* move adjacency information from j to i */
2814  SCIP_CALL( consdataEnsureAdjBilinSize(scip, quadvarterm, quadvarterm->nadjbilin + consdata->quadvarterms[j].nadjbilin) );
2815  BMScopyMemoryArray(&quadvarterm->adjbilin[quadvarterm->nadjbilin], consdata->quadvarterms[j].adjbilin, consdata->quadvarterms[j].nadjbilin); /*lint !e866*/
2816  quadvarterm->nadjbilin += consdata->quadvarterms[j].nadjbilin;
2817  consdata->quadvarterms[j].nadjbilin = 0;
2818  }
2819  consdata->quadvarterms[j].lincoef = 0.0;
2820  consdata->quadvarterms[j].sqrcoef = 0.0;
2821  /* mark that activity information in quadvarterm is not up to date anymore */
2822  }
2823 
2824  /* remove quad var terms i+1..j-1 backwards */
2825  for( j = j-1; j > i; --j )
2826  {
2827  SCIP_CALL( delQuadVarTermPos(scip, cons, j) );
2828  }
2829 
2830  /* for binary variables, x^2 = x
2831  * however, we may destroy convexity of a quadratic term that involves also bilinear terms
2832  * thus, we do this step only if the variable does not appear in any bilinear term */
2833  if( quadvarterm->sqrcoef != 0.0 && SCIPvarIsBinary(quadvarterm->var) && quadvarterm->nadjbilin == 0 )
2834  {
2835  SCIPdebugMsg(scip, "replace square of binary variable by itself: <%s>^2 --> <%s>\n", SCIPvarGetName(quadvarterm->var), SCIPvarGetName(quadvarterm->var));
2836  quadvarterm->lincoef += quadvarterm->sqrcoef;
2837  quadvarterm->sqrcoef = 0.0;
2838 
2839  /* invalidate nonlinear row */
2840  if( consdata->nlrow != NULL )
2841  {
2842  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2843  }
2844  }
2845 
2846  /* if its 0.0 or linear, get rid of it */
2847  if( SCIPisZero(scip, quadvarterm->sqrcoef) && quadvarterm->nadjbilin == 0 )
2848  {
2849  if( !SCIPisZero(scip, quadvarterm->lincoef) )
2850  {
2851  /* seem to be a linear term now, thus add as linear term */
2852  SCIP_CALL( addLinearCoef(scip, cons, quadvarterm->var, quadvarterm->lincoef) );
2853  }
2854  /* remove term at pos i */
2855  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
2856  }
2857  else
2858  {
2859  ++i;
2860  }
2861  }
2862 
2863  consdata->quadvarsmerged = TRUE;
2864  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2865 
2866  return SCIP_OKAY;
2867 }
2868 
2869 /** merges entries with same linear variable into one entry and cleans up entries with coefficient 0.0 */
2870 static
2872  SCIP* scip, /**< SCIP data structure */
2873  SCIP_CONS* cons /**< quadratic constraint */
2874  )
2875 {
2876  SCIP_CONSDATA* consdata;
2877  SCIP_Real newcoef;
2878  int i;
2879  int j;
2880  int qvarpos;
2881 
2882  assert(scip != NULL);
2883  assert(cons != NULL);
2884 
2885  consdata = SCIPconsGetData(cons);
2886 
2887  if( consdata->linvarsmerged )
2888  return SCIP_OKAY;
2889 
2890  if( consdata->nlinvars == 0 )
2891  {
2892  consdata->linvarsmerged = TRUE;
2893  return SCIP_OKAY;
2894  }
2895 
2896  i = 0;
2897  while( i < consdata->nlinvars )
2898  {
2899  /* make sure linear variables are sorted (do this in every round, since we may move variables around) */
2900  consdataSortLinearVars(consdata);
2901 
2902  /* sum up coefficients that correspond to variable i */
2903  newcoef = consdata->lincoefs[i];
2904  for( j = i+1; j < consdata->nlinvars && consdata->linvars[i] == consdata->linvars[j]; ++j )
2905  newcoef += consdata->lincoefs[j];
2906  /* delete the additional variables in backward order */
2907  for( j = j-1; j > i; --j )
2908  {
2909  SCIP_CALL( delLinearCoefPos(scip, cons, j) );
2910  }
2911 
2912  /* check if there is already a quadratic variable term with this variable */
2913  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->linvars[i], &qvarpos) );
2914  if( qvarpos >= 0)
2915  {
2916  /* add newcoef to linear coefficient of quadratic variable and mark linear variable as to delete */
2917  assert(qvarpos < consdata->nquadvars);
2918  assert(consdata->quadvarterms[qvarpos].var == consdata->linvars[i]);
2919  consdata->quadvarterms[qvarpos].lincoef += newcoef;
2920  newcoef = 0.0;
2921  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2922  }
2923 
2924  /* delete also entry at position i, if it became zero (or was zero before) */
2925  if( SCIPisZero(scip, newcoef) )
2926  {
2927  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
2928  }
2929  else
2930  {
2931  SCIP_CALL( chgLinearCoefPos(scip, cons, i, newcoef) );
2932  ++i;
2933  }
2934  }
2935 
2936  consdata->linvarsmerged = TRUE;
2937 
2938  return SCIP_OKAY;
2939 }
2940 
2941 /** merges bilinear terms with same variables into a single term, removes bilinear terms with coefficient 0.0 */
2942 static
2944  SCIP* scip, /**< SCIP data structure */
2945  SCIP_CONS* cons /**< quadratic constraint */
2946  )
2947 {
2948  SCIP_CONSDATA* consdata;
2949  SCIP_BILINTERM* bilinterm;
2950  int i;
2951  int j;
2952  int* todelete;
2953  int ntodelete;
2954 
2955  assert(scip != NULL);
2956  assert(cons != NULL);
2957 
2958  consdata = SCIPconsGetData(cons);
2959 
2960  /* check if the bilinear terms are sorted */
2961  assert(consdataCheckBilinTermsSort(consdata));
2962 
2963  if( consdata->bilinmerged )
2964  return SCIP_OKAY;
2965 
2966  if( consdata->nbilinterms == 0 )
2967  {
2968  consdata->bilinmerged = TRUE;
2969  return SCIP_OKAY;
2970  }
2971 
2972  /* alloc memory for array of terms that need to be deleted finally */
2973  ntodelete = 0;
2974  SCIP_CALL( SCIPallocBufferArray(scip, &todelete, consdata->nbilinterms) );
2975 
2976  /* make sure bilinear terms are sorted */
2977  SCIP_CALL( consdataSortBilinTerms(scip, consdata) );
2978 
2979  i = 0;
2980  while( i < consdata->nbilinterms )
2981  {
2982  bilinterm = &consdata->bilinterms[i];
2983 
2984  /* sum up coefficients that correspond to same variables as term i */
2985  for( j = i+1; j < consdata->nbilinterms && bilinterm->var1 == consdata->bilinterms[j].var1 && bilinterm->var2 == consdata->bilinterms[j].var2; ++j )
2986  {
2987  bilinterm->coef += consdata->bilinterms[j].coef;
2988  todelete[ntodelete++] = j;
2989  }
2990 
2991  /* delete also entry at position i, if it became zero (or was zero before) */
2992  if( SCIPisZero(scip, bilinterm->coef) )
2993  {
2994  todelete[ntodelete++] = i;
2995  }
2996 
2997  /* continue with term after the current series */
2998  i = j;
2999  }
3000 
3001  /* delete bilinear terms */
3002  SCIP_CALL( removeBilinearTermsPos(scip, cons, ntodelete, todelete) );
3003 
3004  SCIPfreeBufferArray(scip, &todelete);
3005 
3006  consdata->bilinmerged = TRUE;
3007 
3008  /* check if the bilinear terms are sorted */
3009  assert(consdataCheckBilinTermsSort(consdata));
3010 
3011  return SCIP_OKAY;
3012 }
3013 
3014 /** removes fixes (or aggregated) variables from a quadratic constraint */
3015 static
3017  SCIP* scip, /**< SCIP data structure */
3018  SCIP_EVENTHDLR* eventhdlr, /**< event handler for variable bound changes */
3019  SCIP_CONS* cons /**< quadratic constraint */
3020  )
3021 {
3022  SCIP_CONSDATA* consdata;
3023  SCIP_BILINTERM* bilinterm;
3024  SCIP_Real bilincoef;
3025  SCIP_Real coef;
3026  SCIP_Real offset;
3027  SCIP_VAR* var;
3028  SCIP_VAR* var2;
3029  int var2pos;
3030  int i;
3031  int j;
3032  int k;
3033 
3034  SCIP_Bool have_change;
3035 
3036  assert(scip != NULL);
3037  assert(cons != NULL);
3038 
3039  consdata = SCIPconsGetData(cons);
3040 
3041  have_change = FALSE;
3042  i = 0;
3043  while( i < consdata->nlinvars )
3044  {
3045  var = consdata->linvars[i];
3046 
3047  if( SCIPvarIsActive(var) && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
3048  {
3049  ++i;
3050  continue;
3051  }
3052 
3053  have_change = TRUE;
3054 
3055  coef = consdata->lincoefs[i];
3056  offset = 0.0;
3057 
3058  if( SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
3059  {
3060  offset = coef * (SCIPvarGetLbGlobal(var) + SCIPvarGetUbGlobal(var)) / 2.0;
3061  coef = 0.0;
3062  }
3063  else
3064  {
3065  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &coef, &offset) );
3066  }
3067 
3068  SCIPdebugMsg(scip, " linear term %g*<%s> is replaced by %g * <%s> + %g\n", consdata->lincoefs[i], SCIPvarGetName(consdata->linvars[i]),
3069  coef, SCIPvarGetName(var), offset);
3070 
3071  /* delete previous variable (this will move another variable to position i) */
3072  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
3073 
3074  /* put constant part into bounds */
3075  if( offset != 0.0 )
3076  {
3077  if( !SCIPisInfinity(scip, -consdata->lhs) )
3078  {
3079  SCIP_CALL( chgSideQuadratic(scip, cons, eventhdlr, SCIP_SIDETYPE_LEFT, consdata->lhs - offset) );
3080  }
3081  if( !SCIPisInfinity(scip, consdata->rhs) )
3082  {
3083  SCIP_CALL( chgSideQuadratic(scip, cons, eventhdlr, SCIP_SIDETYPE_RIGHT, consdata->rhs - offset) );
3084  }
3085  }
3086 
3087  /* nothing left to do if variable had been fixed */
3088  if( coef == 0.0 )
3089  continue;
3090 
3091  /* if GetProbvar gave a linear variable, just add it
3092  * if it's a multilinear variable, add it's disaggregated variables */
3093  if( SCIPvarIsActive(var) )
3094  {
3095  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
3096  }
3097  else
3098  {
3099  int naggrs;
3100  SCIP_VAR** aggrvars;
3101  SCIP_Real* aggrscalars;
3102  SCIP_Real aggrconstant;
3103 
3104  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
3105 
3106  naggrs = SCIPvarGetMultaggrNVars(var);
3107  aggrvars = SCIPvarGetMultaggrVars(var);
3108  aggrscalars = SCIPvarGetMultaggrScalars(var);
3109  aggrconstant = SCIPvarGetMultaggrConstant(var);
3110 
3111  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars + naggrs) );
3112 
3113  for( j = 0; j < naggrs; ++j )
3114  {
3115  SCIP_CALL( addLinearCoef(scip, cons, aggrvars[j], coef * aggrscalars[j]) );
3116  }
3117 
3118  if( aggrconstant != 0.0 )
3119  {
3120  if( !SCIPisInfinity(scip, -consdata->lhs) )
3121  consdata->lhs -= coef * aggrconstant;
3122  if( !SCIPisInfinity(scip, consdata->rhs) )
3123  consdata->rhs -= coef * aggrconstant;
3124  }
3125  }
3126  }
3127 
3128  i = 0;
3129  while( i < consdata->nquadvars )
3130  {
3131  var = consdata->quadvarterms[i].var;
3132 
3133  if( SCIPvarIsActive(var) && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
3134  {
3135  ++i;
3136  continue;
3137  }
3138 
3139  have_change = TRUE;
3140 
3141  coef = 1.0;
3142  offset = 0.0;
3143 
3144  if( !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
3145  {
3146  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &coef, &offset) );
3147  }
3148  else
3149  {
3150  coef = 0.0;
3151  offset = (SCIPvarGetLbGlobal(var) + SCIPvarGetUbGlobal(var)) / 2.0;
3152  }
3153 
3154  SCIPdebugMsg(scip, " quadratic variable <%s> with status %d is replaced by %g * <%s> + %g\n", SCIPvarGetName(consdata->quadvarterms[i].var),
3155  SCIPvarGetStatus(consdata->quadvarterms[i].var), coef, SCIPvarGetName(var), offset);
3156 
3157  /* handle fixed variable */
3158  if( coef == 0.0 )
3159  {
3160  /* if not fixed to 0.0, add to linear coefs of vars in bilinear terms, and deal with linear and square term as constant */
3161  if( offset != 0.0 )
3162  {
3163  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
3164  {
3165  bilinterm = &consdata->bilinterms[consdata->quadvarterms[i].adjbilin[j]];
3166 
3167  var2 = bilinterm->var1 == consdata->quadvarterms[i].var ? bilinterm->var2 : bilinterm->var1;
3168  assert(var2 != consdata->quadvarterms[i].var);
3169 
3170  var2pos = 0;
3171  while( consdata->quadvarterms[var2pos].var != var2 )
3172  {
3173  ++var2pos;
3174  assert(var2pos < consdata->nquadvars);
3175  }
3176  consdata->quadvarterms[var2pos].lincoef += bilinterm->coef * offset;
3177  }
3178 
3179  offset = consdata->quadvarterms[i].lincoef * offset + consdata->quadvarterms[i].sqrcoef * offset * offset;
3180  if( !SCIPisInfinity(scip, -consdata->lhs) )
3181  consdata->lhs -= offset;
3182  if( !SCIPisInfinity(scip, consdata->rhs) )
3183  consdata->rhs -= offset;
3184  }
3185 
3186  /* remove bilinear terms */
3187  SCIP_CALL( removeBilinearTermsPos(scip, cons, consdata->quadvarterms[i].nadjbilin, consdata->quadvarterms[i].adjbilin) );
3188 
3189  /* delete quad. var term i */
3190  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
3191 
3192  continue;
3193  }
3194 
3195  assert(var != NULL);
3196 
3197  /* if GetProbvar gave an active variable, replace the quad var term so that it uses the new variable */
3198  if( SCIPvarIsActive(var) )
3199  {
3200  /* replace x by coef*y+offset */
3201  SCIP_CALL( replaceQuadVarTermPos(scip, cons, i, var, coef, offset) );
3202 
3203  continue;
3204  }
3205  else
3206  {
3207  /* if GetProbVar gave a multi-aggregated variable, add new quad var terms and new bilinear terms
3208  * x is replaced by coef * (sum_i a_ix_i + b) + offset
3209  * lcoef * x + scoef * x^2 + bcoef * x * y ->
3210  * (b*coef + offset) * (lcoef + (b*coef + offset) * scoef)
3211  * + sum_i a_i*coef * (lcoef + 2 (b*coef + offset) * scoef) x_i
3212  * + sum_i (a_i*coef)^2 * scoef * x_i^2
3213  * + 2 sum_{i,j, i<j} (a_i a_j coef^2 scoef) x_i x_j
3214  * + bcoef * (b*coef + offset + coef * sum_i a_ix_i) y
3215  */
3216  int naggrs;
3217  SCIP_VAR** aggrvars; /* x_i */
3218  SCIP_Real* aggrscalars; /* a_i */
3219  SCIP_Real aggrconstant; /* b */
3220  int nquadtermsold;
3221 
3222  SCIP_Real lcoef;
3223  SCIP_Real scoef;
3224 
3225  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
3226 
3227  naggrs = SCIPvarGetMultaggrNVars(var);
3228  aggrvars = SCIPvarGetMultaggrVars(var);
3229  aggrscalars = SCIPvarGetMultaggrScalars(var);
3230  aggrconstant = SCIPvarGetMultaggrConstant(var);
3231 
3232  lcoef = consdata->quadvarterms[i].lincoef;
3233  scoef = consdata->quadvarterms[i].sqrcoef;
3234 
3235  nquadtermsold = consdata->nquadvars;
3236 
3237  SCIP_CALL( consdataEnsureQuadVarTermsSize(scip, consdata, consdata->nquadvars + naggrs) );
3238 
3239  /* take care of constant part */
3240  if( aggrconstant != 0.0 || offset != 0.0 )
3241  {
3242  SCIP_Real constant;
3243  constant = (aggrconstant * coef + offset) * (lcoef + (aggrconstant * coef + offset) * scoef);
3244  if( !SCIPisInfinity(scip, -consdata->lhs) )
3245  consdata->lhs -= constant;
3246  if( !SCIPisInfinity(scip, consdata->rhs) )
3247  consdata->rhs -= constant;
3248  }
3249 
3250  /* add x_i's with linear and square coefficients */
3251  for( j = 0; j < naggrs; ++j )
3252  {
3253  SCIP_CALL( addQuadVarTerm(scip, cons, aggrvars[j],
3254  coef * aggrscalars[j] * (lcoef + 2.0 * scoef * (coef * aggrconstant + offset)),
3255  coef * coef * aggrscalars[j] * aggrscalars[j] * scoef) );
3256  }
3257 
3258  /* ensure space for bilinear terms */
3259  SCIP_CALL( consdataEnsureBilinSize(scip, consdata, consdata->nquadvars + (scoef != 0.0 ? (naggrs * (naggrs-1))/2 : 0) + consdata->quadvarterms[j].nadjbilin * naggrs) );
3260 
3261  /* add x_j*x_k's */
3262  if( scoef != 0.0 )
3263  {
3264  for( j = 0; j < naggrs; ++j )
3265  for( k = 0; k < j; ++k )
3266  {
3267  assert(aggrvars[j] != aggrvars[k]);
3268  SCIP_CALL( addBilinearTerm(scip, cons, nquadtermsold + j, nquadtermsold + k,
3269  2.0 * aggrscalars[j] * aggrscalars[k] * coef * coef * scoef) );
3270  }
3271  }
3272 
3273  /* add x_i*y's */
3274  for( k = 0; k < consdata->quadvarterms[i].nadjbilin; ++k )
3275  {
3276  bilinterm = &consdata->bilinterms[consdata->quadvarterms[i].adjbilin[k]];
3277  bilincoef = bilinterm->coef; /* copy coef, as bilinterm pointer may become invalid by realloc in addBilinearTerm() below */
3278  var2 = (bilinterm->var1 == consdata->quadvarterms[i].var) ? bilinterm->var2 : bilinterm->var1;
3279  assert(var2 != consdata->quadvarterms[i].var);
3280 
3281  /* this is not efficient, but we cannot sort the quadratic terms here, since we currently iterate over them */
3282  var2pos = 0;
3283  while( consdata->quadvarterms[var2pos].var != var2 )
3284  {
3285  ++var2pos;
3286  assert(var2pos < consdata->nquadvars);
3287  }
3288 
3289  for( j = 0; j < naggrs; ++j )
3290  {
3291  if( aggrvars[j] == var2 )
3292  { /* x_i == y, so we have a square term here */
3293  consdata->quadvarterms[var2pos].sqrcoef += bilincoef * coef * aggrscalars[j];
3294  }
3295  else
3296  { /* x_i != y, so we need to add a bilinear term here */
3297  SCIP_CALL( addBilinearTerm(scip, cons, nquadtermsold + j, var2pos, bilincoef * coef * aggrscalars[j]) );
3298  }
3299  }
3300 
3301  consdata->quadvarterms[var2pos].lincoef += bilincoef * (aggrconstant * coef + offset);
3302  }
3303 
3304  /* remove bilinear terms */
3305  SCIP_CALL( removeBilinearTermsPos(scip, cons, consdata->quadvarterms[i].nadjbilin, consdata->quadvarterms[i].adjbilin) );
3306 
3307  /* delete quad. var term i */
3308  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
3309  }
3310  }
3311 
3312  consdata->isremovedfixings = TRUE;
3313 
3314  SCIPdebugMsg(scip, "removed fixations from <%s>\n -> ", SCIPconsGetName(cons));
3315  SCIPdebugPrintCons(scip, cons, NULL);
3316 
3317 #ifndef NDEBUG
3318  for( i = 0; i < consdata->nlinvars; ++i )
3319  assert(SCIPvarIsActive(consdata->linvars[i]));
3320 
3321  for( i = 0; i < consdata->nquadvars; ++i )
3322  assert(SCIPvarIsActive(consdata->quadvarterms[i].var));
3323 #endif
3324 
3325  if( !have_change )
3326  return SCIP_OKAY;
3327 
3328  /* some quadratic variable may have been replaced by an already existing linear variable
3329  * in this case, we want the linear variable to be removed, which happens in mergeAndCleanLinearVars
3330  */
3331  consdata->linvarsmerged = FALSE;
3332 
3333  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
3334  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, cons) );
3335  SCIP_CALL( mergeAndCleanLinearVars(scip, cons) );
3336 
3337 #ifndef NDEBUG
3338  for( i = 0; i < consdata->nbilinterms; ++i )
3339  {
3340  assert(consdata->bilinterms[i].var1 != consdata->bilinterms[i].var2);
3341  assert(consdata->bilinterms[i].coef != 0.0);
3342  assert(SCIPvarCompare(consdata->bilinterms[i].var1, consdata->bilinterms[i].var2) < 0);
3343  }
3344 #endif
3345 
3346  return SCIP_OKAY;
3347 }
3348 
3349 /** create a nonlinear row representation of the constraint and stores them in consdata */
3350 static
3352  SCIP* scip, /**< SCIP data structure */
3353  SCIP_CONS* cons /**< quadratic constraint */
3354  )
3355 {
3356  SCIP_CONSDATA* consdata;
3357  int nquadvars; /* number of variables in quadratic terms */
3358  SCIP_VAR** quadvars; /* variables in quadratic terms */
3359  int nquadelems; /* number of quadratic elements (square and bilinear terms) */
3360  SCIP_QUADELEM* quadelems; /* quadratic elements (square and bilinear terms) */
3361  int nquadlinterms; /* number of linear terms using variables that are in quadratic terms */
3362  SCIP_VAR** quadlinvars; /* variables of linear terms using variables that are in quadratic terms */
3363  SCIP_Real* quadlincoefs; /* coefficients of linear terms using variables that are in quadratic terms */
3364  int i;
3365  int idx1;
3366  int idx2;
3367  int lincnt;
3368  int elcnt;
3369  SCIP_VAR* lastvar;
3370  int lastvaridx;
3371  SCIP_EXPRCURV curvature;
3372 
3373  assert(scip != NULL);
3374  assert(cons != NULL);
3375 
3376  consdata = SCIPconsGetData(cons);
3377  assert(consdata != NULL);
3378 
3379  if( consdata->nlrow != NULL )
3380  {
3381  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3382  }
3383 
3384  nquadvars = consdata->nquadvars;
3385  nquadelems = consdata->nbilinterms;
3386  nquadlinterms = 0;
3387  for( i = 0; i < nquadvars; ++i )
3388  {
3389  if( consdata->quadvarterms[i].sqrcoef != 0.0 )
3390  ++nquadelems;
3391  if( !SCIPisZero(scip, consdata->quadvarterms[i].lincoef) )
3392  ++nquadlinterms;
3393  }
3394 
3395  SCIP_CALL( SCIPallocBufferArray(scip, &quadvars, nquadvars) );
3396  SCIP_CALL( SCIPallocBufferArray(scip, &quadelems, nquadelems) );
3397  SCIP_CALL( SCIPallocBufferArray(scip, &quadlinvars, nquadlinterms) );
3398  SCIP_CALL( SCIPallocBufferArray(scip, &quadlincoefs, nquadlinterms) );
3399 
3400  lincnt = 0;
3401  elcnt = 0;
3402  for( i = 0; i < nquadvars; ++i )
3403  {
3404  quadvars[i] = consdata->quadvarterms[i].var;
3405 
3406  if( consdata->quadvarterms[i].sqrcoef != 0.0 )
3407  {
3408  assert(elcnt < nquadelems);
3409  quadelems[elcnt].idx1 = i;
3410  quadelems[elcnt].idx2 = i;
3411  quadelems[elcnt].coef = consdata->quadvarterms[i].sqrcoef;
3412  ++elcnt;
3413  }
3414 
3415  if( !SCIPisZero(scip, consdata->quadvarterms[i].lincoef) )
3416  {
3417  assert(lincnt < nquadlinterms);
3418  quadlinvars [lincnt] = consdata->quadvarterms[i].var;
3419  quadlincoefs[lincnt] = consdata->quadvarterms[i].lincoef;
3420  ++lincnt;
3421  }
3422  }
3423  assert(lincnt == nquadlinterms);
3424 
3425  /* bilinear terms are sorted first by first variable, then by second variable
3426  * 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 */
3427  lastvar = NULL;
3428  lastvaridx = -1;
3429  for( i = 0; i < consdata->nbilinterms; ++i )
3430  {
3431  if( lastvar == consdata->bilinterms[i].var1 )
3432  {
3433  assert(lastvaridx >= 0);
3434  assert(consdata->quadvarterms[lastvaridx].var == consdata->bilinterms[i].var1);
3435  }
3436  else
3437  {
3438  lastvar = consdata->bilinterms[i].var1;
3439  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, lastvar, &lastvaridx) );
3440  }
3441  idx1 = lastvaridx;
3442 
3443  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->bilinterms[i].var2, &idx2) );
3444 
3445  assert(elcnt < nquadelems);
3446  quadelems[elcnt].idx1 = MIN(idx1, idx2);
3447  quadelems[elcnt].idx2 = MAX(idx1, idx2);
3448  quadelems[elcnt].coef = consdata->bilinterms[i].coef;
3449  ++elcnt;
3450  }
3451  assert(elcnt == nquadelems);
3452 
3453  /* set curvature for the nonlinear row */
3454  if( consdata->isconcave && consdata->isconvex )
3455  {
3456  assert(consdata->nbilinterms == 0 && consdata->nquadvars == 0);
3457  curvature = SCIP_EXPRCURV_LINEAR;
3458  }
3459  else if( consdata->isconcave )
3460  curvature = SCIP_EXPRCURV_CONCAVE;
3461  else if( consdata->isconvex )
3462  curvature = SCIP_EXPRCURV_CONVEX;
3463  else
3464  curvature = SCIP_EXPRCURV_UNKNOWN;
3465 
3466  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
3467  consdata->nlinvars, consdata->linvars, consdata->lincoefs,
3468  nquadvars, quadvars, nquadelems, quadelems,
3469  NULL, consdata->lhs, consdata->rhs,
3470  curvature) );
3471 
3472  SCIP_CALL( SCIPaddLinearCoefsToNlRow(scip, consdata->nlrow, nquadlinterms, quadlinvars, quadlincoefs) );
3473 
3474  SCIPfreeBufferArray(scip, &quadlincoefs);
3475  SCIPfreeBufferArray(scip, &quadlinvars);
3476  SCIPfreeBufferArray(scip, &quadelems);
3477  SCIPfreeBufferArray(scip, &quadvars);
3478 
3479  return SCIP_OKAY;
3480 }
3481 
3482 /** solve constraint as presolving */
3483 static
3485  SCIP* scip, /**< SCIP data structure */
3486  SCIP_CONS* cons, /**< constraint */
3487  SCIP_RESULT* result, /**< to store result of solve: cutoff, success, or do-not-find */
3488  SCIP_Bool* redundant, /**< to store whether constraint is redundant now (should be deleted) */
3489  int* naggrvars /**< counter on number of variable aggregations */
3490  )
3491 {
3492  SCIP_CONSDATA* consdata;
3493 
3494  assert(scip != NULL);
3495  assert(cons != NULL);
3496  assert(result != NULL);
3497  assert(redundant != NULL);
3498 
3499  *result = SCIP_DIDNOTFIND;
3500  *redundant = FALSE;
3501 
3502  consdata = SCIPconsGetData(cons);
3503  assert(consdata != NULL);
3504 
3505  /* if constraint is an equality with two variables, at least one of them binary,
3506  * and linear after fixing the binary, then we can aggregate the variables */
3507  if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) && consdata->nlinvars == 0 && consdata->nquadvars == 2 &&
3508  ((SCIPvarIsBinary(consdata->quadvarterms[0].var) && consdata->quadvarterms[1].sqrcoef == 0.0) ||
3509  (SCIPvarIsBinary(consdata->quadvarterms[1].var) && consdata->quadvarterms[0].sqrcoef == 0.0)) )
3510  {
3511  SCIP_Bool infeasible;
3512  SCIP_Bool aggregated;
3513  SCIP_Real a;
3514  SCIP_Real b;
3515  SCIP_Real c;
3516  SCIP_VAR* x;
3517  SCIP_VAR* y;
3518  int binvaridx;
3519 
3520  /* constraint is a*(x+x^2) + b*y + c*x*y = rhs, with x binary variable
3521  * x = 0 -> b*y == rhs
3522  * x = 1 -> (b+c)*y == rhs - a
3523  *
3524  * 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
3525  */
3526 
3527  binvaridx = (SCIPvarIsBinary(consdata->quadvarterms[0].var) && consdata->quadvarterms[1].sqrcoef == 0.0) ? 0 : 1;
3528 
3529  x = consdata->quadvarterms[binvaridx].var;
3530  a = consdata->quadvarterms[binvaridx].sqrcoef + consdata->quadvarterms[binvaridx].lincoef;
3531 
3532  y = consdata->quadvarterms[1-binvaridx].var;
3533  b = consdata->quadvarterms[1-binvaridx].lincoef;
3534 
3535  assert(consdata->nbilinterms <= 1); /* should actually be 1, since constraint is otherwise linear */
3536  c = (consdata->nbilinterms == 1) ? consdata->bilinterms[0].coef : 0.0;
3537 
3538  if( !SCIPisZero(scip, b) && !SCIPisZero(scip, b+c) )
3539  {
3540  SCIPdebugMsg(scip, "<%s> = 0 -> %g*<%s> = %g and <%s> = 1 -> %g*<%s> = %g\n", SCIPvarGetName(x), b, SCIPvarGetName(y), consdata->rhs,
3541  SCIPvarGetName(x), b+c, SCIPvarGetName(y), consdata->rhs - a);
3542  SCIPdebugMsg(scip, "=> attempt aggregation <%s> = %g*<%s> + %g\n", SCIPvarGetName(y), (consdata->rhs-a)/(b+c) - consdata->rhs/b,
3543  SCIPvarGetName(x), consdata->rhs/b);
3544 
3545  SCIP_CALL( SCIPaggregateVars(scip, x, y, (consdata->rhs-a)/(b+c) - consdata->rhs/b, -1.0, -consdata->rhs/b, &infeasible, redundant, &aggregated) );
3546  if( infeasible )
3547  *result = SCIP_CUTOFF;
3548  else if( *redundant || aggregated )
3549  {
3550  /* aggregated (or were already aggregated), so constraint is now redundant */
3551  *result = SCIP_SUCCESS;
3552  *redundant = TRUE;
3553 
3554  if( aggregated )
3555  ++*naggrvars;
3556  }
3557  }
3558 
3559  /* @todo if b is 0 or b+c is 0, or lhs != rhs, then could replace by varbound constraint */
3560  }
3561 
3562  return SCIP_OKAY;
3563 }
3564 
3565 
3566 /** reformulates products of binary variables as AND constraint
3567  *
3568  * 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.
3569  */
3570 static
3572  SCIP* scip, /**< SCIP data structure */
3573  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3574  SCIP_CONS* cons, /**< constraint */
3575  int* naddconss /**< buffer where to add the number of AND constraints added */
3576  )
3577 {
3578  SCIP_CONSHDLRDATA* conshdlrdata;
3579  SCIP_CONSDATA* consdata;
3580  char name[SCIP_MAXSTRLEN];
3581  SCIP_VAR* vars[2];
3582  SCIP_VAR* auxvar;
3583  SCIP_CONS* andcons;
3584  int i;
3585  int ntodelete;
3586  int* todelete;
3587 
3588  assert(scip != NULL);
3589  assert(conshdlr != NULL);
3590  assert(cons != NULL);
3591  assert(naddconss != NULL);
3592 
3593  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3594  assert(conshdlrdata != NULL);
3595 
3596  /* if no binary variables, then we will find nothing to reformulate here
3597  * (note that this does not count in integer variables with {0,1} bounds...)
3598  */
3599  if( SCIPgetNBinVars(scip) == 0 )
3600  return SCIP_OKAY;
3601 
3602  /* if user does not like AND very much, then return */
3603  if( conshdlrdata->empathy4and < 2 )
3604  return SCIP_OKAY;
3605 
3606  consdata = SCIPconsGetData(cons);
3607  assert(consdata != NULL);
3608 
3609  if( consdata->nbilinterms == 0 )
3610  return SCIP_OKAY;
3611 
3612  /* get array to store indices of bilinear terms that shall be deleted */
3613  SCIP_CALL( SCIPallocBufferArray(scip, &todelete, consdata->nbilinterms) );
3614  ntodelete = 0;
3615 
3616  for( i = 0; i < consdata->nbilinterms; ++i )
3617  {
3618  vars[0] = consdata->bilinterms[i].var1;
3619  if( !SCIPvarIsBinary(vars[0]) )
3620  continue;
3621 
3622  vars[1] = consdata->bilinterms[i].var2;
3623  if( !SCIPvarIsBinary(vars[1]) )
3624  continue;
3625 
3626  /* create auxiliary variable */
3627  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_%s", SCIPvarGetName(vars[0]), SCIPvarGetName(vars[1]), SCIPconsGetName(cons));
3628  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY,
3629  SCIPvarIsInitial(vars[0]) || SCIPvarIsInitial(vars[1]), SCIPvarIsRemovable(vars[0]) && SCIPvarIsRemovable(vars[1]), NULL, NULL, NULL, NULL, NULL) );
3630  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3631 #ifdef WITH_DEBUG_SOLUTION
3632  if( SCIPdebugIsMainscip(scip) )
3633  {
3634  SCIP_Real var0val;
3635  SCIP_Real var1val;
3636  SCIP_CALL( SCIPdebugGetSolVal(scip, vars[0], &var0val) );
3637  SCIP_CALL( SCIPdebugGetSolVal(scip, vars[1], &var1val) );
3638  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, var0val * var1val) );
3639  }
3640 #endif
3641 
3642  /* create AND-constraint auxvar = x and y, need to be enforced as not redundant */
3643  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%sAND%s", SCIPvarGetName(vars[0]), SCIPvarGetName(vars[1]));
3644  SCIP_CALL( SCIPcreateConsAnd(scip, &andcons, name, auxvar, 2, vars,
3645  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3646  SCIPconsIsSeparated(cons), TRUE, TRUE,
3649  SCIP_CALL( SCIPaddCons(scip, andcons) );
3650  SCIPdebugMsg(scip, "added AND constraint: ");
3651  SCIPdebugPrintCons(scip, andcons, NULL);
3652  SCIP_CALL( SCIPreleaseCons(scip, &andcons) );
3653  ++*naddconss;
3654 
3655  /* add bilincoef * auxvar to linear terms */
3656  SCIP_CALL( addLinearCoef(scip, cons, auxvar, consdata->bilinterms[i].coef) );
3657  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
3658 
3659  /* remember that we have to delete this bilinear term */
3660  assert(ntodelete < consdata->nbilinterms);
3661  todelete[ntodelete++] = i;
3662  }
3663 
3664  /* remove bilinear terms that have been replaced */
3665  SCIP_CALL( removeBilinearTermsPos(scip, cons, ntodelete, todelete) );
3666  SCIPfreeBufferArray(scip, &todelete);
3667 
3668  return SCIP_OKAY;
3669 }
3670 
3671 /** gets bounds of variable y if x takes a certain value; checks whether x = xval has implications on y */
3672 static
3674  SCIP* scip, /**< SCIP data structure */
3675  SCIP_VAR* x, /**< variable which implications to check */
3676  SCIP_Bool xval, /**< value of x to check for (TRUE for 1, FALSE for 0) */
3677  SCIP_VAR* y, /**< variable to check if bounds can be reduced */
3678  SCIP_INTERVAL* resultant /**< buffer to store bounds on y */
3679  )
3680 {
3681  SCIP_VAR** implvars;
3682  SCIP_BOUNDTYPE* impltypes;
3683  SCIP_Real* implbounds;
3684  int nimpls;
3685  int pos;
3686 
3687  assert(scip != NULL);
3688  assert(x != NULL);
3689  assert(y != NULL);
3690  assert(resultant != NULL);
3691 
3693 
3694  if( !SCIPvarIsBinary(x) || !SCIPvarIsActive(x) )
3695  return SCIP_OKAY;
3696 
3697  /* check in cliques for binary to binary implications */
3698  if( SCIPvarIsBinary(y) )
3699  {
3700  resultant->inf = MAX(resultant->inf, MIN(resultant->sup, 0.0));
3701  resultant->sup = MIN(resultant->sup, MAX(resultant->inf, 1.0));
3702 
3703  if( SCIPhaveVarsCommonClique(scip, x, xval, y, TRUE, FALSE) )
3704  {
3705  resultant->sup = MIN(resultant->sup, MAX(resultant->inf, 0.0));
3706  }
3707  else if( SCIPhaveVarsCommonClique(scip, x, xval, y, FALSE, FALSE) )
3708  {
3709  resultant->inf = MAX(resultant->inf, MIN(resultant->sup, 1.0));
3710  }
3711 
3712  return SCIP_OKAY;
3713  }
3714 
3715  /* analyze implications for x = xval */
3716  nimpls = SCIPvarGetNImpls(x, xval);
3717  if( nimpls == 0 )
3718  return SCIP_OKAY;
3719 
3720  implvars = SCIPvarGetImplVars (x, xval);
3721  impltypes = SCIPvarGetImplTypes (x, xval);
3722  implbounds = SCIPvarGetImplBounds(x, xval);
3723 
3724  assert(implvars != NULL);
3725  assert(impltypes != NULL);
3726  assert(implbounds != NULL);
3727 
3728  /* find implications */
3729  if( !SCIPsortedvecFindPtr((void**)implvars, SCIPvarComp, (void*)y, nimpls, &pos) )
3730  return SCIP_OKAY;
3731 
3732  /* if there are several implications on y, go to the first one */
3733  while( pos > 0 && implvars[pos-1] == y )
3734  --pos;
3735 
3736  /* update implied lower and upper bounds on y
3737  * but make sure that resultant will not be empty, due to tolerances
3738  */
3739  while( pos < nimpls && implvars[pos] == y )
3740  {
3741  if( impltypes[pos] == SCIP_BOUNDTYPE_LOWER )
3742  resultant->inf = MAX(resultant->inf, MIN(resultant->sup, implbounds[pos]));
3743  else
3744  resultant->sup = MIN(resultant->sup, MAX(resultant->inf, implbounds[pos]));
3745  ++pos;
3746  }
3747 
3748  assert(resultant->sup >= resultant->inf);
3749 
3750  return SCIP_OKAY;
3751 }
3752 
3753 /** Reformulates products of binary times bounded continuous variables as system of linear inequalities (plus auxiliary variable).
3754  *
3755  * For a product x*y, with y a binary variable and x a continous variable with finite bounds,
3756  * 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.
3757  *
3758  * 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.
3759  * For each product of linear term of length at most maxnrvar with y, an auxiliary z and linear inequalities are added.
3760  *
3761  * If y is a binary variable, the AND constraint \f$ z = x \wedge y \f$ may be added instead of linear constraints.
3762  */
3763 static
3765  SCIP* scip, /**< SCIP data structure */
3766  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3767  SCIP_CONS* cons, /**< constraint */
3768  int* naddconss /**< buffer where to add the number of auxiliary constraints added */
3769  )
3770 { /*lint --e{666} */
3771  SCIP_CONSHDLRDATA* conshdlrdata;
3772  SCIP_CONSDATA* consdata;
3773  SCIP_VAR** xvars;
3774  SCIP_Real* xcoef;
3775  SCIP_INTERVAL xbndszero;
3776  SCIP_INTERVAL xbndsone;
3777  SCIP_INTERVAL act0;
3778  SCIP_INTERVAL act1;
3779  int nxvars;
3780  SCIP_VAR* y;
3781  SCIP_VAR* bvar;
3782  char name[SCIP_MAXSTRLEN];
3783  int nbilinterms;
3784  SCIP_VAR* auxvar;
3785  SCIP_CONS* auxcons;
3786  int i;
3787  int j;
3788  int k;
3789  int bilinidx;
3790  SCIP_Real bilincoef;
3791  SCIP_Real mincoef;
3792  SCIP_Real maxcoef;
3793  int* todelete;
3794  int ntodelete;
3795  int maxnrvar;
3796  SCIP_Bool integral;
3797  SCIP_Longint gcd;
3798  SCIP_Bool auxvarinitial;
3799  SCIP_Bool auxvarremovable;
3800 
3801  assert(scip != NULL);
3802  assert(conshdlr != NULL);
3803  assert(cons != NULL);
3804  assert(naddconss != NULL);
3805 
3806  /* if no binary variables, then we will find nothing to reformulate here
3807  * (note that this does not count in integer variables with {0,1} bounds...)
3808  */
3809  if( SCIPgetNBinVars(scip) == 0 )
3810  return SCIP_OKAY;
3811 
3812  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3813  assert(conshdlrdata != NULL);
3814 
3815  maxnrvar = conshdlrdata->replacebinaryprodlength;
3816  if( maxnrvar == 0 )
3817  return SCIP_OKAY;
3818 
3819  consdata = SCIPconsGetData(cons);
3820  assert(consdata != NULL);
3821 
3822  xvars = NULL;
3823  xcoef = NULL;
3824  todelete = NULL;
3825  gcd = 0;
3826 
3827  for( i = 0; i < consdata->nquadvars; ++i )
3828  {
3829  y = consdata->quadvarterms[i].var;
3830  if( !SCIPvarIsBinary(y) )
3831  continue;
3832 
3833  nbilinterms = consdata->quadvarterms[i].nadjbilin;
3834  if( nbilinterms == 0 )
3835  continue;
3836 
3837  SCIP_CALL( SCIPreallocBufferArray(scip, &xvars, MIN(maxnrvar, nbilinterms)+2) ); /* add 2 for later use when creating linear constraints */
3838  SCIP_CALL( SCIPreallocBufferArray(scip, &xcoef, MIN(maxnrvar, nbilinterms)+2) );
3839 
3840  /* alloc array to store indices of bilinear terms that shall be deleted */
3841  SCIP_CALL( SCIPreallocBufferArray(scip, &todelete, nbilinterms) );
3842  ntodelete = 0;
3843 
3844  auxvarinitial = SCIPvarIsInitial(y);
3845  auxvarremovable = SCIPvarIsRemovable(y);
3846 
3847  /* 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)
3848  * and compute range of sum_i a_i*x_i for the cases y = 0 and y = 1
3849  * we may need several rounds if maxnrvar < nbilinterms
3850  */
3851  j = 0;
3852  do
3853  {
3854  nxvars = 0;
3855  SCIPintervalSet(&xbndszero, 0.0);
3856  SCIPintervalSet(&xbndsone, 0.0);
3857 
3858  mincoef = SCIPinfinity(scip);
3859  maxcoef = 0.0;
3860  integral = TRUE;
3861 
3862  /* collect at most maxnrvar variables for x term */
3863  for( ; j < nbilinterms && nxvars < maxnrvar; ++j )
3864  {
3865  bilinidx = consdata->quadvarterms[i].adjbilin[j];
3866  assert(bilinidx >= 0);
3867  assert(bilinidx < consdata->nbilinterms);
3868 
3869  bvar = consdata->bilinterms[bilinidx].var1;
3870  if( bvar == y )
3871  bvar = consdata->bilinterms[bilinidx].var2;
3872  assert(bvar != y);
3873 
3874  /* skip products with unbounded variables */
3875  if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(bvar)) || SCIPisInfinity(scip, SCIPvarGetUbGlobal(bvar)) )
3876  {
3877  SCIPdebugMsg(scip, "skip reform of <%s><%s> due to unbounded second variable [%g,%g]\n",
3879  continue;
3880  }
3881 
3882  /* skip products with non-binary variables if binreformbinaryonly is set */
3883  if( conshdlrdata->binreformbinaryonly && !SCIPvarIsBinary(bvar) )
3884  {
3885  SCIPdebugMsg(scip, "skip reform of <%s><%s> because second variable is not binary\n",
3886  SCIPvarGetName(y), SCIPvarGetName(bvar));
3887  continue;
3888  }
3889 
3890  bilincoef = consdata->bilinterms[bilinidx].coef;
3891  assert(bilincoef != 0.0);
3892 
3893  /* get activity of bilincoef * x if y = 0 */
3894  SCIP_CALL( getImpliedBounds(scip, y, FALSE, bvar, &act0) );
3895  SCIPintervalMulScalar(SCIPinfinity(scip), &act0, act0, bilincoef);
3896 
3897  /* get activity of bilincoef * x if y = 1 */
3898  SCIP_CALL( getImpliedBounds(scip, y, TRUE, bvar, &act1) );
3899  SCIPintervalMulScalar(SCIPinfinity(scip), &act1, act1, bilincoef);
3900 
3901  /* skip products that give rise to very large coefficients (big big-M's) */
3902  if( SCIPfeastol(scip) * REALABS(act0.inf) >= conshdlrdata->binreformmaxcoef || SCIPfeastol(scip) * REALABS(act0.sup) >= conshdlrdata->binreformmaxcoef )
3903  {
3904  SCIPdebugMsg(scip, "skip reform of %g<%s><%s> due to huge activity [%g,%g] for <%s> = 0.0\n",
3905  bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar), SCIPintervalGetInf(act0), SCIPintervalGetSup(act0), SCIPvarGetName(y));
3906  continue;
3907  }
3908  if( SCIPfeastol(scip) * REALABS(act1.inf) >= conshdlrdata->binreformmaxcoef || SCIPfeastol(scip) * REALABS(act1.sup) >= conshdlrdata->binreformmaxcoef )
3909  {
3910  SCIPdebugMsg(scip, "skip reform of %g<%s><%s> due to huge activity [%g,%g] for <%s> = 1.0\n",
3911  bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar), SCIPintervalGetInf(act1), SCIPintervalGetSup(act1), SCIPvarGetName(y));
3912  continue;
3913  }
3914  if( !SCIPisZero(scip, MIN(REALABS(act0.inf), REALABS(act0.sup))) &&
3915  SCIPfeastol(scip) * MAX(REALABS(act0.inf), REALABS(act0.sup)) / MIN(REALABS(act0.inf), REALABS(act0.sup)) >= conshdlrdata->binreformmaxcoef )
3916  {
3917  SCIPdebugMsg(scip, "skip reform of %g<%s><%s> due to huge activity ratio %g for <%s> = 0.0\n", bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar),
3918  MAX(REALABS(act0.inf), REALABS(act0.sup)) / MIN(REALABS(act0.inf), REALABS(act0.sup)), SCIPvarGetName(y));
3919  continue;
3920  }
3921  if( !SCIPisZero(scip, MIN(REALABS(act1.inf), REALABS(act1.sup))) &&
3922  SCIPfeastol(scip) * MAX(REALABS(act1.inf), REALABS(act1.sup)) / MIN(REALABS(act1.inf), REALABS(act1.sup)) >= conshdlrdata->binreformmaxcoef )
3923  {
3924  SCIPdebugMsg(scip, "skip reform of %g<%s><%s> due to huge activity ratio %g for <%s> = 0.0\n", bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar),
3925  MAX(REALABS(act1.inf), REALABS(act1.sup)) / MIN(REALABS(act1.inf), REALABS(act1.sup)), SCIPvarGetName(y));
3926  continue;
3927  }
3928 
3929  /* add bvar to x term */
3930  xvars[nxvars] = bvar;
3931  xcoef[nxvars] = bilincoef;
3932  ++nxvars;
3933 
3934  /* update bounds on x term */
3935  SCIPintervalAdd(SCIPinfinity(scip), &xbndszero, xbndszero, act0);
3936  SCIPintervalAdd(SCIPinfinity(scip), &xbndsone, xbndsone, act1);
3937 
3938  if( REALABS(bilincoef) < mincoef )
3939  mincoef = ABS(bilincoef);
3940  if( REALABS(bilincoef) > maxcoef )
3941  maxcoef = ABS(bilincoef);
3942 
3943  /* update whether all coefficients will be integral and if so, compute their gcd */
3944  integral &= (SCIPvarGetType(bvar) < SCIP_VARTYPE_CONTINUOUS) && SCIPisIntegral(scip, bilincoef); /*lint !e514 */
3945  if( integral )
3946  {
3947  if( nxvars == 1 )
3948  gcd = (SCIP_Longint)SCIPround(scip, REALABS(bilincoef));
3949  else
3950  gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)SCIPround(scip, REALABS(bilincoef)));
3951  }
3952 
3953  /* if bvar is initial, then also the auxiliary variable should be initial
3954  * if bvar is not removable, then also the auxiliary variable should not be removable
3955  */
3956  auxvarinitial |= SCIPvarIsInitial(bvar);
3957  auxvarremovable &= SCIPvarIsRemovable(bvar);
3958 
3959  /* remember that we have to remove this bilinear term later */
3960  assert(ntodelete < nbilinterms);
3961  todelete[ntodelete++] = bilinidx;
3962  }
3963 
3964  if( nxvars == 0 ) /* all (remaining) x_j seem to be unbounded */
3965  break;
3966 
3967  assert(!SCIPisInfinity(scip, -SCIPintervalGetInf(xbndszero)));
3968  assert(!SCIPisInfinity(scip, SCIPintervalGetSup(xbndszero)));
3969  assert(!SCIPisInfinity(scip, -SCIPintervalGetInf(xbndsone)));
3970  assert(!SCIPisInfinity(scip, SCIPintervalGetSup(xbndsone)));
3971 
3972 #ifdef SCIP_DEBUG
3973  if( SCIPintervalGetInf(xbndszero) != SCIPintervalGetInf(xbndsone) || /*lint !e777*/
3974  +SCIPintervalGetSup(xbndszero) != SCIPintervalGetSup(xbndsone) ) /*lint !e777*/
3975  {
3976  SCIPdebugMsg(scip, "got different bounds for y = 0: [%g, %g] and y = 1: [%g, %g]\n", xbndszero.inf, xbndszero.sup, xbndsone.inf, xbndsone.sup);
3977  }
3978 #endif
3979 
3980  if( nxvars == 1 && conshdlrdata->empathy4and >= 1 && SCIPvarIsBinary(xvars[0]) )
3981  {
3982  /* product of two binary variables, replace by auxvar and AND constraint */
3983  /* add auxiliary variable z */
3984  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3985  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT,
3986  auxvarinitial, auxvarremovable, NULL, NULL, NULL, NULL, NULL) );
3987  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3988 
3989 #ifdef WITH_DEBUG_SOLUTION
3990  if( SCIPdebugIsMainscip(scip) )
3991  {
3992  SCIP_Real var0val;
3993  SCIP_Real var1val;
3994  SCIP_CALL( SCIPdebugGetSolVal(scip, xvars[0], &var0val) );
3995  SCIP_CALL( SCIPdebugGetSolVal(scip, y, &var1val) );
3996  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, var0val * var1val) );
3997  }
3998 #endif
3999 
4000  /* add constraint z = x and y; need to be enforced, as it is not redundant w.r.t. existing constraints */
4001  xvars[1] = y;
4002  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%sAND%s_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4003  SCIP_CALL( SCIPcreateConsAnd(scip, &auxcons, name, auxvar, 2, xvars,
4004  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
4005  SCIPconsIsSeparated(cons), TRUE, TRUE,
4008  SCIP_CALL( SCIPaddCons(scip, auxcons) );
4009  SCIPdebugMsg(scip, "added AND constraint: ");
4010  SCIPdebugPrintCons(scip, auxcons, NULL);
4011  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
4012  ++*naddconss;
4013 
4014  /* add linear term coef*auxvar */
4015  SCIP_CALL( addLinearCoef(scip, cons, auxvar, xcoef[0]) );
4016 
4017  /* forget about auxvar */
4018  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
4019  }
4020  else
4021  {
4022  /* product of binary variable with more than one binary or with continuous variables or with binary and user
4023  * did not like AND -> replace by auxvar and linear constraints */
4024  SCIP_Real scale;
4025 
4026  /* scale auxiliary constraint by some nice value,
4027  * if all coefficients are integral, take a value that preserves integrality (-> gcd), so we can make the auxiliary variable impl. integer
4028  */
4029  if( integral )
4030  {
4031  scale = (SCIP_Real)gcd;
4032  assert(scale >= 1.0);
4033  }
4034  else if( nxvars == 1 )
4035  {
4036  /* scaling by the only coefficient gives auxiliary variable = x * y, which thus will be implicit integral provided y is not continuous */
4037  assert(mincoef == maxcoef); /*lint !e777 */
4038  scale = mincoef;
4039  integral = SCIPvarGetType(xvars[0]) < SCIP_VARTYPE_CONTINUOUS;
4040  }
4041  else
4042  {
4043  scale = 1.0;
4044  if( maxcoef < 0.5 )
4045  scale = maxcoef;
4046  if( mincoef > 2.0 )
4047  scale = mincoef;
4048  if( scale != 1.0 )
4049  scale = SCIPselectSimpleValue(scale / 2.0, 1.5 * scale, MAXDNOM);
4050  }
4051  assert(scale > 0.0);
4052  assert(!SCIPisInfinity(scip, scale));
4053 
4054  /* if x-term is always negative for y = 1, negate scale so we get a positive auxiliary variable; maybe this is better sometimes? */
4055  if( !SCIPisPositive(scip, SCIPintervalGetSup(xbndsone)) )
4056  scale = -scale;
4057 
4058  SCIPdebugMsg(scip, "binary reformulation using scale %g, nxvars = %d, integral = %u\n", scale, nxvars, integral);
4059  if( scale != 1.0 )
4060  {
4061  SCIPintervalDivScalar(SCIPinfinity(scip), &xbndszero, xbndszero, scale);
4062  SCIPintervalDivScalar(SCIPinfinity(scip), &xbndsone, xbndsone, scale);
4063  for( k = 0; k < nxvars; ++k )
4064  xcoef[k] /= scale;
4065  }
4066 
4067  /* add auxiliary variable z */
4068  if( nxvars == 1 )
4069  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4070  else
4071  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_more_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4072  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, MIN(0., SCIPintervalGetInf(xbndsone)), MAX(0., SCIPintervalGetSup(xbndsone)),
4074  auxvarinitial, auxvarremovable, NULL, NULL, NULL, NULL, NULL) );
4075  SCIP_CALL( SCIPaddVar(scip, auxvar) );
4076 
4077  /* compute value of auxvar in debug solution */
4078 #ifdef WITH_DEBUG_SOLUTION
4079  if( SCIPdebugIsMainscip(scip) )
4080  {
4081  SCIP_Real debugval;
4082  SCIP_Real varval;
4083 
4084  SCIP_CALL( SCIPdebugGetSolVal(scip, y, &varval) );
4085  if( SCIPisZero(scip, varval) )
4086  {
4087  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, 0.0) );
4088  }
4089  else
4090  {
4091  assert(SCIPisEQ(scip, varval, 1.0));
4092 
4093  debugval = 0.0;
4094  for( k = 0; k < nxvars; ++k )
4095  {
4096  SCIP_CALL( SCIPdebugGetSolVal(scip, xvars[k], &varval) );
4097  debugval += xcoef[k] * varval;
4098  }
4099  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, debugval) );
4100  }
4101  }
4102 #endif
4103 
4104  /* add auxiliary constraints
4105  * it seems to be advantageous to make the varbound constraints initial and the linear constraints not initial
4106  * maybe because it is more likely that a binary variable takes value 0 instead of 1, and thus the varbound constraints
4107  * are more often active, compared to the linear constraints added below
4108  * also, the varbound constraints are more sparse than the linear cons
4109  */
4110  if( SCIPisNegative(scip, SCIPintervalGetInf(xbndsone)) )
4111  {
4112  /* add 0 <= z - xbndsone.inf * y constraint (as varbound constraint), need to be enforced as not redundant */
4113  if( nxvars == 1 )
4114  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_1", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4115  else
4116  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_1", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4117  SCIP_CALL( SCIPcreateConsVarbound(scip, &auxcons, name, auxvar, y, -SCIPintervalGetInf(xbndsone), 0.0, SCIPinfinity(scip),
4118  SCIPconsIsInitial(cons) /*&& conshdlrdata->binreforminitial*/,
4119  SCIPconsIsSeparated(cons), TRUE, TRUE,
4122  SCIP_CALL( SCIPaddCons(scip, auxcons) );
4123  SCIPdebugMsg(scip, "added varbound constraint: ");
4124  SCIPdebugPrintCons(scip, auxcons, NULL);
4125  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
4126  ++*naddconss;
4127  }
4128  if( SCIPisPositive(scip, SCIPintervalGetSup(xbndsone)) )
4129  {
4130  /* add z - xbndsone.sup * y <= 0 constraint (as varbound constraint), need to be enforced as not redundant */
4131  if( nxvars == 1 )
4132  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_2", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4133  else
4134  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_2", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4135  SCIP_CALL( SCIPcreateConsVarbound(scip, &auxcons, name, auxvar, y, -SCIPintervalGetSup(xbndsone), -SCIPinfinity(scip), 0.0,
4136  SCIPconsIsInitial(cons) /*&& conshdlrdata->binreforminitial*/,
4137  SCIPconsIsSeparated(cons), TRUE, TRUE,
4140  SCIP_CALL( SCIPaddCons(scip, auxcons) );
4141  SCIPdebugMsg(scip, "added varbound constraint: ");
4142  SCIPdebugPrintCons(scip, auxcons, NULL);
4143  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
4144  ++*naddconss;
4145  }
4146 
4147  /* add xbndszero.inf <= sum_i a_i*x_i + xbndszero.inf * y - z constraint, need to be enforced as not redundant */
4148  xvars[nxvars] = y;
4149  xvars[nxvars+1] = auxvar;
4150  xcoef[nxvars] = SCIPintervalGetInf(xbndszero);
4151  xcoef[nxvars+1] = -1;
4152 
4153  if( nxvars == 1 )
4154  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_3", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4155  else
4156  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_3", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4157  SCIP_CALL( SCIPcreateConsLinear(scip, &auxcons, name, nxvars+2, xvars, xcoef, SCIPintervalGetInf(xbndszero), SCIPinfinity(scip),
4158  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
4159  SCIPconsIsSeparated(cons), TRUE, TRUE,
4162  SCIP_CALL( SCIPaddCons(scip, auxcons) );
4163  SCIPdebugMsg(scip, "added linear constraint: ");
4164  SCIPdebugPrintCons(scip, auxcons, NULL);
4165  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
4166  ++*naddconss;
4167 
4168  /* add sum_i a_i*x_i + xbndszero.sup * y - z <= xbndszero.sup constraint, need to be enforced as not redundant */
4169  xcoef[nxvars] = SCIPintervalGetSup(xbndszero);
4170 
4171  if( nxvars == 1 )
4172  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_4", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4173  else
4174  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_4", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4175  SCIP_CALL( SCIPcreateConsLinear(scip, &auxcons, name, nxvars+2, xvars, xcoef, -SCIPinfinity(scip), SCIPintervalGetSup(xbndszero),
4176  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
4177  SCIPconsIsSeparated(cons), TRUE, TRUE,
4180  SCIP_CALL( SCIPaddCons(scip, auxcons) );
4181  SCIPdebugMsg(scip, "added linear constraint: ");
4182  SCIPdebugPrintCons(scip, auxcons, NULL);
4183  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
4184  ++*naddconss;
4185 
4186  /* add linear term scale*auxvar to this constraint */
4187  SCIP_CALL( addLinearCoef(scip, cons, auxvar, scale) );
4188 
4189  /* forget about auxvar */
4190  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
4191  }
4192  }
4193  while( j < nbilinterms );
4194 
4195  /* remove bilinear terms that have been replaced */
4196  SCIP_CALL( removeBilinearTermsPos(scip, cons, ntodelete, todelete) );
4197  }
4198  SCIPdebugMsg(scip, "resulting quadratic constraint: ");
4199  SCIPdebugPrintCons(scip, cons, NULL);
4200 
4201  SCIPfreeBufferArrayNull(scip, &todelete);
4202  SCIPfreeBufferArrayNull(scip, &xcoef);
4203  SCIPfreeBufferArrayNull(scip, &xvars);
4204 
4205  return SCIP_OKAY;
4206 }
4207 
4208 /** tries to automatically convert a quadratic constraint (or a part of it) into a more specific and more specialized constraint */
4209 static
4211  SCIP* scip, /**< SCIP data structure */
4212  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
4213  SCIP_CONS* cons, /**< source constraint to try to convert */
4214  SCIP_Bool* upgraded, /**< buffer to store whether constraint was upgraded */
4215  int* nupgdconss, /**< buffer to increase if constraint was upgraded */
4216  int* naddconss, /**< buffer to increase with number of additional constraints created during upgrade */
4217  SCIP_PRESOLTIMING presoltiming /**< current presolving timing */
4218  )
4219 {
4220  SCIP_CONSHDLRDATA* conshdlrdata;
4221  SCIP_CONSDATA* consdata;
4222  SCIP_VAR* var;
4223  SCIP_Real lincoef;
4224  SCIP_Real quadcoef;
4225  SCIP_Real lb;
4226  SCIP_Real ub;
4227  int nbinlin;
4228  int nbinquad;
4229  int nintlin;
4230  int nintquad;
4231  int nimpllin;
4232  int nimplquad;
4233  int ncontlin;
4234  int ncontquad;
4235  SCIP_Bool integral;
4236  int i;
4237  int j;
4238  SCIP_CONS** upgdconss;
4239  int upgdconsssize;
4240  int nupgdconss_;
4241 
4242  assert(scip != NULL);
4243  assert(conshdlr != NULL);
4244  assert(cons != NULL);
4245  assert(!SCIPconsIsModifiable(cons));
4246  assert(upgraded != NULL);
4247  assert(nupgdconss != NULL);
4248  assert(naddconss != NULL);
4249 
4250  *upgraded = FALSE;
4251 
4252  nupgdconss_ = 0;
4253 
4254  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4255  assert(conshdlrdata != NULL);
4256 
4257  /* if there are no upgrade methods, we can also stop */
4258  if( conshdlrdata->nquadconsupgrades == 0 )
4259  return SCIP_OKAY;
4260 
4261  upgdconsssize = 2;
4262  SCIP_CALL( SCIPallocBufferArray(scip, &upgdconss, upgdconsssize) );
4263 
4264  consdata = SCIPconsGetData(cons);
4265  assert(consdata != NULL);
4266 
4267  /* calculate some statistics on quadratic constraint */
4268  nbinlin = 0;
4269  nbinquad = 0;
4270  nintlin = 0;
4271  nintquad = 0;
4272  nimpllin = 0;
4273  nimplquad = 0;
4274  ncontlin = 0;
4275  ncontquad = 0;
4276  integral = TRUE;
4277  for( i = 0; i < consdata->nlinvars; ++i )
4278  {
4279  var = consdata->linvars[i];
4280  lincoef = consdata->lincoefs[i];
4281  lb = SCIPvarGetLbLocal(var);
4282  ub = SCIPvarGetUbLocal(var);
4283  assert(!SCIPisZero(scip, lincoef));
4284 
4285  switch( SCIPvarGetType(var) )
4286  {
4287  case SCIP_VARTYPE_BINARY:
4288  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4289  integral = integral && SCIPisIntegral(scip, lincoef);
4290  nbinlin++;
4291  break;
4292  case SCIP_VARTYPE_INTEGER:
4293  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4294  integral = integral && SCIPisIntegral(scip, lincoef);
4295  nintlin++;
4296  break;
4297  case SCIP_VARTYPE_IMPLINT:
4298  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4299  integral = integral && SCIPisIntegral(scip, lincoef);
4300  nimpllin++;
4301  break;
4303  integral = integral && SCIPisRelEQ(scip, lb, ub) && SCIPisIntegral(scip, lincoef * lb);
4304  ncontlin++;
4305  break;
4306  default:
4307  SCIPerrorMessage("unknown variable type\n");
4308  return SCIP_INVALIDDATA;
4309  }
4310  }
4311 
4312  for( i = 0; i < consdata->nquadvars; ++i )
4313  {
4314  var = consdata->quadvarterms[i].var;
4315  lincoef = consdata->quadvarterms[i].lincoef;
4316  quadcoef = consdata->quadvarterms[i].sqrcoef;
4317  lb = SCIPvarGetLbLocal(var);
4318  ub = SCIPvarGetUbLocal(var);
4319 
4320  switch( SCIPvarGetType(var) )
4321  {
4322  case SCIP_VARTYPE_BINARY:
4323  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4324  integral = integral && SCIPisIntegral(scip, lincoef) && SCIPisIntegral(scip, quadcoef);
4325  nbinquad++;
4326  break;
4327  case SCIP_VARTYPE_INTEGER:
4328  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4329  integral = integral && SCIPisIntegral(scip, lincoef) && SCIPisIntegral(scip, quadcoef);
4330  nintquad++;
4331  break;
4332  case SCIP_VARTYPE_IMPLINT:
4333  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4334  integral = integral && SCIPisIntegral(scip, lincoef) && SCIPisIntegral(scip, quadcoef);
4335  nimplquad++;
4336  break;
4338  integral = integral && SCIPisRelEQ(scip, lb, ub) && SCIPisIntegral(scip, lincoef * lb + quadcoef * lb * lb);
4339  ncontquad++;
4340  break;
4341  default:
4342  SCIPerrorMessage("unknown variable type\n");
4343  return SCIP_INVALIDDATA;
4344  }
4345  }
4346 
4347  if( integral )
4348  {
4349  for( i = 0; i < consdata->nbilinterms && integral; ++i )
4350  {
4351  if( SCIPvarGetType(consdata->bilinterms[i].var1) < SCIP_VARTYPE_CONTINUOUS && SCIPvarGetType(consdata->bilinterms[i].var2) < SCIP_VARTYPE_CONTINUOUS )
4352  integral = integral && SCIPisIntegral(scip, consdata->bilinterms[i].coef);
4353  else
4354  integral = FALSE;
4355  }
4356  }
4357 
4358  /* call the upgrading methods */
4359 
4360  SCIPdebugMsg(scip, "upgrading quadratic constraint <%s> (%d upgrade methods):\n",
4361  SCIPconsGetName(cons), conshdlrdata->nquadconsupgrades);
4362  SCIPdebugMsg(scip, " binlin=%d binquad=%d intlin=%d intquad=%d impllin=%d implquad=%d contlin=%d contquad=%d integral=%u\n",
4363  nbinlin, nbinquad, nintlin, nintquad, nimpllin, nimplquad, ncontlin, ncontquad, integral);
4364  SCIPdebugPrintCons(scip, cons, NULL);
4365 
4366  /* try all upgrading methods in priority order in case the upgrading step is enable */
4367  for( i = 0; i < conshdlrdata->nquadconsupgrades; ++i )
4368  {
4369  if( !conshdlrdata->quadconsupgrades[i]->active )
4370  continue;
4371 
4372  SCIP_CALL( conshdlrdata->quadconsupgrades[i]->quadconsupgd(scip, cons,
4373  nbinlin, nbinquad, nintlin, nintquad, nimpllin, nimplquad, ncontlin, ncontquad, integral,
4374  &nupgdconss_, upgdconss, upgdconsssize, presoltiming) );
4375 
4376  while( nupgdconss_ < 0 )
4377  {
4378  /* upgrade function requires more memory: resize upgdconss and call again */
4379  assert(-nupgdconss_ > upgdconsssize);
4380  upgdconsssize = -nupgdconss_;
4381  SCIP_CALL( SCIPreallocBufferArray(scip, &upgdconss, -nupgdconss_) );
4382 
4383  SCIP_CALL( conshdlrdata->quadconsupgrades[i]->quadconsupgd(scip, cons,
4384  nbinlin, nbinquad, nintlin, nintquad, nimpllin, nimplquad, ncontlin, ncontquad, integral,
4385  &nupgdconss_, upgdconss, upgdconsssize, presoltiming) );
4386 
4387  assert(nupgdconss_ != 0);
4388  }
4389 
4390  if( nupgdconss_ > 0 )
4391  {
4392  /* got upgrade */
4393  SCIPdebugPrintCons(scip, cons, NULL);
4394  SCIPdebugMsg(scip, " -> upgraded to %d constraints:\n", nupgdconss_);
4395 
4396  /* add the upgraded constraints to the problem and forget them */
4397  for( j = 0; j < nupgdconss_; ++j )
4398  {
4399  SCIPdebugMsgPrint(scip, "\t");
4400  SCIPdebugPrintCons(scip, upgdconss[j], NULL);
4401 
4402  SCIP_CALL( SCIPaddCons(scip, upgdconss[j]) ); /*lint !e613*/
4403  SCIP_CALL( SCIPreleaseCons(scip, &upgdconss[j]) ); /*lint !e613*/
4404  }
4405 
4406  /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
4407  *nupgdconss += 1;
4408  *naddconss += nupgdconss_ - 1;
4409  *upgraded = TRUE;
4410 
4411  /* delete upgraded constraint */
4412  SCIPdebugMsg(scip, "delete constraint <%s> after upgrade\n", SCIPconsGetName(cons));
4413  SCIP_CALL( SCIPdelCons(scip, cons) );
4414 
4415  break;
4416  }
4417  }
4418 
4419  SCIPfreeBufferArray(scip, &upgdconss);
4420 
4421  return SCIP_OKAY;
4422 }
4423 
4424 /** helper function for presolveDisaggregate */
4425 static
4427  SCIP* scip, /**< SCIP data structure */
4428  SCIP_CONSDATA* consdata, /**< constraint data */
4429  int quadvaridx, /**< index of quadratic variable to mark */
4430  SCIP_HASHMAP* var2component, /**< variables to components mapping */
4431  int componentnr, /**< the component number to mark to */
4432  int* componentsize /**< buffer to store size of component (incremented by 1) */
4433  )
4434 {
4435  SCIP_QUADVARTERM* quadvarterm;
4436  SCIP_VAR* othervar;
4437  int othervaridx;
4438  int i;
4439 
4440  assert(consdata != NULL);
4441  assert(quadvaridx >= 0);
4442  assert(quadvaridx < consdata->nquadvars);
4443  assert(var2component != NULL);
4444  assert(componentnr >= 0);
4445 
4446  quadvarterm = &consdata->quadvarterms[quadvaridx];
4447 
4448  if( SCIPhashmapExists(var2component, quadvarterm->var) )
4449  {
4450  /* if we saw the variable before, then it should have the same component number */
4451  assert(SCIPhashmapGetImageInt(var2component, quadvarterm->var) == componentnr);
4452  return SCIP_OKAY;
4453  }
4454 
4455  /* assign component number to variable */
4456  SCIP_CALL( SCIPhashmapInsertInt(var2component, quadvarterm->var, componentnr) );
4457  ++*componentsize;
4458 
4459  /* assign same component number to all variables this variable is multiplied with */
4460  for( i = 0; i < quadvarterm->nadjbilin; ++i )
4461  {
4462  othervar = consdata->bilinterms[quadvarterm->adjbilin[i]].var1 == quadvarterm->var ?
4463  consdata->bilinterms[quadvarterm->adjbilin[i]].var2 : consdata->bilinterms[quadvarterm->adjbilin[i]].var1;
4464  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, othervar, &othervaridx) );
4465  assert(othervaridx >= 0);
4466  SCIP_CALL( presolveDisaggregateMarkComponent(scip, consdata, othervaridx, var2component, componentnr, componentsize) );
4467  }
4468 
4469  return SCIP_OKAY;
4470 }
4471 
4472 /** merges components in variables connectivity graph */
4473 static
4475  SCIP* scip, /**< SCIP data structure */
4476  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
4477  SCIP_HASHMAP* var2component, /**< variables to component mapping */
4478  int nvars, /**< number of variables */
4479  int* ncomponents, /**< number of components */
4480  int* componentssize /**< size of components */
4481  )
4482 {
4483  SCIP_CONSHDLRDATA* conshdlrdata;
4484  SCIP_HASHMAPENTRY* entry;
4485  int maxncomponents;
4486  int* oldcompidx;
4487  int* newcompidx;
4488  int i;
4489  int oldcomponent;
4490  int newcomponent;
4491 
4492  assert(scip != NULL);
4493  assert(conshdlr != NULL);
4494  assert(var2component != NULL);
4495  assert(ncomponents != NULL);
4496  assert(componentssize != NULL);
4497 
4498  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4499  assert(conshdlrdata != NULL);
4500 
4501  maxncomponents = conshdlrdata->maxdisaggrsize;
4502  assert(maxncomponents > 0);
4503 
4504  /* if already not too many components, then nothing to do */
4505  if( *ncomponents <= maxncomponents )
4506  return SCIP_OKAY;
4507 
4508  /*
4509  printf("component sizes before:");
4510  for( i = 0; i < *ncomponents; ++i )
4511  printf(" %d", componentssize[i]);
4512  printf("\n");
4513  */
4514 
4515  SCIP_CALL( SCIPallocBufferArray(scip, &oldcompidx, *ncomponents) );
4516  SCIP_CALL( SCIPallocBufferArray(scip, &newcompidx, *ncomponents) );
4517 
4518  for( i = 0; i < *ncomponents; ++i )
4519  oldcompidx[i] = i;
4520 
4521  switch( conshdlrdata->disaggrmergemethod )
4522  {
4523  case 's' :
4524  /* sort components by size, increasing order */
4525  SCIPsortIntInt(componentssize, oldcompidx, *ncomponents);
4526  break;
4527  case 'b' :
4528  case 'm' :
4529  /* sort components by size, decreasing order */
4530  SCIPsortDownIntInt(componentssize, oldcompidx, *ncomponents);
4531  break;
4532  default :
4533  SCIPerrorMessage("invalid value for constraints/quadratic/disaggrmergemethod parameter");
4534  return SCIP_PARAMETERWRONGVAL;
4535  }
4536 
4537  SCIPdebugMsg(scip, "%-30s: % 4d components of size % 4d to % 4d, median: % 4d\n", SCIPgetProbName(scip), *ncomponents, componentssize[0], componentssize[*ncomponents-1], componentssize[*ncomponents/2]);
4538 
4539  if( conshdlrdata->disaggrmergemethod == 'm' )
4540  {
4541  SCIP_Real targetsize;
4542  int count = 0;
4543 
4544  /* a minimal component size we should reach to have all components roughly the same size */
4545  targetsize = nvars / maxncomponents; /*lint !e653*/
4546  for( i = 0; i < *ncomponents; ++i )
4547  {
4548  newcompidx[oldcompidx[i]] = i;
4549  count += componentssize[i];
4550 
4551  /* fill with small components until we reach targetsize
4552  * Since targetsize might be fractional, we also add another component if
4553  * the number of variables remaining (=nvars-count) is larger than
4554  * what we expect to put into the remaining components (=targetsize * (maxncomponents - i-1)).
4555  * Thus, from time to time, a component is made larger than the targetsize to avoid
4556  * having to add much into the last component.
4557  */
4558  while( i < *ncomponents-1 && (componentssize[i] + componentssize[*ncomponents-1] <= targetsize ||
4559  nvars - count > targetsize * (maxncomponents - i)) )
4560  {
4561  /* map last (=smallest) component to component i */
4562  newcompidx[oldcompidx[*ncomponents-1]] = i;
4563 
4564  /* increase size of component i accordingly */
4565  componentssize[i] += componentssize[*ncomponents-1];
4566  count += componentssize[*ncomponents-1];
4567 
4568  /* forget about last component */
4569  --*ncomponents;
4570  }
4571  }
4572  assert(count == nvars);
4573  }
4574  else
4575  {
4576  /* get inverse permutation */
4577  for( i = 0; i < *ncomponents; ++i )
4578  newcompidx[oldcompidx[i]] = i;
4579  }
4580 
4581  /* assign new component numbers to variables, cutting off at maxncomponents */
4582  for( i = 0; i < SCIPhashmapGetNEntries(var2component); ++i )
4583  {
4584  entry = SCIPhashmapGetEntry(var2component, i);
4585  if( entry == NULL )
4586  continue;
4587 
4588  oldcomponent = (int)(size_t)SCIPhashmapEntryGetImage(entry);
4589 
4590  newcomponent = newcompidx[oldcomponent];
4591  if( newcomponent >= maxncomponents )
4592  {
4593  newcomponent = maxncomponents-1;
4594  ++componentssize[maxncomponents-1];
4595  }
4596 
4597  SCIPhashmapEntrySetImage(entry, (void*)(size_t)newcomponent); /*lint !e571*/
4598  }
4599  if( *ncomponents > maxncomponents )
4600  *ncomponents = maxncomponents;
4601 
4602  /*
4603  printf("component sizes after :");
4604  for( i = 0; i < *ncomponents; ++i )
4605  printf(" %d", componentssize[i]);
4606  printf("\n");
4607  */
4608 
4609  SCIPfreeBufferArray(scip, &newcompidx);
4610  SCIPfreeBufferArray(scip, &oldcompidx);
4611 
4612  return SCIP_OKAY;
4613 }
4614 
4615 /** compute the next highest power of 2 for a 32-bit argument
4616  *
4617  * Source: https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
4618  *
4619  * @note Returns 0 for v=0.
4620  */
4621 static
4622 unsigned int nextPowerOf2(
4623  unsigned int v /**< input */
4624  )
4625 {
4626  v--;
4627  v |= v >> 1;
4628  v |= v >> 2;
4629  v |= v >> 4;
4630  v |= v >> 8;
4631  v |= v >> 16;
4632  v++;
4633 
4634  return v;
4635 }
4636 
4637 
4638 /** for quadratic constraints that consists of a sum of quadratic terms, disaggregates the sum into a set of constraints by introducing auxiliary variables
4639  *
4640  * Assume the quadratic constraint can be written in the form
4641  * lhs <= b'x + sum_{k=1..p} q_k(x_k) <= rhs
4642  * where x_k denotes a subset of the variables in x and these subsets are pairwise disjunct
4643  * and q_k(.) is a quadratic form.
4644  * p is selected as large as possible, but to be <= conshdlrdata->maxdisaggrsize.
4645  *
4646  * Without additional scaling, the constraint is disaggregated into
4647  * lhs <= b'x + sum_k c_k z_k <= rhs
4648  * c_k z_k ~ q_k(x)
4649  * where "~" is either "<=", "==", or ">=", depending on whether lhs or rhs are infinite.
4650  * Further, c_k is chosen to be the maximal absolute value of the coefficients of the quadratic terms in q_k(x).
4651  * This is done to ensure that z_k takes values with a similar magnitute as the variables in x_k (better for separation).
4652  *
4653  * However, a solution of this disaggregated system can violate the original constraint by (p+1)*epsilon
4654  * (assuming unscaled violations are used, which is the default).
4655  * Therefore, all constraints are scaled by p+1:
4656  * (p+1)*lhs <= (p+1)*b'x + (p+1) * sum_k c_k z_k <= (p+1) * rhs
4657  * (p+1)*c_k z_k ~ (p+1)*q_k(x)
4658  */
4659 static
4661  SCIP* scip, /**< SCIP data structure */
4662  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
4663  SCIP_CONS* cons, /**< source constraint to try to convert */
4664  int* naddconss /**< pointer to counter of added constraints */
4665  )
4666 {
4667  SCIP_CONSDATA* consdata;
4668  SCIP_HASHMAP* var2component;
4669  int* componentssize;
4670  int ncomponents;
4671  int i;
4672  int comp;
4673  SCIP_CONS** auxconss;
4674  SCIP_VAR** auxvars;
4675  SCIP_Real* auxcoefs;
4676 #ifdef WITH_DEBUG_SOLUTION
4677  SCIP_Real* auxsolvals; /* value of auxiliary variable in debug solution */
4678 #endif
4679  SCIP_Real scale;
4680  char name[SCIP_MAXSTRLEN];
4681 
4682  assert(scip != NULL);
4683  assert(conshdlr != NULL);
4684  assert(cons != NULL);
4685  assert(naddconss != NULL);
4686 
4687  consdata = SCIPconsGetData(cons);
4688  assert(consdata != NULL);
4689 
4690  /* skip if constraint has been already disaggregated */
4691  if( consdata->isdisaggregated )
4692  return SCIP_OKAY;
4693 
4694  consdata->isdisaggregated = TRUE;
4695 
4696  /* make sure there are no quadratic variables without coefficients */
4697  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
4698  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, cons) );
4699 
4700  if( consdata->nquadvars <= 1 )
4701  return SCIP_OKAY;
4702 
4703  /* sort quadratic variable terms here, so we can later search in it without reordering the array */
4704  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
4705 
4706  /* check how many quadratic terms with non-overlapping variables we have
4707  * in other words, the number of components in the sparsity graph of the quadratic term matrix
4708  */
4709  ncomponents = 0;
4710  SCIP_CALL( SCIPhashmapCreate(&var2component, SCIPblkmem(scip), consdata->nquadvars) );
4711  SCIP_CALL( SCIPallocBufferArray(scip, &componentssize, consdata->nquadvars) );
4712  for( i = 0; i < consdata->nquadvars; ++i )
4713  {
4714  /* if variable was marked already, skip it */
4715  if( SCIPhashmapExists(var2component, (void*)consdata->quadvarterms[i].var) )
4716  continue;
4717 
4718  /* start a new component with variable i */
4719  componentssize[ncomponents] = 0;
4720  SCIP_CALL( presolveDisaggregateMarkComponent(scip, consdata, i, var2component, ncomponents, componentssize + ncomponents) );
4721  ++ncomponents;
4722  }
4723 
4724  assert(ncomponents >= 1);
4725 
4726  /* if there is only one component, we cannot disaggregate
4727  * @todo we could still split the constraint into several while keeping the number of variables sharing several constraints as small as possible
4728  */
4729  if( ncomponents == 1 )
4730  {
4731  SCIPhashmapFree(&var2component);
4732  SCIPfreeBufferArray(scip, &componentssize);
4733  return SCIP_OKAY;
4734  }
4735 
4736  /* merge some components, if necessary */
4737  SCIP_CALL( presolveDisaggregateMergeComponents(scip, conshdlr, var2component, consdata->nquadvars, &ncomponents, componentssize) );
4738 
4739  SCIPfreeBufferArray(scip, &componentssize);
4740 
4741  /* scale all new constraints (ncomponents+1 many) by ncomponents+1 (or its next power of 2), so violations sum up to at most epsilon */
4742  scale = nextPowerOf2((unsigned int)ncomponents + 1);
4743 
4744  SCIP_CALL( SCIPallocBufferArray(scip, &auxconss, ncomponents) );
4745  SCIP_CALL( SCIPallocBufferArray(scip, &auxvars, ncomponents) );
4746  SCIP_CALL( SCIPallocBufferArray(scip, &auxcoefs, ncomponents) );
4747 #ifdef WITH_DEBUG_SOLUTION
4748  SCIP_CALL( SCIPallocClearBufferArray(scip, &auxsolvals, ncomponents) );
4749 #endif
4750 
4751  /* create auxiliary variables and empty constraints for each component */
4752  for( comp = 0; comp < ncomponents; ++comp )
4753  {
4754  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_comp%d", SCIPconsGetName(cons), comp);
4755 
4756  SCIP_CALL( SCIPcreateVar(scip, &auxvars[comp], name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
4758 
4759  SCIP_CALL( SCIPcreateConsQuadratic2(scip, &auxconss[comp], name, 0, NULL, NULL, 0, NULL, 0, NULL,
4760  (SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : 0.0),
4761  (SCIPisInfinity(scip, consdata->rhs) ? SCIPinfinity(scip) : 0.0),
4764  SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons)) );
4765 
4766  auxcoefs[comp] = SCIPinfinity(scip);
4767  }
4768 
4769  /* add quadratic variables to each component constraint
4770  * delete adjacency information */
4771  for( i = 0; i < consdata->nquadvars; ++i )
4772  {
4773  assert(SCIPhashmapExists(var2component, consdata->quadvarterms[i].var));
4774 
4775  comp = SCIPhashmapGetImageInt(var2component, consdata->quadvarterms[i].var);
4776  assert(comp >= 0);
4777  assert(comp < ncomponents);
4778 
4779  /* add variable term to corresponding constraint */
4780  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, auxconss[comp], consdata->quadvarterms[i].var, scale * consdata->quadvarterms[i].lincoef, scale * consdata->quadvarterms[i].sqrcoef) );
4781 
4782  /* reduce coefficient of aux variable */
4783  if( !SCIPisZero(scip, consdata->quadvarterms[i].lincoef) && ABS(consdata->quadvarterms[i].lincoef) < auxcoefs[comp] )
4784  auxcoefs[comp] = REALABS(consdata->quadvarterms[i].lincoef);
4785  if( !SCIPisZero(scip, consdata->quadvarterms[i].sqrcoef) && ABS(consdata->quadvarterms[i].sqrcoef) < auxcoefs[comp] )
4786  auxcoefs[comp] = REALABS(consdata->quadvarterms[i].sqrcoef);
4787 
4788  SCIPfreeBlockMemoryArray(scip, &consdata->quadvarterms[i].adjbilin, consdata->quadvarterms[i].adjbilinsize);
4789  consdata->quadvarterms[i].nadjbilin = 0;
4790  consdata->quadvarterms[i].adjbilinsize = 0;
4791 
4792 #ifdef WITH_DEBUG_SOLUTION
4793  if( SCIPdebugIsMainscip(scip) )
4794  {
4795  SCIP_Real debugvarval;
4796 
4797  SCIP_CALL( SCIPdebugGetSolVal(scip, consdata->quadvarterms[i].var, &debugvarval) );
4798  auxsolvals[comp] += consdata->quadvarterms[i].lincoef * debugvarval + consdata->quadvarterms[i].sqrcoef * debugvarval * debugvarval;
4799  }
4800 #endif
4801  }
4802 
4803  /* add bilinear terms to each component constraint */
4804  for( i = 0; i < consdata->nbilinterms; ++i )
4805  {
4806  assert(SCIPhashmapExists(var2component, consdata->bilinterms[i].var1));
4807  assert(SCIPhashmapExists(var2component, consdata->bilinterms[i].var2));
4808 
4809  comp = SCIPhashmapGetImageInt(var2component, consdata->bilinterms[i].var1);
4810  assert(comp == SCIPhashmapGetImageInt(var2component, consdata->bilinterms[i].var2));
4811  assert(!SCIPisZero(scip, consdata->bilinterms[i].coef));
4812 
4813  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, auxconss[comp],
4814  consdata->bilinterms[i].var1, consdata->bilinterms[i].var2, scale * consdata->bilinterms[i].coef) );
4815 
4816  if( ABS(consdata->bilinterms[i].coef) < auxcoefs[comp] )
4817  auxcoefs[comp] = ABS(consdata->bilinterms[i].coef);
4818 
4819 #ifdef WITH_DEBUG_SOLUTION
4820  if( SCIPdebugIsMainscip(scip) )
4821  {
4822  SCIP_Real debugvarval1;
4823  SCIP_Real debugvarval2;
4824 
4825  SCIP_CALL( SCIPdebugGetSolVal(scip, consdata->bilinterms[i].var1, &debugvarval1) );
4826  SCIP_CALL( SCIPdebugGetSolVal(scip, consdata->bilinterms[i].var2, &debugvarval2) );
4827  auxsolvals[comp] += consdata->bilinterms[i].coef * debugvarval1 * debugvarval2;
4828  }
4829 #endif
4830  }
4831 
4832  /* forget about bilinear terms in cons */
4833  SCIPfreeBlockMemoryArray(scip, &consdata->bilinterms, consdata->bilintermssize);
4834  consdata->nbilinterms = 0;
4835  consdata->bilintermssize = 0;
4836 
4837  /* remove quadratic variable terms from cons */
4838  for( i = consdata->nquadvars - 1; i >= 0; --i )
4839  {
4840  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
4841  }
4842  assert(consdata->nquadvars == 0);
4843 
4844  /* scale remaining linear variables and sides by scale */
4845  for( i = 0; i < consdata->nlinvars; ++i )
4846  {
4847  SCIP_CALL( chgLinearCoefPos(scip, cons, i, scale * consdata->lincoefs[i]) );
4848  }
4849  if( !SCIPisInfinity(scip, -consdata->lhs) )
4850  {
4851  consdata->lhs *= scale;
4852  assert(!SCIPisInfinity(scip, -consdata->lhs) );
4853  }
4854  if( !SCIPisInfinity(scip, consdata->rhs) )
4855  {
4856  consdata->rhs *= scale;
4857  assert(!SCIPisInfinity(scip, consdata->rhs) );
4858  }
4859 
4860  /* add auxiliary variables to auxiliary constraints
4861  * add aux vars and constraints to SCIP
4862  * add aux vars to this constraint
4863  * set value of aux vars in debug solution, if any
4864  */
4865  SCIPdebugMsg(scip, "add %d constraints for disaggregation of quadratic constraint <%s>\n", ncomponents, SCIPconsGetName(cons));
4866  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars + ncomponents) );
4867  for( comp = 0; comp < ncomponents; ++comp )
4868  {
4869  SCIP_CONSDATA* auxconsdata;
4870 
4871  SCIP_CALL( SCIPaddLinearVarQuadratic(scip, auxconss[comp], auxvars[comp], -scale * auxcoefs[comp]) );
4872 
4873  SCIP_CALL( SCIPaddVar(scip, auxvars[comp]) );
4874 
4875  SCIP_CALL( SCIPaddCons(scip, auxconss[comp]) );
4876  SCIPdebugPrintCons(scip, auxconss[comp], NULL);
4877 
4878  SCIP_CALL( addLinearCoef(scip, cons, auxvars[comp], scale * auxcoefs[comp]) );
4879 
4880  /* mark that the constraint should not further be disaggregated */
4881  auxconsdata = SCIPconsGetData(auxconss[comp]);
4882  assert(auxconsdata != NULL);
4883  auxconsdata->isdisaggregated = TRUE;
4884 
4885 #ifdef WITH_DEBUG_SOLUTION
4886  if( SCIPdebugIsMainscip(scip) )
4887  {
4888  /* auxvar should take value from auxsolvals in debug solution, but we also scaled auxvar by auxcoefs[comp] */
4889  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvars[comp], auxsolvals[comp] / auxcoefs[comp]) );
4890  }
4891 #endif
4892 
4893  SCIP_CALL( SCIPreleaseCons(scip, &auxconss[comp]) );
4894  SCIP_CALL( SCIPreleaseVar(scip, &auxvars[comp]) );
4895  }
4896  *naddconss += ncomponents;
4897 
4898  SCIPdebugPrintCons(scip, cons, NULL);
4899 
4900  SCIPfreeBufferArray(scip, &auxconss);
4901  SCIPfreeBufferArray(scip, &auxvars);
4902  SCIPfreeBufferArray(scip, &auxcoefs);
4903 #ifdef WITH_DEBUG_SOLUTION
4904  SCIPfreeBufferArray(scip, &auxsolvals);
4905 #endif
4906  SCIPhashmapFree(&var2component);
4907 
4908  return SCIP_OKAY;
4909 }
4910 
4911 #ifdef CHECKIMPLINBILINEAR
4912 /** checks if there are bilinear terms x*y with a binary variable x and an implication x = {0,1} -> y = 0
4913  *
4914  * In this case, the bilinear term can be removed (x=0 case) or replaced by y (x=1 case).
4915  */
4916 static
4917 SCIP_RETCODE presolveApplyImplications(
4918  SCIP* scip, /**< SCIP data structure */
4919  SCIP_CONS* cons, /**< quadratic constraint */
4920  int* nbilinremoved /**< buffer to store number of removed bilinear terms */
4921  )
4922 {
4923  SCIP_CONSDATA* consdata;
4924  SCIP_VAR* x;
4925  SCIP_VAR* y;
4926  SCIP_INTERVAL implbnds;
4927  int i;
4928  int j;
4929  int k;
4930 
4931  assert(scip != NULL);
4932  assert(cons != NULL);
4933  assert(nbilinremoved != NULL);
4934 
4935  *nbilinremoved = 0;
4936 
4937  consdata = SCIPconsGetData(cons);
4938  assert(consdata != NULL);
4939 
4940  SCIPdebugMsg(scip, "apply implications in <%s>\n", SCIPconsGetName(cons));
4941 
4942  /* sort quadvarterms in case we need to search */
4943  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
4944 
4945  for( i = 0; i < consdata->nquadvars; ++i )
4946  {
4947  x = consdata->quadvarterms[i].var;
4948  assert(x != NULL);
4949 
4950  if( consdata->quadvarterms[i].nadjbilin == 0 )
4951  continue;
4952 
4953  if( !SCIPvarIsBinary(x) )
4954  continue;
4955 
4956  if( !SCIPvarIsActive(x) )
4957  continue;
4958 
4959  if( SCIPvarGetNImpls(x, TRUE) == 0 && SCIPvarGetNImpls(x, FALSE) == 0 )
4960  continue;
4961 
4962  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
4963  {
4964  k = consdata->quadvarterms[i].adjbilin[j];
4965  assert(k >= 0);
4966  assert(k < consdata->nbilinterms);
4967 
4968  if( consdata->bilinterms[k].coef == 0.0 )
4969  continue;
4970 
4971  y = consdata->bilinterms[k].var1 == x ? consdata->bilinterms[k].var2 : consdata->bilinterms[k].var1;
4972  assert(x != y);
4973 
4974  SCIP_CALL( getImpliedBounds(scip, x, TRUE, y, &implbnds) );
4975  if( SCIPisZero(scip, implbnds.inf) && SCIPisZero(scip, implbnds.sup) )
4976  {
4977  /* if x = 1 implies y = 0, then we can remove the bilinear term x*y, since it is always 0
4978  * we only set the coefficient to 0.0 here and mark the bilinterms as not merged */
4979  SCIPdebugMsg(scip, "remove bilinear term %g<%s><%s> from <%s> due to implication\n", consdata->bilinterms[k].coef, SCIPvarGetName(x), SCIPvarGetName(y), SCIPconsGetName(cons));
4980  consdata->bilinterms[k].coef = 0.0;
4981  consdata->bilinmerged = FALSE;
4982  ++*nbilinremoved;
4983  continue;
4984  }
4985 
4986  SCIP_CALL( getImpliedBounds(scip, x, FALSE, y, &implbnds) );
4987  if( SCIPisZero(scip, implbnds.inf) && SCIPisZero(scip, implbnds.sup) )
4988  {
4989  /* if x = 0 implies y = 0, then we can replace the bilinear term x*y by y
4990  * we only move the coefficient to the linear coef of y here and mark the bilinterms as not merged */
4991  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));
4992  assert(consdata->quadvarssorted);
4993  SCIP_CALL( SCIPaddQuadVarLinearCoefQuadratic(scip, cons, y, consdata->bilinterms[k].coef) );
4994  consdata->bilinterms[k].coef = 0.0;
4995  consdata->bilinmerged = FALSE;
4996  ++*nbilinremoved;
4997  }
4998  }
4999  }
5000 
5001  if( *nbilinremoved > 0 )
5002  {
5003  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
5004 
5005  /* invalidate nonlinear row */
5006  if( consdata->nlrow != NULL )
5007  {
5008  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
5009  }
5010 
5011  consdata->ispropagated = FALSE;
5012  consdata->ispresolved = FALSE;
5013  consdata->iscurvchecked = FALSE;
5014  }
5015 
5016  consdata->isimpladded = FALSE;
5017 
5018  return SCIP_OKAY;
5019 }
5020 #endif
5021 
5022 /** checks a quadratic constraint for convexity and/or concavity without checking multivariate functions */
5023 static
5024 void checkCurvatureEasy(
5025  SCIP* scip, /**< SCIP data structure */
5026  SCIP_CONS* cons, /**< quadratic constraint */
5027  SCIP_HASHMAP* assumevarfixed, /**< variables to be assumed to be fixed, or NULL */
5028  SCIP_Bool* determined, /**< pointer to store whether the curvature could be determined */
5029  SCIP_Bool checkmultivariate, /**< whether curvature will be checked later on for multivariate functions */
5030  SCIP_Bool* isconvex, /**< buffer to store whether found convex */
5031  SCIP_Bool* isconcave, /**< buffer to store whether found concave */
5032  SCIP_Real* maxnonconvexity /**< buffer to store "maximal nonconvexity" */
5033  )
5034 {
5035  SCIP_CONSDATA* consdata;
5036  int nquadvars;
5037 
5038  assert(scip != NULL);
5039  assert(cons != NULL);
5040  assert(determined != NULL);
5041  assert(isconvex != NULL);
5042  assert(isconcave != NULL);
5043  assert(maxnonconvexity != NULL);
5044 
5045  consdata = SCIPconsGetData(cons);
5046  assert(consdata != NULL);
5047 
5048  nquadvars = consdata->nquadvars;
5049  *determined = TRUE;
5050 
5051  SCIPdebugMsg(scip, "Checking curvature of constraint <%s> without multivariate functions\n", SCIPconsGetName(cons));
5052 
5053  *maxnonconvexity = 0.0;
5054  if( nquadvars == 1 )
5055  {
5056  assert(consdata->nbilinterms == 0);
5057  if( assumevarfixed == NULL || !SCIPhashmapExists(assumevarfixed, (void*)consdata->quadvarterms[0].var) )
5058  {
5059  *isconvex = !SCIPisNegative(scip, consdata->quadvarterms[0].sqrcoef);
5060  *isconcave = !SCIPisPositive(scip, consdata->quadvarterms[0].sqrcoef);
5061 
5062  if( !SCIPisInfinity(scip, -consdata->lhs) && consdata->quadvarterms[0].sqrcoef > 0.0 )
5063  *maxnonconvexity = consdata->quadvarterms[0].sqrcoef;
5064  if( !SCIPisInfinity(scip, consdata->rhs) && consdata->quadvarterms[0].sqrcoef < 0.0 )
5065  *maxnonconvexity = -consdata->quadvarterms[0].sqrcoef;
5066  }
5067  else
5068  {
5069  /* only variable should be assumed to be fixed, so we are linear */
5070  *isconvex = TRUE;
5071  *isconcave = TRUE;
5072  }
5073  }
5074  else if( nquadvars == 0 )
5075  {
5076  *isconvex = TRUE;
5077  *isconcave = TRUE;
5078  }
5079  else if( consdata->nbilinterms == 0 )
5080  {
5081  int v;
5082 
5083  *isconvex = TRUE;
5084  *isconcave = TRUE;
5085 
5086  for( v = nquadvars - 1; v >= 0; --v )
5087  {
5088  /* skip assumed-to-be-fixed variables */
5089  if( assumevarfixed != NULL && SCIPhashmapExists(assumevarfixed, (void*)consdata->quadvarterms[v].var) )
5090  continue;
5091 
5092  *isconvex = *isconvex && !SCIPisNegative(scip, consdata->quadvarterms[v].sqrcoef);
5093  *isconcave = *isconcave && !SCIPisPositive(scip, consdata->quadvarterms[v].sqrcoef);
5094 
5095  if( !SCIPisInfinity(scip, -consdata->lhs) && consdata->quadvarterms[v].sqrcoef > consdata->maxnonconvexity )
5096  *maxnonconvexity = consdata->quadvarterms[0].sqrcoef;
5097  if( !SCIPisInfinity(scip, consdata->rhs) && -consdata->quadvarterms[v].sqrcoef > consdata->maxnonconvexity )
5098  *maxnonconvexity = -consdata->quadvarterms[0].sqrcoef;
5099  }
5100  }
5101  else if( !checkmultivariate )
5102  {
5103  *isconvex = FALSE;
5104  *isconcave = FALSE;
5105  *maxnonconvexity = SCIPinfinity(scip);
5106  }
5107  else
5108  {
5109  *isconvex = FALSE;
5110  *isconcave = FALSE;
5111  *determined = FALSE;
5112  }
5113 }
5114 
5115 /** checks a quadratic constraint for convexity and/or concavity while checking multivariate functions */
5116 static
5118  SCIP* scip, /**< SCIP data structure */
5119  SCIP_CONS* cons, /**< quadratic constraint */
5120  SCIP_HASHMAP* assumevarfixed, /**< variables to be assumed to be fixed, or NULL */
5121  SCIP_Bool* isconvex, /**< buffer to store whether found convex */
5122  SCIP_Bool* isconcave, /**< buffer to store whether found concave */
5123  SCIP_Real* maxnonconvexity /**< buffer to store "maximal nonconvexity" */
5124  )
5125 {
5126  SCIP_CONSDATA* consdata;
5127  double* matrix;
5128  SCIP_HASHMAP* var2index;
5129  int i;
5130  int n;
5131  int nn;
5132  int row;
5133  int col;
5134  double* alleigval;
5135 
5136  assert(scip != NULL);
5137  assert(cons != NULL);
5138  assert(isconvex != NULL);
5139  assert(isconcave != NULL);
5140  assert(maxnonconvexity != NULL);
5141 
5142  consdata = SCIPconsGetData(cons);
5143  assert(consdata != NULL);
5144 
5145  n = consdata->nquadvars;
5146 
5147  SCIPdebugMsg(scip, "Checking curvature of constraint <%s> with multivariate functions\n", SCIPconsGetName(cons));
5148 
5149  if( n == 2 && assumevarfixed == NULL )
5150  {
5151  SCIP_Real tracehalf;
5152  SCIP_Real discriminantroot;
5153 
5154  /* compute eigenvalues by hand */
5155  assert(consdata->nbilinterms == 1);
5156  *isconvex =
5157  consdata->quadvarterms[0].sqrcoef >= 0 &&
5158  consdata->quadvarterms[1].sqrcoef >= 0 &&
5159  4 * consdata->quadvarterms[0].sqrcoef * consdata->quadvarterms[1].sqrcoef >= consdata->bilinterms[0].coef * consdata->bilinterms[0].coef;
5160  *isconcave =
5161  consdata->quadvarterms[0].sqrcoef <= 0 &&
5162  consdata->quadvarterms[1].sqrcoef <= 0 &&
5163  4 * consdata->quadvarterms[0].sqrcoef * consdata->quadvarterms[1].sqrcoef >= consdata->bilinterms[0].coef * consdata->bilinterms[0].coef;
5164 
5165  /* store largest eigenvalue causing nonconvexity according to sides */
5166  tracehalf = (consdata->quadvarterms[0].sqrcoef + consdata->quadvarterms[1].sqrcoef) / 2.0;
5167  discriminantroot = consdata->quadvarterms[0].sqrcoef * consdata->quadvarterms[1].sqrcoef - SQR(consdata->bilinterms[0].coef / 2.0);
5168  discriminantroot = SQR(tracehalf) - discriminantroot;
5169  assert(!SCIPisNegative(scip, discriminantroot));
5170  discriminantroot = SQRT(MAX(0.0, discriminantroot));
5171 
5172  *maxnonconvexity = 0.0;
5173  if( !SCIPisInfinity(scip, -consdata->lhs) )
5174  *maxnonconvexity = MAX(*maxnonconvexity, tracehalf + discriminantroot);
5175  if( !SCIPisInfinity(scip, consdata->rhs) )
5176  *maxnonconvexity = MAX(*maxnonconvexity, discriminantroot - tracehalf);
5177 
5178  return SCIP_OKAY;
5179  }
5180 
5181  /* do not check curvature if n is too large */
5182  nn = n * n;
5183  if( nn < 0 || (unsigned) (int) nn > UINT_MAX / sizeof(SCIP_Real) )
5184  {
5185  SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL, "cons_quadratic - n is too large to check the curvature\n");
5186  *isconvex = FALSE;
5187  *isconcave = FALSE;
5188  *maxnonconvexity = SCIPinfinity(scip);
5189  return SCIP_OKAY;
5190  }
5191 
5192  /* lower triangular of quadratic term matrix */
5193  SCIP_CALL( SCIPallocBufferArray(scip, &matrix, nn) );
5194  BMSclearMemoryArray(matrix, nn);
5195 
5196  *isconvex = TRUE;
5197  *isconcave = TRUE;
5198  *maxnonconvexity = 0.0;
5199 
5200  SCIP_CALL( SCIPhashmapCreate(&var2index, SCIPblkmem(scip), n) );
5201  for( i = 0; i < n; ++i )
5202  {
5203  /* skip variables that we assume are fixed -> 0 row/col in coef matrix */
5204  if( assumevarfixed != NULL && SCIPhashmapExists(assumevarfixed, (void*)consdata->quadvarterms[i].var) )
5205  continue;
5206 
5207  if( consdata->quadvarterms[i].nadjbilin > 0 )
5208  {
5209  SCIP_CALL( SCIPhashmapInsertInt(var2index, consdata->quadvarterms[i].var, i) );
5210  matrix[i*n + i] = consdata->quadvarterms[i].sqrcoef;
5211  }
5212  else
5213  {
5214  /* if pure square term, then update maximal nonconvex eigenvalue, as it will not be considered in lapack call below */
5215  if( !SCIPisInfinity(scip, -consdata->lhs) && consdata->quadvarterms[i].sqrcoef > *maxnonconvexity )
5216  *maxnonconvexity = consdata->quadvarterms[i].sqrcoef;
5217  if( !SCIPisInfinity(scip, consdata->rhs) && -consdata->quadvarterms[i].sqrcoef > *maxnonconvexity )
5218  *maxnonconvexity = -consdata->quadvarterms[i].sqrcoef;
5219  }
5220  /* nonzero elements on diagonal tell a lot about convexity/concavity */
5221  if( SCIPisNegative(scip, consdata->quadvarterms[i].sqrcoef) )
5222  *isconvex = FALSE;
5223  if( SCIPisPositive(scip, consdata->quadvarterms[i].sqrcoef) )
5224  *isconcave = FALSE;
5225  }
5226 
5227  /* skip lapack call, if we know already that we are indefinite
5228  * NOTE: this will leave out updating consdata->maxnonconvexity, so that it only provides a lower bound in this case
5229  */
5230  if( !*isconvex && !*isconcave )
5231  {
5232  SCIPfreeBufferArray(scip, &matrix);
5233  SCIPhashmapFree(&var2index);
5234  /* make sure that maxnonconvexity is strictly different from zero if nonconvex
5235  * TODO one could think about doing some eigenvalue estimation here (Gershgorin)
5236  */
5237  *maxnonconvexity = MAX(1000.0, *maxnonconvexity);
5238  return SCIP_OKAY;
5239  }
5240 
5242  {
5243  for( i = 0; i < consdata->nbilinterms; ++i )
5244  {
5245  /* skip variables that we assume are fixed -> 0 row/col in coef matrix */
5246  if( assumevarfixed != NULL && (SCIPhashmapExists(assumevarfixed, (void*)consdata->bilinterms[i].var1) || SCIPhashmapExists(assumevarfixed, (void*)consdata->bilinterms[i].var2)) )
5247  continue;
5248 
5249  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var1));
5250  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var2));
5251  row = SCIPhashmapGetImageInt(var2index, consdata->bilinterms[i].var1);
5252  col = SCIPhashmapGetImageInt(var2index, consdata->bilinterms[i].var2);
5253  if( row < col )
5254  matrix[row * n + col] = consdata->bilinterms[i].coef/2;
5255  else
5256  matrix[col * n + row] = consdata->bilinterms[i].coef/2;
5257  }
5258 
5259  SCIP_CALL( SCIPallocBufferArray(scip, &alleigval, n) );
5260  /* @todo Can we compute only min and max eigen value?
5261  * @todo Can we estimate the numerical error?
5262  * @todo Trying a cholesky factorization may be much faster.
5263  */
5264  if( LapackDsyev(FALSE, n, matrix, alleigval) != SCIP_OKAY )
5265  {
5266  SCIPwarningMessage(scip, "Failed to compute eigenvalues of quadratic coefficient matrix of constraint %s. Assuming matrix is indefinite.\n", SCIPconsGetName(cons));
5267  *isconvex = FALSE;
5268  *isconcave = FALSE;
5269  }
5270  else
5271  {
5272  /* deconvexification reformulates a stricly convex quadratic function in binaries such that it becomes not-strictly convex
5273  * by adding the -lambda*(x^2-x) terms for lambda the smallest eigenvalue of the matrix
5274  * 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
5275  */
5276 #ifdef DECONVEXIFY
5277  SCIP_Bool allbinary;
5278  printf("cons <%s>[%g,%g] spectrum = [%g,%g]\n", SCIPconsGetName(cons), consdata->lhs, consdata->rhs, alleigval[0], alleigval[n-1]);
5279 #endif
5280  *isconvex &= !SCIPisNegative(scip, alleigval[0]); /*lint !e514*/
5281  *isconcave &= !SCIPisPositive(scip, alleigval[n-1]); /*lint !e514*/
5282 #ifdef DECONVEXIFY
5283  for( i = 0; i < consdata->nquadvars; ++i )
5284  if( !SCIPvarIsBinary(consdata->quadvarterms[i].var) )
5285  break;
5286  allbinary = i == consdata->nquadvars;
5287 
5288  if( !SCIPisInfinity(scip, consdata->rhs) && alleigval[0] > 0.1 && allbinary )
5289  {
5290  printf("deconvexify cons <%s> by shifting hessian by %g\n", SCIPconsGetName(cons), alleigval[0]);
5291  for( i = 0; i < consdata->nquadvars; ++i )
5292  {
5293  consdata->quadvarterms[i].sqrcoef -= alleigval[0];
5294  consdata->quadvarterms[i].lincoef += alleigval[0];
5295  }
5296  }
5297 
5298  if( !SCIPisInfinity(scip, consdata->lhs) && alleigval[n-1] < -0.1 && allbinary )
5299  {
5300  printf("deconcavify cons <%s> by shifting hessian by %g\n", SCIPconsGetName(cons), alleigval[n-1]);
5301  for( i = 0; i < consdata->nquadvars; ++i )
5302  {
5303  consdata->quadvarterms[i].sqrcoef -= alleigval[n-1];
5304  consdata->quadvarterms[i].lincoef += alleigval[n-1];
5305  }
5306  }
5307 #endif
5308  }
5309 
5310  /* update largest eigenvalue causing nonconvexity according to sides */
5311  if( !SCIPisInfinity(scip, -consdata->lhs) )
5312  *maxnonconvexity = MAX(*maxnonconvexity, alleigval[n-1]);
5313  if( !SCIPisInfinity(scip, consdata->rhs) )
5314  *maxnonconvexity = MAX(*maxnonconvexity, -alleigval[0]);
5315 
5316  SCIPfreeBufferArray(scip, &alleigval);
5317  }
5318  else
5319  {
5320  *isconvex = FALSE;
5321  *isconcave = FALSE;
5322  *maxnonconvexity = SCIPinfinity(scip);
5323  }
5324 
5325  SCIPhashmapFree(&var2index);
5326  SCIPfreeBufferArray(scip, &matrix);
5327 
5328  return SCIP_OKAY;
5329 }
5330 
5331 
5332 /** checks a quadratic constraint for convexity and/or concavity */
5333 static
5335  SCIP* scip, /**< SCIP data structure */
5336  SCIP_CONS* cons, /**< quadratic constraint */
5337  SCIP_Bool checkmultivariate /**< whether curvature should also be checked for multivariate functions */
5338  )
5339 {
5340  SCIP_Bool determined;
5341  SCIP_Bool isconvex;
5342  SCIP_Bool isconcave;
5343  SCIP_CONSDATA* consdata;
5344 
5345  consdata = SCIPconsGetData(cons);
5346  assert(consdata != NULL);
5347 
5348  if( consdata->iscurvchecked )
5349  return SCIP_OKAY;
5350 
5351  checkCurvatureEasy(scip, cons, NULL, &determined, checkmultivariate, &isconvex, &isconcave,
5352  &consdata->maxnonconvexity);
5353  if( !determined && checkmultivariate )
5354  {
5355  SCIP_CALL( checkCurvatureExpensive(scip, cons, NULL, &isconvex, &isconcave,
5356  &consdata->maxnonconvexity) );
5357  }
5358 
5359  consdata->isconvex = isconvex;
5360  consdata->isconcave = isconcave;
5361  consdata->iscurvchecked = TRUE;
5362 
5363  return SCIP_OKAY;
5364 }
5365 
5366 /** check whether indefinite constraint function is factorable and store corresponding coefficients */
5367 static
5369  SCIP* scip, /**< SCIP data structure */
5370  SCIP_CONS* cons /**< constraint */
5371  )
5372 {
5373  SCIP_BILINTERM* bilinterm;
5374  SCIP_CONSDATA* consdata;
5375  SCIP_Real* a;
5376  SCIP_Real* eigvals;
5377  SCIP_Real sigma1;
5378  SCIP_Real sigma2;
5379  SCIP_Bool success;
5380  int n;
5381  int i;
5382  int idx1;
5383  int idx2;
5384  int posidx;
5385  int negidx;
5386 
5387  assert(scip != NULL);
5388  assert(cons != NULL);
5389 
5390  consdata = SCIPconsGetData(cons);
5391  assert(consdata != NULL);
5392  assert(consdata->factorleft == NULL);
5393  assert(consdata->factorright == NULL);
5394 
5395  /* we don't need this if there are no bilinear terms */
5396  if( consdata->nbilinterms == 0 )
5397  return SCIP_OKAY;
5398 
5399  /* write constraint as lhs <= linear + x'^T A x' <= rhs where x' = (x,1) and
5400  * A = ( Q b/2 )
5401  * ( b^T/2 0 )
5402  * compute an eigenvalue factorization of A and check if there are one positive and one negative eigenvalue
5403  * 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
5404  * thus, x'^T A x' = sigma1^2 (v1^T x')^2 - sigma2^2 (v2^T x')^2
5405  * = (sigma1 (v1^T x') - sigma2 (v2^T x')) * (sigma1 (v1^T x') + sigma2 (v2^T x'))
5406  * we then store sigma1 v1^T - sigma2 v2^T as left factor coef, and sigma1 v1^T + sigma2 v2^T as right factor coef
5407  */
5408 
5409  /* if we already know that there are only positive or only negative eigenvalues, then don't try */
5410  if( consdata->iscurvchecked && (consdata->isconvex || consdata->isconcave) )
5411  return SCIP_OKAY;
5412 
5413  n = consdata->nquadvars + 1;
5414 
5415  /* @todo handle case n=3 explicitly */
5416 
5417  /* skip too large matrices */
5418  if( n > 50 )
5419  return SCIP_OKAY;
5420 
5421  /* need routine to compute eigenvalues/eigenvectors */
5422  if( !SCIPisIpoptAvailableIpopt() )
5423  return SCIP_OKAY;
5424 
5425  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
5426 
5427  SCIP_CALL( SCIPallocBufferArray(scip, &a, n*n) );
5428  BMSclearMemoryArray(a, n*n);
5429 
5430  /* set lower triangular entries of A corresponding to bilinear terms */
5431  for( i = 0; i < consdata->nbilinterms; ++i )
5432  {
5433  bilinterm = &consdata->bilinterms[i];
5434 
5435  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var1, &idx1) );
5436  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var2, &idx2) );
5437  assert(idx1 >= 0);
5438  assert(idx2 >= 0);
5439  assert(idx1 != idx2);
5440 
5441  a[MIN(idx1,idx2) * n + MAX(idx1,idx2)] = bilinterm->coef / 2.0;
5442  }
5443 
5444  /* set lower triangular entries of A corresponding to square and linear terms */
5445  for( i = 0; i < consdata->nquadvars; ++i )
5446  {
5447  a[i*n + i] = consdata->quadvarterms[i].sqrcoef;
5448  a[i*n + n-1] = consdata->quadvarterms[i].lincoef / 2.0;
5449  }
5450 
5451  SCIP_CALL( SCIPallocBufferArray(scip, &eigvals, n) );
5452  if( LapackDsyev(TRUE, n, a, eigvals) != SCIP_OKAY )
5453  {
5454  SCIPdebugMsg(scip, "Failed to compute eigenvalues and eigenvectors of augmented quadratic form matrix for constraint <%s>.\n", SCIPconsGetName(cons));
5455  goto CLEANUP;
5456  }
5457 
5458  /* check if there is exactly one positive and one negative eigenvalue */
5459  posidx = -1;
5460  negidx = -1;
5461  for( i = 0; i < n; ++i )
5462  {
5463  if( SCIPisPositive(scip, eigvals[i]) )
5464  {
5465  if( posidx == -1 )
5466  posidx = i;
5467  else
5468  break;
5469  }
5470  else if( SCIPisNegative(scip, eigvals[i]) )
5471  {
5472  if( negidx == -1 )
5473  negidx = i;
5474  else
5475  break;
5476  }
5477  }
5478  if( i < n || posidx == -1 || negidx == -1 )
5479  {
5480  SCIPdebugMsg(scip, "Augmented quadratic form of constraint <%s> is not factorable.\n", SCIPconsGetName(cons));
5481  goto CLEANUP;
5482  }
5483  assert(SCIPisPositive(scip, eigvals[posidx]));
5484  assert(SCIPisNegative(scip, eigvals[negidx]));
5485 
5486  /* compute factorleft and factorright */
5487  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->factorleft, consdata->nquadvars + 1) );
5488  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->factorright, consdata->nquadvars + 1) );
5489 
5490  /* eigenvectors are stored in a, inverse eigenvector matrix is transposed of a
5491  * it seems that v1 and v2 are at &a[posidx*n] and &a[negidx*n]
5492  */
5493  sigma1 = sqrt( eigvals[posidx]);
5494  sigma2 = sqrt(-eigvals[negidx]);
5495  for( i = 0; i < n; ++i )
5496  {
5497  consdata->factorleft[i] = sigma1 * a[posidx * n + i] - sigma2 * a[negidx * n + i];
5498  consdata->factorright[i] = sigma1 * a[posidx * n + i] + sigma2 * a[negidx * n + i];
5499  /* set almost-zero elements to zero */
5500  if( SCIPisZero(scip, consdata->factorleft[i]) )
5501  consdata->factorleft[i] = 0.0;
5502  if( SCIPisZero(scip, consdata->factorright[i]) )
5503  consdata->factorright[i] = 0.0;
5504  }
5505 
5506 #ifdef SCIP_DEBUG
5507  SCIPdebugMsg(scip, "constraint <%s> has factorable quadratic form: (%g", SCIPconsGetName(cons), consdata->factorleft[n-1]);
5508  for( i = 0; i < consdata->nquadvars; ++i )
5509  {
5510  if( consdata->factorleft[i] != 0.0 )
5511  SCIPdebugMsgPrint(scip, " %+g<%s>", consdata->factorleft[i], SCIPvarGetName(consdata->quadvarterms[i].var));
5512  }
5513  SCIPdebugMsgPrint(scip, ") * (%g", consdata->factorright[n-1]);
5514  for( i = 0; i < consdata->nquadvars; ++i )
5515  {
5516  if( consdata->factorright[i] != 0.0 )
5517  SCIPdebugMsgPrint(scip, " %+g<%s>", consdata->factorright[i], SCIPvarGetName(consdata->quadvarterms[i].var));
5518  }
5519  SCIPdebugMsgPrint(scip, ")\n");
5520 #endif
5521 
5522  /* check whether factorleft * factorright^T is matrix of augmented quadratic form
5523  * we check here only the nonzero entries from the quadratic form
5524  */
5525  success = TRUE;
5526 
5527  /* check bilinear terms */
5528  for( i = 0; i < consdata->nbilinterms; ++i )
5529  {
5530  bilinterm = &consdata->bilinterms[i];
5531 
5532  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var1, &idx1) );
5533  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var2, &idx2) );
5534 
5535  if( !SCIPisRelEQ(scip, consdata->factorleft[idx1] * consdata->factorright[idx2] + consdata->factorleft[idx2] * consdata->factorright[idx1], bilinterm->coef) )
5536  {
5537  success = FALSE;
5538  break;
5539  }
5540  }
5541 
5542  /* set lower triangular entries of A corresponding to square and linear terms */
5543  for( i = 0; i < consdata->nquadvars; ++i )
5544  {
5545  if( !SCIPisRelEQ(scip, consdata->factorleft[i] * consdata->factorright[i], consdata->quadvarterms[i].sqrcoef) )
5546  {
5547  success = FALSE;
5548  break;
5549  }
5550 
5551  if( !SCIPisRelEQ(scip, consdata->factorleft[n-1] * consdata->factorright[i] + consdata->factorleft[i] * consdata->factorright[n-1], consdata->quadvarterms[i].lincoef) )
5552  {
5553  success = FALSE;
5554  break;
5555  }
5556  }
5557 
5558  if( !success )
5559  {
5560  SCIPdebugMsg(scip, "Factorization not accurate enough. Dropping it.\n");
5561  SCIPfreeBlockMemoryArray(scip, &consdata->factorleft, consdata->nquadvars + 1);
5562  SCIPfreeBlockMemoryArray(scip, &consdata->factorright, consdata->nquadvars + 1);
5563  }
5564 
5565  CLEANUP:
5566  SCIPfreeBufferArray(scip, &eigvals);
5567  SCIPfreeBufferArray(scip, &a);
5568 
5569  return SCIP_OKAY;
5570 }
5571 
5572 /** computes activity and violation of a constraint
5573  *
5574  * If solution violates bounds by more than feastol, the violation is still computed, but *solviolbounds is set to TRUE
5575  */
5576 static
5578  SCIP* scip, /**< SCIP data structure */
5579  SCIP_CONS* cons, /**< constraint */
5580  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
5581  SCIP_Bool* solviolbounds /**< buffer to store whether quadratic variables in solution are outside their bounds by more than feastol */
5582  )
5583 { /*lint --e{666}*/
5584  SCIP_CONSDATA* consdata;
5585  SCIP_Real varval;
5586  SCIP_Real varval2;
5587  SCIP_Real absviol;
5588  SCIP_Real relviol;
5589  SCIP_VAR* var;
5590  SCIP_VAR* var2;
5591  int i;
5592  int j;
5593 
5594  assert(scip != NULL);
5595  assert(cons != NULL);
5596  assert(solviolbounds != NULL);
5597 
5598  consdata = SCIPconsGetData(cons);
5599  assert(consdata != NULL);
5600 
5601  *solviolbounds = FALSE;
5602  consdata->activity = 0.0;
5603  consdata->lhsviol = 0.0;
5604  consdata->rhsviol = 0.0;
5605 
5606  for( i = 0; i < consdata->nlinvars; ++i )
5607  {
5608  SCIP_Real activity;
5609 
5610  var = consdata->linvars[i];
5611  varval = SCIPgetSolVal(scip, sol, var);
5612  activity = consdata->lincoefs[i] * varval;
5613 
5614  /* the contribution of a variable with |varval| = +inf is +inf when activity > 0.0, -inf when activity < 0.0, and
5615  * 0.0 otherwise
5616  */
5617  if( SCIPisInfinity(scip, REALABS(varval)) )
5618  {
5619  if( activity > 0.0 && !SCIPisInfinity(scip, consdata->rhs) )
5620  {
5621  consdata->activity = SCIPinfinity(scip);
5622  consdata->rhsviol = SCIPinfinity(scip);
5623  return SCIP_OKAY;
5624  }
5625 
5626  if( activity < 0.0 && !SCIPisInfinity(scip, -consdata->lhs) )
5627  {
5628  consdata->activity = -SCIPinfinity(scip);
5629  consdata->lhsviol = SCIPinfinity(scip);
5630  return SCIP_OKAY;
5631  }
5632  }
5633 
5634  consdata->activity += activity;
5635  }
5636 
5637  for( j = 0; j < consdata->nquadvars; ++j )
5638  {
5639  SCIP_Real activity;
5640 
5641  var = consdata->quadvarterms[j].var;
5642  varval = SCIPgetSolVal(scip, sol, var);
5643  activity = (consdata->quadvarterms[j].lincoef + consdata->quadvarterms[j].sqrcoef * varval) * varval;
5644 
5645  /* the contribution of a variable with |varval| = +inf is +inf when activity > 0.0, -inf when activity < 0.0, and
5646  * 0.0 otherwise
5647  */
5648  if( SCIPisInfinity(scip, REALABS(varval)) )
5649  {
5650  if( activity > 0.0 && !SCIPisInfinity(scip, consdata->rhs) )
5651  {
5652  consdata->activity = SCIPinfinity(scip);
5653  consdata->rhsviol = SCIPinfinity(scip);
5654  return SCIP_OKAY;
5655  }
5656 
5657  if( activity < 0.0 && !SCIPisInfinity(scip, -consdata->lhs) )
5658  {
5659  consdata->activity = -SCIPinfinity(scip);
5660  consdata->lhsviol = SCIPinfinity(scip);
5661  return SCIP_OKAY;
5662  }
5663  }
5664 
5665  /* project onto local box, in case the LP solution is slightly outside the bounds (which is not our job to enforce) */
5666  if( sol == NULL )
5667  {
5668  /* 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 */
5669  if( (!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) && !SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var))) ||
5670  (!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) && !SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var))) )
5671  *solviolbounds = TRUE;
5672  else
5673  {
5674  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
5675  activity = (consdata->quadvarterms[j].lincoef + consdata->quadvarterms[j].sqrcoef * varval) * varval;
5676  }
5677  }
5678 
5679  consdata->activity += activity;
5680  }
5681 
5682  for( j = 0; j < consdata->nbilinterms; ++j )
5683  {
5684  SCIP_Real activity;
5685 
5686  var = consdata->bilinterms[j].var1;
5687  var2 = consdata->bilinterms[j].var2;
5688  varval = SCIPgetSolVal(scip, sol, var);
5689  varval2 = SCIPgetSolVal(scip, sol, var2);
5690 
5691  /* project onto local box, in case the LP solution is slightly outside the bounds (which is not our job to enforce) */
5692  if( sol == NULL )
5693  {
5694  /* 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 */
5695  if( (!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) && !SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var))) ||
5696  (!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) && !SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var))) )
5697  *solviolbounds = TRUE;
5698  else
5699  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
5700 
5701  /* 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 */
5702  if( (!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var2)) && !SCIPisFeasGE(scip, varval2, SCIPvarGetLbLocal(var2))) ||
5703  (!SCIPisInfinity(scip, SCIPvarGetUbLocal(var2)) && !SCIPisFeasLE(scip, varval2, SCIPvarGetUbLocal(var2))) )
5704  *solviolbounds = TRUE;
5705  else
5706  varval2 = MAX(SCIPvarGetLbLocal(var2), MIN(SCIPvarGetUbLocal(var2), varval2));
5707  }
5708 
5709  activity = consdata->bilinterms[j].coef * varval * varval2;
5710 
5711  /* consider var*var2 as a new variable and handle it as it would appear linearly */
5712  if( SCIPisInfinity(scip, REALABS(varval*varval2)) )
5713  {
5714  if( activity > 0.0 && !SCIPisInfinity(scip, consdata->rhs) )
5715  {
5716  consdata->activity = SCIPinfinity(scip);
5717  consdata->rhsviol = SCIPinfinity(scip);
5718  return SCIP_OKAY;
5719  }
5720 
5721  if( activity < 0.0 && !SCIPisInfinity(scip, -consdata->lhs) )
5722  {
5723  consdata->activity = -SCIPinfinity(scip);
5724  consdata->lhsviol = SCIPinfinity(scip);
5725  return SCIP_OKAY;
5726  }
5727  }
5728 
5729  consdata->activity += activity;
5730  }
5731 
5732  absviol = 0.0;
5733  relviol = 0.0;
5734  /* compute absolute violation left hand side */
5735  if( consdata->activity < consdata->lhs && !SCIPisInfinity(scip, -consdata->lhs) )
5736  {
5737  consdata->lhsviol = consdata->lhs - consdata->activity;
5738  absviol = consdata->lhsviol;
5739  relviol = SCIPrelDiff(consdata->lhs, consdata->activity);
5740  }
5741  else
5742  consdata->lhsviol = 0.0;
5743 
5744  /* compute absolute violation right hand side */
5745  if( consdata->activity > consdata->rhs && !SCIPisInfinity(scip, consdata->rhs) )
5746  {
5747  consdata->rhsviol = consdata->activity - consdata->rhs;
5748  absviol = consdata->rhsviol;
5749  relviol = SCIPrelDiff(consdata->activity, consdata->rhs);
5750  }
5751  else
5752  consdata->rhsviol = 0.0;
5753 
5754  /* update absolute and relative violation of the solution */
5755  if( sol != NULL )
5756  SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
5757 
5758  return SCIP_OKAY;
5759 }
5760 
5761 /** computes violation of a set of constraints */
5762 static
5764  SCIP* scip, /**< SCIP data structure */
5765  SCIP_CONS** conss, /**< constraints */
5766  int nconss, /**< number of constraints */
5767  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
5768  SCIP_Bool* solviolbounds, /**< buffer to store whether quadratic variables in solution are outside their bounds by more than feastol in some constraint */
5769  SCIP_CONS** maxviolcon /**< buffer to store constraint with largest violation, or NULL if solution is feasible */
5770  )
5771 {
5772  SCIP_CONSDATA* consdata;
5773  SCIP_Real viol;
5774  SCIP_Real maxviol;
5775  SCIP_Bool solviolbounds1;
5776  int c;
5777 
5778  assert(scip != NULL);
5779  assert(conss != NULL || nconss == 0);
5780  assert(solviolbounds != NULL);
5781  assert(maxviolcon != NULL);
5782 
5783  *solviolbounds = FALSE;
5784  *maxviolcon = NULL;
5785 
5786  maxviol = 0.0;
5787 
5788  for( c = 0; c < nconss; ++c )
5789  {
5790  assert(conss != NULL);
5791  assert(conss[c] != NULL);
5792 
5793  SCIP_CALL( computeViolation(scip, conss[c], sol, &solviolbounds1) );
5794  *solviolbounds |= solviolbounds1;
5795 
5796  consdata = SCIPconsGetData(conss[c]);
5797  assert(consdata != NULL);
5798 
5799  viol = MAX(consdata->lhsviol, consdata->rhsviol);
5800  if( viol > maxviol && SCIPisGT(scip, viol, SCIPfeastol(scip)) )
5801  {
5802  maxviol = viol;
5803  *maxviolcon = conss[c];
5804  }
5805  }
5806 
5807  return SCIP_OKAY;
5808 }
5809 
5810 
5811 /** index comparison method for bilinear terms */
5812 static
5813 SCIP_DECL_SORTINDCOMP(bilinTermComp2)
5814 { /*lint --e{715}*/
5815  SCIP_BILINTERM* bilinterms = (SCIP_BILINTERM*)dataptr;
5816  int var1cmp;
5817 
5818  assert(bilinterms != NULL);
5819 
5820  var1cmp = SCIPvarCompare(bilinterms[ind1].var1, bilinterms[ind2].var1);
5821  if( var1cmp != 0 )
5822  return var1cmp;
5823 
5824  return SCIPvarCompare(bilinterms[ind1].var2, bilinterms[ind2].var2);
5825 }
5826 
5827 /** volume comparison method for bilinear terms; prioritizes bilinear products with a larger volume */
5828 static
5829 SCIP_DECL_SORTINDCOMP(bilinTermCompVolume)
5830 { /*lint --e{715}*/
5831  SCIP_BILINTERM* bilinterms = (SCIP_BILINTERM*)dataptr;
5832  SCIP_Real vol1;
5833  SCIP_Real vol2;
5834 
5835  assert(bilinterms != NULL);
5836 
5837  vol1 = (SCIPvarGetUbLocal(bilinterms[ind1].var1) - SCIPvarGetLbLocal(bilinterms[ind1].var1))
5838  * (SCIPvarGetUbLocal(bilinterms[ind1].var2) - SCIPvarGetLbLocal(bilinterms[ind1].var2));
5839  vol2 = (SCIPvarGetUbLocal(bilinterms[ind2].var1) - SCIPvarGetLbLocal(bilinterms[ind2].var1))
5840  * (SCIPvarGetUbLocal(bilinterms[ind2].var2) - SCIPvarGetLbLocal(bilinterms[ind2].var2));
5841 
5842  if( vol1 > vol2 )
5843  return -1;
5844  else if( vol1 < vol2 )
5845  return 1;
5846  return bilinTermComp2(dataptr, ind1, ind2);
5847 }
5848 
5849 /** helper function to sort all bilinear terms in the constraint handler data */
5850 static
5852  SCIP* scip, /**< SCIP data structure */
5853  SCIP_BILINTERM* bilinterms, /**< array containing all bilinear terms */
5854  int nbilinterms, /**< total number of bilinear terms */
5855  SCIP_CONS** bilinconss, /**< array for mapping each term to its constraint */
5856  int* bilinposs /**< array for mapping each term to its position in the corresponding
5857  * bilinconss constraint */
5858  )
5859 {
5860  int* perm;
5861  int i;
5862  int nexti;
5863  int v;
5864  SCIP_BILINTERM bilinterm;
5865  SCIP_CONS* bilincons;
5866  int bilinpos;
5867 
5868  assert(scip != NULL);
5869  assert(bilinterms != NULL);
5870  assert(nbilinterms > 0);
5871  assert(bilinconss != NULL);
5872  assert(bilinposs != NULL);
5873 
5874  /* get temporary memory to store the sorted permutation and the inverse permutation */
5875  SCIP_CALL( SCIPallocBufferArray(scip, &perm, nbilinterms) );
5876 
5877  /* call quicksort */
5878  SCIPsort(perm, bilinTermCompVolume, (void*)bilinterms, nbilinterms);
5879 
5880  /* permute the bilinear terms according to the resulting permutation */
5881  for( v = 0; v < nbilinterms; ++v )
5882  {
5883  if( perm[v] != v )
5884  {
5885  bilinterm = bilinterms[v];
5886  bilincons = bilinconss[v];
5887  bilinpos = bilinposs[v];
5888 
5889  i = v;
5890  do
5891  {
5892  assert(0 <= perm[i] && perm[i] < nbilinterms);
5893  assert(perm[i] != i);
5894 
5895  bilinterms[i] = bilinterms[perm[i]];
5896  bilinconss[i] = bilinconss[perm[i]];
5897  bilinposs[i] = bilinposs[perm[i]];
5898 
5899  nexti = perm[i];
5900  perm[i] = i;
5901  i = nexti;
5902  }
5903  while( perm[i] != v );
5904  bilinterms[i] = bilinterm;
5905  bilinconss[i] = bilincons;
5906  bilinposs[i] = bilinpos;
5907  perm[i] = i;
5908  }
5909  }
5910 
5911  /* free temporary memory */
5912  SCIPfreeBufferArray(scip, &perm);
5913 
5914  return SCIP_OKAY;
5915 }
5916 
5917 /** stores all bilinear terms in the quadratic constraint handler data; in addition, for each bilinear term we store
5918  * the number of nonconvex constraints that require to over- or underestimate this term, which only depends on the
5919  * lhs, rhs, and the bilinear coefficient
5920  */
5921 static
5923  SCIP* scip, /**< SCIP data structure */
5924  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5925  SCIP_CONS** conss, /**< constraints to process */
5926  int nconss /**< number of constraints */
5927  )
5928 {
5929  SCIP_BILINTERM* bilinterms;
5930  SCIP_CONS** bilincons;
5931  int* bilinpos;
5932  int nbilinterms;
5933  int pos;
5934  int c;
5935  int i;
5936 
5937  assert(scip != NULL);
5938  assert(conshdlrdata != NULL);
5939  assert(conss != NULL);
5940 
5941  /* check for all cases for which we don't want to spend time for collecting all bilinear terms */
5942  if( nconss == 0 || conshdlrdata->storedbilinearterms || SCIPgetSubscipDepth(scip) != 0 || SCIPgetDepth(scip) >= 1
5943  || SCIPinProbing(scip) || SCIPinDive(scip) )
5944  return SCIP_OKAY;
5945 
5946  assert(conshdlrdata->bilinestimators == NULL);
5947  assert(conshdlrdata->nbilinterms == 0);
5948 
5949  conshdlrdata->storedbilinearterms = TRUE;
5950  nbilinterms = 0;
5951 
5952  /* count the number of bilinear terms (including duplicates) */
5953  for( c = 0; c < nconss; ++c )
5954  {
5955  SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]);
5956  assert(consdata != NULL);
5957  nbilinterms += consdata->nbilinterms;
5958  }
5959 
5960  /* no bilinear terms available -> stop */
5961  if( nbilinterms == 0 )
5962  return SCIP_OKAY;
5963 
5964  /* allocate temporary memory for sorting all bilinear terms (including duplicates) */
5965  SCIP_CALL( SCIPallocBufferArray(scip, &bilinterms, nbilinterms) );
5966  SCIP_CALL( SCIPallocBufferArray(scip, &bilincons, nbilinterms) );
5967  SCIP_CALL( SCIPallocBufferArray(scip, &bilinpos, nbilinterms) );
5968 
5969  /* copy all bilinear terms; note that we need separate entries for x*y and y*x */
5970  pos = 0;
5971  for( c = 0; c < nconss; ++c )
5972  {
5973  SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]);
5974 
5975  /* allocate memory to store the later computed indices of each bilinear term in the bilinterms array of the
5976  * constraint handler data
5977  */
5978  if( consdata->nbilinterms > 0 )
5979  {
5980  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->bilintermsidx, consdata->nbilinterms) );
5981  }
5982 
5983  for( i = 0; i < consdata->nbilinterms; ++i )
5984  {
5985  assert(consdata->bilinterms != NULL);
5986  assert(consdata->bilinterms[i].var1 != consdata->bilinterms[i].var2);
5987 
5988  /* add xy */
5989  bilinterms[pos] = consdata->bilinterms[i];
5990  bilincons[pos] = conss[c];
5991  bilinpos[pos] = i;
5992  ++pos;
5993 
5994  /* invalidate bilinear term index */
5995  assert(consdata->bilintermsidx != NULL);
5996  consdata->bilintermsidx[i] = -1;
5997  }
5998  }
5999  assert(pos == nbilinterms);
6000 
6001  /* sorts all bilinear terms (including duplicates) */
6002  SCIP_CALL( sortAllBilinTerms(scip, bilinterms, nbilinterms, bilincons, bilinpos) );
6003 
6004  /* count the number of bilinear terms without duplicates */
6005  conshdlrdata->nbilinterms = nbilinterms;
6006  for( i = 0; i < nbilinterms - 1; ++i )
6007  {
6008  assert(bilinTermCompVolume((void*)bilinterms, i, i+1) != 0 || bilinTermComp2((void*)bilinterms, i, i+1) <= 0);
6009 
6010  if( bilinTermComp2((void*)bilinterms, i, i+1) == 0 )
6011  --(conshdlrdata->nbilinterms);
6012  }
6013  assert(conshdlrdata->nbilinterms <= nbilinterms && conshdlrdata->nbilinterms > 0);
6014 
6015  /* store all information for each bilinear term into the constraint handler data */
6016  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bilinestimators, conshdlrdata->nbilinterms) );
6017 
6018  /* filter duplicates and update entries in the corresponding constraint datas */
6019  pos = 0;
6020  for( i = 0; i < nbilinterms; ++i )
6021  {
6022  SCIP_CONSDATA* consdata = SCIPconsGetData(bilincons[i]);
6023  SCIP_VAR* x;
6024  SCIP_Bool haslhs = !SCIPisInfinity(scip, -consdata->lhs);
6025  SCIP_Bool hasrhs = !SCIPisInfinity(scip, consdata->rhs);
6026 
6027  assert(consdata != NULL);
6028  assert(bilinpos[i] >= 0 && bilinpos[i] < consdata->nbilinterms);
6029 
6030  /* check for a new bilinear term */
6031  if( i == 0 || bilinTermComp2((void*)bilinterms, i-1, i) != 0 )
6032  {
6033  conshdlrdata->bilinestimators[pos].x = bilinterms[i].var1;
6034  conshdlrdata->bilinestimators[pos].y = bilinterms[i].var2;
6035  conshdlrdata->bilinestimators[pos].lastimprfac = 0.0;
6036  conshdlrdata->bilinestimators[pos].maxnonconvexity = 0.0;
6037  ++pos;
6038  }
6039 
6040  /* store whether under- or overestimation is needed for each bilinear term; note that we do not consider convex
6041  * constraints because they will not be used in separated generateCutNonConvex(), which is the only function that
6042  * uses a term-wise relaxation
6043  */
6044  if( SCIPisPositive(scip, bilinterms[i].coef) )
6045  {
6046  conshdlrdata->bilinestimators[pos-1].nunderest += (hasrhs && !consdata->isconvex) ? 1 : 0;
6047  conshdlrdata->bilinestimators[pos-1].noverest += (haslhs && !consdata->isconcave) ? 1 : 0;
6048  conshdlrdata->bilinestimators[pos-1].maxnonconvexity = MAX(conshdlrdata->bilinestimators[pos-1].maxnonconvexity, consdata->maxnonconvexity);
6049  }
6050  else
6051  {
6052  assert(SCIPisNegative(scip, bilinterms[i].coef));
6053  conshdlrdata->bilinestimators[pos-1].nunderest += (haslhs && !consdata->isconcave) ? 1 : 0;
6054  conshdlrdata->bilinestimators[pos-1].noverest += (hasrhs && !consdata->isconvex) ? 1 : 0;
6055  conshdlrdata->bilinestimators[pos-1].maxnonconvexity = MAX(conshdlrdata->bilinestimators[pos-1].maxnonconvexity, consdata->maxnonconvexity);
6056  }
6057 
6058  /* update index of bilinear term in the constraint data */
6059  x = consdata->bilinterms[bilinpos[i]].var1;
6060 
6061  assert(pos > 0);
6062  if( x == conshdlrdata->bilinestimators[pos-1].x )
6063  {
6064  assert(consdata->bilinterms[bilinpos[i]].var2 == conshdlrdata->bilinestimators[pos-1].y);
6065  consdata->bilintermsidx[bilinpos[i]] = pos-1;
6066  }
6067  }
6068  assert(pos == conshdlrdata->nbilinterms);
6069 
6070 #ifndef NDEBUG
6071  /* check whether
6072  * - all bilintermsidx entries have been set
6073  * - variables in bilinear terms of each constraint data and the constraint handler data match
6074  */
6075  for( c = 0; c < nconss; ++c )
6076  {
6077  SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]);
6078  assert(consdata != NULL);
6079 
6080  for( i = 0; i < consdata->nbilinterms; ++i )
6081  {
6082  SCIP_VAR* x = consdata->bilinterms[i].var1;
6083  SCIP_VAR* y = consdata->bilinterms[i].var2;
6084  int idx = consdata->bilintermsidx[i];
6085 
6086  assert(idx >= 0 && idx < conshdlrdata->nbilinterms);
6087  assert(x == conshdlrdata->bilinestimators[idx].x);
6088  assert(y == conshdlrdata->bilinestimators[idx].y);
6089 
6090  /* at least one direction is important if the constraint is not convex */
6091  if( !SCIPisInfinity(scip, consdata->rhs) && !consdata->isconvex )
6092  assert(conshdlrdata->bilinestimators[idx].nunderest + conshdlrdata->bilinestimators[idx].noverest > 0);
6093  if( !SCIPisInfinity(scip, -consdata->lhs) && !consdata->isconcave )
6094  assert(conshdlrdata->bilinestimators[idx].nunderest + conshdlrdata->bilinestimators[idx].noverest > 0);
6095  }
6096  }
6097 #endif
6098 
6099  /* free memory */
6100  SCIPfreeBufferArray(scip, &bilinpos);
6101  SCIPfreeBufferArray(scip, &bilincons);
6102  SCIPfreeBufferArray(scip, &bilinterms);
6103 
6104  return SCIP_OKAY;
6105 }
6106 
6107 /** frees memory allocated in storeAllBilinearTerms() */
6108 static
6110  SCIP* scip, /**< SCIP data structure */
6111  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6112  SCIP_CONS** conss, /**< constraints to process */
6113  int nconss /**< number of constraints */
6114 
6115  )
6116 {
6117  int c;
6118 
6119  assert(conshdlrdata != NULL);
6120 
6121  for( c = 0; c < nconss; ++c )
6122  {
6123  SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
6124  assert(consdata != NULL);
6125 
6126  SCIPfreeBlockMemoryArrayNull(scip, &consdata->bilintermsidx, consdata->nbilinterms);
6127  }
6128 
6129  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bilinestimators, conshdlrdata->nbilinterms);
6130 
6131  conshdlrdata->nbilinterms = 0;
6132  conshdlrdata->storedbilinearterms = FALSE;
6133 
6134  return SCIP_OKAY;
6135 }
6136 
6137 /** tries to compute cut for multleft * <coefleft, x'> * multright <= rhs / (multright * <coefright, x'>) where x'=(x,1) */
6138 static
6140  SCIP* scip, /**< SCIP data structure */
6141  SCIP_CONS* cons, /**< constraint */
6142  SCIP_Real* ref, /**< reference solution where to generate the cut */
6143  SCIP_Real multleft, /**< multiplicator on lhs */
6144  SCIP_Real* coefleft, /**< coefficient for factor on lhs */
6145  SCIP_Real multright, /**< multiplicator on both sides */
6146  SCIP_Real* coefright, /**< coefficient for factor that goes to rhs */
6147  SCIP_Real rightminactivity, /**< minimal activity of <coefright, x> */
6148  SCIP_Real rightmaxactivity, /**< maximal activity of <coefright, x> */
6149  SCIP_Real rhs, /**< denominator on rhs */
6150  SCIP_ROWPREP* rowprep, /**< rowprep to store cut coefs and constant */
6151  SCIP_Bool* success /**< buffer to indicate whether a cut was successfully computed */
6152  )
6153 {
6154  SCIP_CONSDATA* consdata;
6155  SCIP_Real constant;
6156  SCIP_Real coef;
6157  int i;
6158 
6159  assert(rowprep != NULL);
6160  assert(rightminactivity * multright > 0.0);
6161  assert(rightmaxactivity * multright > 0.0);
6162  assert(multright == 1.0 || multright == -1.0);
6163 
6164  consdata = SCIPconsGetData(cons);
6165  assert(consdata != NULL);
6166 
6167  rowprep->sidetype = SCIP_SIDETYPE_RIGHT;
6168 
6169  if( rhs > 0.0 )
6170  {
6171  /* if rhs > 0.0, then rhs / (multright * <coefright, x'>) is convex, thus need secant:
6172  * 1 / multright*<coefright, x'> <= 1/minact + 1/maxact - 1/(minact * maxact) multright*<coefright, x'>
6173  * where [minact, maxact] = multright * [rightminactivity, rightmaxactivity]
6174  *
6175  * assuming multright is either -1 or 1, and substituting gives
6176  * multright/rightminactivity + multright/rightmaxactivity - multright/(rightminactivity * rightmaxactivity) *<coefright, x'>
6177  *
6178  * multiplying by rhs, gives the estimate
6179  * rhs / (multright * <coefright, x'>) <= rhs * multright * (1/rightminactivity + 1/rightmaxactivity - 1/(rightminactivity * rightmaxactivity) * <coefright, x'>)
6180  */
6181 
6182  /* cannot do if unbounded */
6183  if( SCIPisInfinity(scip, rightmaxactivity * multright) )
6184  {
6185  *success = FALSE;
6186  return SCIP_OKAY;
6187  }
6188 
6189  assert(SCIPisFeasLE(scip, rightminactivity, rightmaxactivity));
6190 
6191  constant = multleft * multright * coefleft[consdata->nquadvars];
6192  constant -= rhs * multright * (1.0 / rightminactivity + 1.0 / rightmaxactivity);
6193  constant += rhs * multright * coefright[consdata->nquadvars] / (rightminactivity * rightmaxactivity);
6194 
6195  SCIPaddRowprepConstant(rowprep, constant);
6196 
6197  for( i = 0; i < consdata->nquadvars; ++i )
6198  {
6199  coef = multleft * multright * coefleft[i];
6200  coef += rhs * multright / (rightminactivity * rightmaxactivity) * coefright[i];
6201  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, consdata->quadvarterms[i].var, coef) );
6202  }
6203 
6204  (void) SCIPsnprintf(rowprep->name, SCIP_MAXSTRLEN, "%s_factorablesecant_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
6205 
6206  rowprep->local = TRUE;
6207  }
6208  else
6209  {
6210  SCIP_Real refvalue;
6211 
6212  /* if rhs < 0.0, then rhs / (multright * <coefright, x'>) is convex, thus need linearization:
6213  * rhs / (multright * <coefright, x'>)
6214  * <= rhs / (multright * <coefright, ref'>) - rhs / (multright * <coefright, ref'>)^2 * (multright * <coefright, x'> - multright * <coefright, ref'>)
6215  * = 2*rhs / (multright * <coefright, ref'>) - rhs / (multright * <coefright, ref'>)^2 * (multright * <coefright, x'>)
6216  *
6217  * where ref' = (ref, 1)
6218  */
6219 
6220  /* compute <coefright, ref'> */
6221  refvalue = coefright[consdata->nquadvars];
6222  for( i = 0; i < consdata->nquadvars; ++i )
6223  refvalue += coefright[i] * ref[i];
6224 
6225  /* should not happen, since we checked activity of <coefright,x> before, and assume ref within bounds */
6226  assert(!SCIPisZero(scip, refvalue));
6227 
6228  constant = multleft * multright * coefleft[consdata->nquadvars];
6229  constant -= 2.0 * rhs / (multright * refvalue);
6230  constant += rhs / (refvalue * refvalue) * multright * coefright[consdata->nquadvars];
6231 
6232  SCIPaddRowprepConstant(rowprep, constant);
6233 
6234  for( i = 0; i < consdata->nquadvars; ++i )
6235  {
6236  coef = multleft * multright * coefleft[i];
6237  coef += rhs / (refvalue * refvalue) * multright * coefright[i];
6238  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, consdata->quadvarterms[i].var, coef) );
6239  }
6240 
6241  (void) SCIPsnprintf(rowprep->name, SCIP_MAXSTRLEN, "%s_factorablelinearization_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
6242  }
6243 
6244  *success = TRUE;
6245 
6246  return SCIP_OKAY;
6247 }
6248 
6249 /** tries to generate a cut if constraint quadratic function is factorable and there are no linear variables
6250  * (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
6251  */
6252 static
6254  SCIP* scip, /**< SCIP data structure */
6255  SCIP_CONS* cons, /**< constraint */
6256  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
6257  SCIP_Real* ref, /**< reference solution where to generate the cut */
6258  SCIP_ROWPREP* rowprep, /**< data structure to store cut coefficients */
6259  SCIP_Bool* success /**< buffer to indicate whether a cut was successfully computed */
6260  )
6261 {
6262  SCIP_CONSDATA* consdata;
6263  SCIP_Real leftminactivity;
6264  SCIP_Real leftmaxactivity;
6265  SCIP_Real rightminactivity;
6266  SCIP_Real rightmaxactivity;
6267  SCIP_Real leftminactivityglobal;
6268  SCIP_Real leftmaxactivityglobal;
6269  SCIP_Real rightminactivityglobal;
6270  SCIP_Real rightmaxactivityglobal;
6271  SCIP_Real multleft;
6272  SCIP_Real multright;
6273  SCIP_Real rhs;
6274  int i;
6275 
6276  assert(scip != NULL);
6277  assert(cons != NULL);
6278  assert(ref != NULL);
6279  assert(rowprep != NULL);
6280  assert(success != NULL);
6281 
6282  consdata = SCIPconsGetData(cons);
6283  assert(consdata != NULL);
6284  assert(consdata->nlinvars == 0);
6285  assert(consdata->factorleft != NULL);
6286  assert(consdata->factorright != NULL);
6287 
6288  *success = FALSE;
6289 
6290  leftminactivityglobal = leftminactivity = consdata->factorleft[consdata->nquadvars];
6291  leftmaxactivityglobal = leftmaxactivity = consdata->factorleft[consdata->nquadvars];
6292  rightminactivityglobal = rightminactivity = consdata->factorright[consdata->nquadvars];
6293  rightmaxactivityglobal = rightmaxactivity = consdata->factorright[consdata->nquadvars];
6294  for( i = 0; i < consdata->nquadvars; ++i )
6295  {
6296  if( !SCIPisInfinity(scip, -leftminactivity) )
6297  {
6298  if( consdata->factorleft[i] > 0.0 )
6299  {
6300  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6301  leftminactivity = -SCIPinfinity(scip);
6302  else
6303  leftminactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6304  }
6305  else if( consdata->factorleft[i] < 0.0 )
6306  {
6307  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6308  leftminactivity = -SCIPinfinity(scip);
6309  else
6310  leftminactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6311  }
6312  }
6313  if( !SCIPisInfinity(scip, leftmaxactivity) )
6314  {
6315  if( consdata->factorleft[i] > 0.0 )
6316  {
6317  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6318  leftmaxactivity = SCIPinfinity(scip);
6319  else
6320  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6321  }
6322  else if( consdata->factorleft[i] < 0.0 )
6323  {
6324  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6325  leftmaxactivity = SCIPinfinity(scip);
6326  else
6327  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6328  }
6329  }
6330 
6331  if( !SCIPisInfinity(scip, -rightminactivity) )
6332  {
6333  if( consdata->factorright[i] > 0.0 )
6334  {
6335  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6336  rightminactivity = -SCIPinfinity(scip);
6337  else
6338  rightminactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6339  }
6340  else if( consdata->factorright[i] < 0.0 )
6341  {
6342  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6343  rightminactivity = -SCIPinfinity(scip);
6344  else
6345  rightminactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6346  }
6347  }
6348  if( !SCIPisInfinity(scip, rightmaxactivity) )
6349  {
6350  if( consdata->factorright[i] > 0.0 )
6351  {
6352  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6353  rightmaxactivity = SCIPinfinity(scip);
6354  else
6355  rightmaxactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6356  }
6357  else if( consdata->factorright[i] < 0.0 )
6358  {
6359  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6360  rightmaxactivity = SCIPinfinity(scip);
6361  else
6362  rightmaxactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6363  }
6364  }
6365 
6366  if( SCIPgetDepth(scip) > 0 )
6367  {
6368  if( !SCIPisInfinity(scip, -leftminactivityglobal) )
6369  {
6370  if( consdata->factorleft[i] > 0.0 )
6371  {
6372  if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(consdata->quadvarterms[i].var)) )
6373  leftminactivityglobal = -SCIPinfinity(scip);
6374  else
6375  leftminactivityglobal += consdata->factorleft[i] * SCIPvarGetLbGlobal(consdata->quadvarterms[i].var);
6376  }
6377  else if( consdata->factorleft[i] < 0.0 )
6378  {
6379  if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(consdata->quadvarterms[i].var)) )
6380  leftminactivityglobal = -SCIPinfinity(scip);
6381  else
6382  leftminactivityglobal += consdata->factorleft[i] * SCIPvarGetUbGlobal(consdata->quadvarterms[i].var);
6383  }
6384  }
6385  if( !SCIPisInfinity(scip, leftmaxactivityglobal) )
6386  {
6387  if( consdata->factorleft[i] > 0.0 )
6388  {
6389  if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(consdata->quadvarterms[i].var)) )
6390  leftmaxactivityglobal = SCIPinfinity(scip);
6391  else
6392  leftmaxactivityglobal += consdata->factorleft[i] * SCIPvarGetUbGlobal(consdata->quadvarterms[i].var);
6393  }
6394  else if( consdata->factorleft[i] < 0.0 )
6395  {
6396  if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(consdata->quadvarterms[i].var)) )
6397  leftmaxactivityglobal = SCIPinfinity(scip);
6398  else
6399  leftmaxactivityglobal += consdata->factorleft[i] * SCIPvarGetLbGlobal(consdata->quadvarterms[i].var);
6400  }
6401  }
6402 
6403  if( !SCIPisInfinity(scip, -rightminactivityglobal) )
6404  {
6405  if( consdata->factorright[i] > 0.0 )
6406  {
6407  if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(consdata->quadvarterms[i].var)) )
6408  rightminactivityglobal = -SCIPinfinity(scip);
6409  else
6410  rightminactivityglobal += consdata->factorright[i] * SCIPvarGetLbGlobal(consdata->quadvarterms[i].var);
6411  }
6412  else if( consdata->factorright[i] < 0.0 )
6413  {
6414  if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(consdata->quadvarterms[i].var)) )
6415  rightminactivityglobal = -SCIPinfinity(scip);
6416  else
6417  rightminactivityglobal += consdata->factorright[i] * SCIPvarGetUbGlobal(consdata->quadvarterms[i].var);
6418  }
6419  }
6420  if( !SCIPisInfinity(scip, rightmaxactivityglobal) )
6421  {
6422  if( consdata->factorright[i] > 0.0 )
6423  {
6424  if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(consdata->quadvarterms[i].var)) )
6425  rightmaxactivityglobal = SCIPinfinity(scip);
6426  else
6427  rightmaxactivityglobal += consdata->factorright[i] * SCIPvarGetUbGlobal(consdata->quadvarterms[i].var);
6428  }
6429  else if( consdata->factorright[i] < 0.0 )
6430  {
6431  if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(consdata->quadvarterms[i].var)) )
6432  rightmaxactivityglobal = SCIPinfinity(scip);
6433  else
6434  rightmaxactivityglobal += consdata->factorright[i] * SCIPvarGetLbGlobal(consdata->quadvarterms[i].var);
6435  }
6436  }
6437  }
6438  }
6439 
6440  /* write violated constraints as multleft * factorleft * factorright <= rhs */
6441  if( violside == SCIP_SIDETYPE_RIGHT )
6442  {
6443  rhs = consdata->rhs;
6444  multleft = 1.0;
6445  }
6446  else
6447  {
6448  rhs = -consdata->lhs;
6449  multleft = -1.0;
6450  }
6451 
6452  if( SCIPisZero(scip, rhs) )
6453  {
6454  /* @todo do something for rhs == 0.0? */
6455  return SCIP_OKAY;
6456  }
6457 
6458  if( !SCIPisFeasPositive(scip, leftminactivity) && !SCIPisFeasNegative(scip, leftmaxactivity) )
6459  {
6460  /* left factor has 0 within activity bounds, or is very close, at least */
6461  if( !SCIPisFeasPositive(scip, rightminactivity) && !SCIPisFeasNegative(scip, rightmaxactivity) )
6462  {
6463  /* right factor also has 0 within activity bounds, or is very close, at least
6464  * -> cannot separate
6465  */
6466  return SCIP_OKAY;
6467  }
6468 
6469  /* write violated constraint as multleft * factorleft * multright * (multright * factorright) <= rhs
6470  * such that multright * factorright > 0.0
6471  */
6472  if( rightminactivity < 0.0 )
6473  multright = -1.0;
6474  else
6475  multright = 1.0;
6476 
6477  /* generate cut for multleft * factorleft * multright <= rhs / (factorright * multright) */
6478  SCIP_CALL( generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorleft, multright, consdata->factorright, rightminactivity, rightmaxactivity, rhs, rowprep, success) );
6479 
6480  /* if right factor has 0 within global activity bounds, then the added linearization is not globally valid */
6481  if( rhs < 0.0 && SCIPgetDepth(scip) > 0 && rightminactivityglobal < 0.0 && rightmaxactivityglobal > 0.0 )
6482  rowprep->local = TRUE;
6483  }
6484  else if( !SCIPisFeasPositive(scip, rightminactivity) && !SCIPisFeasNegative(scip, rightmaxactivity) )
6485  {
6486  /* left factor is bounded away from 0
6487  * right factor has 0 within activity bounds, or is very close, at least
6488  * -> so divide by left factor
6489  */
6490 
6491  /* write violated constraint as multleft * factorright * multright * (multright * factorleft) <= rhs
6492  * such that multright * factorleft > 0.0
6493  */
6494  if( leftminactivity < 0.0 )
6495  multright = -1.0;
6496  else
6497  multright = 1.0;
6498 
6499  /* generate cut for multleft * factorright * multright <= rhs / (factorleft * multright) */
6500  SCIP_CALL( generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorright, multright, consdata->factorleft, leftminactivity, leftmaxactivity, rhs, rowprep, success) );
6501 
6502  /* if left factor has 0 within global activity bounds, then the added linearization is not globally valid */
6503  if( rhs < 0.0 && SCIPgetDepth(scip) > 0 && leftminactivityglobal < 0.0 && leftmaxactivityglobal > 0.0 )
6504  rowprep->local = TRUE;
6505  }
6506  else if( SCIPisInfinity(scip, -leftminactivity) || SCIPisInfinity(scip, leftmaxactivity) ||
6507  (!SCIPisInfinity(scip, -rightminactivity) && !SCIPisInfinity(scip, rightmaxactivity) && rightmaxactivity - rightminactivity < leftmaxactivity - leftminactivity) )
6508  {
6509  /* both factors are bounded away from 0, but the right one has a smaller activity range, so divide by that one */
6510 
6511  /* write violated constraint as multleft * factorleft * multright * (multright * factorright) <= rhs
6512  * such that multright * factorright > 0.0
6513  */
6514  if( rightminactivity < 0.0 )
6515  multright = -1.0;
6516  else
6517  multright = 1.0;
6518 
6519  /* generate cut for multleft * factorleft * multright <= rhs / (factorright * multright) */
6520  SCIP_CALL( generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorleft, multright, consdata->factorright, rightminactivity, rightmaxactivity, rhs, rowprep, success) );
6521 
6522  /* if right factor has 0 within global activity bounds, then the added linearization is not globally valid */
6523  if( rhs < 0.0 && SCIPgetDepth(scip) > 0 && rightminactivityglobal < 0.0 && rightmaxactivityglobal > 0.0 )
6524  rowprep->local = TRUE;
6525  }
6526  else
6527  {
6528  /* both factors are bounded away from 0, but the left one has a smaller activity range, so divide by that one */
6529 
6530  /* write violated constraint as multleft * factorright * multright * (multright * factorleft) <= rhs
6531  * such that multright * factorleft > 0.0
6532  */
6533  if( leftminactivity < 0.0 )
6534  multright = -1.0;
6535  else
6536  multright = 1.0;
6537 
6538  /* generate cut for multleft * factorright * multright <= rhs / (factorleft * multright) */
6539  SCIP_CALL( generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorright, multright, consdata->factorleft, leftminactivity, leftmaxactivity, rhs, rowprep, success) );
6540 
6541  /* if left factor has 0 within global activity bounds, then the added linearization is not globally valid */
6542  if( rhs < 0.0 && SCIPgetDepth(scip) > 0 && leftminactivityglobal < 0.0 && leftmaxactivityglobal > 0.0 )
6543  rowprep->local = TRUE;
6544  }
6545 
6546  return SCIP_OKAY;
6547 }
6548 
6549 /* finds intersections of a parametric line (x,y) = (x0,y0) + t [(x1,y1) - (x0,y0)] on curves x*y = wl and x*y = wu;
6550  * returns TRUE if unsuccessful and FALSE otherwise
6551  */
6552 static
6554  SCIP* scip,
6555  SCIP_Real x0,
6556  SCIP_Real y0_,
6557  SCIP_Real x1,
6558  SCIP_Real y1_,
6559  SCIP_Real wl,
6560  SCIP_Real wu,
6561  SCIP_Real* xl,
6562  SCIP_Real* yl,
6563  SCIP_Real* xu,
6564  SCIP_Real* yu
6565  )
6566 {
6567  SCIP_Real a;
6568  SCIP_Real b;
6569  SCIP_Real c;
6570  SCIP_Real tl;
6571  SCIP_Real tu;
6572 
6573  /* The parametric line is of the form
6574  *
6575  * x = x0 + t (x1-x0)
6576  * y = y0 + t (y1-y0)
6577  *
6578  * and for that to satisfy xy = wl and xy = wu we must have
6579  *
6580  * x0 y0 + t [x0 (y1-y0) + y0 (x1-x0)] + t^2 (x1-x0) (y1-y0) = wl
6581  * = wu
6582  *
6583  * or a t^2 + b t + c - wl = 0 for proper values of a,b,c.
6584  * a t^2 + b t + c - wu = 0
6585  *
6586  * Because of the way this procedure will be used, one of the two
6587  * solutions found we must always use the minimum nonnegative one
6588  */
6589 
6590  a = (x1 - x0) * (y1_ - y0_);
6591  c = x0 * y0_;
6592  b = x0 * y1_ + y0_ * x1 - 2.0 * c;
6593 
6594  tl = 0.0;
6595  tu = 0.0;
6596 
6597  if( !SCIPisZero(scip, (SCIP_Real)a) )
6598  {
6599  if( wl != SCIP_INVALID ) /*lint !e777 */
6600  {
6601  SCIP_Real tl1;
6602  SCIP_Real tl2;
6603  SCIP_Real denom;
6604  SCIP_Real q;
6605 
6606  if( b * b - 4.0 * a * (c - wl) < 0.0 )
6607  {
6608  SCIPdebugMsg(scip, "probable numerical difficulties, give up\n");
6609  return TRUE;
6610  }
6611 
6612  denom = sqrt(b * b - 4.0 * a * (c - wl));
6613  q = -0.5 * (b + COPYSIGN(denom, b));
6614  tl1 = q / a;
6615  tl2 = (c - wl) / q;
6616 
6617  /* choose the smallest non-negative root */
6618  tl = (tl1 >= 0.0 && (tl2 < 0.0 || tl1 < tl2)) ? tl1 : tl2;
6619  }
6620 
6621  if( wu != SCIP_INVALID ) /*lint !e777 */
6622  {
6623  SCIP_Real tu1;
6624  SCIP_Real tu2;
6625  SCIP_Real denom;
6626  SCIP_Real q;
6627 
6628  if( b * b - 4.0 * a * (c - wu) < 0.0 )
6629  {
6630  SCIPdebugMsg(scip, "probable numerical difficulties, give up\n");
6631  return TRUE;
6632  }
6633 
6634  denom = sqrt(b * b - 4.0 * a * (c - wu));
6635  q = -0.5 * (b + COPYSIGN(denom, b));
6636  tu1 = q / a;
6637  tu2 = (c - wu) / q;
6638 
6639  /* choose the smallest non-negative root */
6640  tu = (tu1 >= 0.0 && (tu2 < 0.0 || tu1 < tu2)) ? tu1 : tu2;
6641  }
6642  }
6643  else if( !SCIPisZero(scip, (SCIP_Real)b) )
6644  {
6645  if( wl != SCIP_INVALID ) /*lint !e777 */
6646  tl = (wl - c) / b;
6647  if( wu != SCIP_INVALID ) /*lint !e777 */
6648  tu = (wu - c) / b;
6649  }
6650  else
6651  {
6652  /* no or infinitely many solutions */
6653  return TRUE;
6654  }
6655 
6656  if( wl != SCIP_INVALID ) /*lint !e777 */
6657  {
6658  assert(xl != NULL);
6659  assert(yl != NULL);
6660 
6661  *xl = (SCIP_Real)(x0 + tl * (x1 - x0 ));
6662  *yl = (SCIP_Real)(y0_ + tl * (y1_ - y0_));
6663 
6664  if( SCIPisInfinity(scip, -*xl) || SCIPisInfinity(scip, -*yl) || !SCIPisRelEQ(scip, *xl * *yl, wl) )
6665  {
6666  SCIPdebugMsg(scip, "probable numerical difficulties, give up\n");
6667  return TRUE;
6668  }
6669  }
6670 
6671  if( wu != SCIP_INVALID ) /*lint !e777 */
6672  {
6673  assert(xu != NULL);
6674  assert(yu != NULL);
6675 
6676  *xu = (SCIP_Real)(x0 + tu * (x1 - x0));
6677  *yu = (SCIP_Real)(y0_ + tu * (y1_ - y0_));
6678 
6679  if( SCIPisInfinity(scip, *xu) || SCIPisInfinity(scip, *yu) || !SCIPisRelEQ(scip, *xu * *yu, wu) )
6680  {
6681  SCIPdebugMsg(scip, "probable numerical difficulties, give up\n");
6682  return TRUE;
6683  }
6684  }
6685 
6686  return FALSE;
6687 }
6688 
6689 /** generate coefficients for a plane through points (x1, y1_, x1*y1) and (x2, y2, x2*y2)
6690  * such that intersecting it with one of them (the first if whichuse is FALSE, the second otherwise)
6691  * gives a tangent to the curve x*y = k
6692  *
6693  * Returns TRUE on error and FALSE on success.
6694  */
6695 static
6697  SCIP* scip,
6698  SCIP_Real x1,
6699  SCIP_Real y1_,
6700  SCIP_Real x2,
6701  SCIP_Real y2,
6702  SCIP_Bool whichuse,
6703  SCIP_Real* cx,
6704  SCIP_Real* cy,
6705  SCIP_Real* cw
6706  )
6707 {
6708  SCIP_Real xd;
6709  SCIP_Real yd;
6710  SCIP_Real xo;
6711  SCIP_Real yo;
6712 
6713  assert(cx != NULL);
6714  assert(cy != NULL);
6715  assert(cw != NULL);
6716 
6717  /* the x-y slope of this constraint must be tangent to a curve x*y = k at (xD,yD) */
6718  if( !whichuse )
6719  {
6720  xd = x1;
6721  xo = x2;
6722  yd = y1_;
6723  yo = y2;
6724  }
6725  else
6726  {
6727  xd = x2;
6728  xo = x1;
6729  yd = y2;
6730  yo = y1_;
6731  }
6732 
6733  *cx = yd;
6734  *cy = xd;
6735 
6736  /* lift it so that it touches the other curve */
6737 
6738  /* if the two points are on the same curve, then no cut */
6739  if( SCIPisZero(scip, xo * yo - xd * yd) )
6740  return TRUE;
6741 
6742  /* should ALWAYS be negative */
6743  *cw = (2.0 * xd * yd - (*cx * xo + *cy * yo)) / (xo * yo - xd * yd);
6744 
6745  return FALSE;
6746 }
6747 
6748 /** computes coefficients of a lifted-tangent inequality for x*y = w
6749  *
6750  * The code is an adaptation of the methods in exprMul-upperHull.cpp in Couenne/stable/0.4 rev773,
6751  * written by P. Belotti and licensed under Eclipse Public License.
6752  */
6753 static
6755  SCIP* scip, /**< SCIP data structure */
6756  SCIP_Real xl, /**< lower bound on x */
6757  SCIP_Real xu, /**< upper bound on x */
6758  SCIP_Real x0, /**< reference point for x */
6759  SCIP_Real yl, /**< lower bound on y */
6760  SCIP_Real yu, /**< upper bound on y */
6761  SCIP_Real y0_, /**< reference point for y */
6762  SCIP_Real wl, /**< lower bound on w */
6763  SCIP_Real wu, /**< upper bound on w */
6764  SCIP_Real w0, /**< reference point for w */
6765  SCIP_Real* cx, /**< buffer where to store cut coefficient for x */
6766  SCIP_Real* cy, /**< buffer where to store cut coefficient for y */
6767  SCIP_Real* cw, /**< buffer where to store cut coefficient for w */
6768  SCIP_Real* c0, /**< buffer where to store cut left-hand-side */
6769  SCIP_Bool* success /**< buffer where to indicate whether cut coefficients were computed */
6770  )
6771 {
6772  SCIP_Bool flipx;
6773  SCIP_Bool flipy;
6774  SCIP_Bool flipw;
6775  SCIP_Real tmp;
6776  SCIP_Real xlow = 0.0;
6777  SCIP_Real ylow = 0.0;
6778  SCIP_Real xupp = 0.0;
6779  SCIP_Real yupp = 0.0;
6780  SCIP_Real c0x;
6781  SCIP_Real c0y;
6782  SCIP_Real c0w;
6783 
6784  assert(scip != NULL);
6785  assert(cx != NULL);
6786  assert(cy != NULL);
6787  assert(cw != NULL);
6788  assert(c0 != NULL);
6789  assert(success != NULL);
6790 
6791  *success = FALSE;
6792  *cx = 0.0;
6793  *cy = 0.0;
6794  *cw = 0.0;
6795  *c0 = 0.0;
6796 
6797  SCIPdebugMsg(scip, "entering points:\n");
6798  SCIPdebugMsg(scip, "x: %9g\t[%9g\t%9g]\n", x0, xl, xu);
6799  SCIPdebugMsg(scip, "y: %9g\t[%9g\t%9g]\n", y0_, yl, yu);
6800  SCIPdebugMsg(scip, "w: %9g\t[%9g\t%9g]\n", w0, wl, wu);
6801 
6802  /* generateCutLTI should have recognized these */
6803  assert(wl >= 0.0 || wu <= 0.0);
6804  assert(!SCIPisInfinity(scip, -wl));
6805  assert(!SCIPisInfinity(scip, wu));
6806 
6807  assert(SCIPisFeasGE(scip, x0, xl));
6808  assert(SCIPisFeasLE(scip, x0, xu));
6809  assert(SCIPisFeasGE(scip, y0_, yl));
6810  assert(SCIPisFeasLE(scip, y0_, yu));
6811 
6812  /* preliminary bound tightening */
6813  if( wl >= 0.0 )
6814  {
6815  if( xl >= 0.0 || yl >= 0.0 || SCIPisLT(scip, xl * yl, wl) )
6816  {
6817  xl = MAX(xl, 0.0);
6818  yl = MAX(yl, 0.0);
6819  }
6820  else if( xu <= 0.0 || yu <= 0.0 || SCIPisLT(scip, xu * yu, wl) )
6821  {
6822  xu = MIN(xu, 0.0);
6823  yu = MIN(yu, 0.0);
6824  }
6825  else
6826  {
6827  /* both variables have mixed sign (xl < 0 && xu > 0 && yl < 0 && yu > 0) and both xl*yl and xu*yu are feasible
6828  * cannot generate cut for this
6829  */
6830  return;
6831  }
6832  }
6833  else
6834  {
6835  if( xl >= 0.0 || yu <= 0.0 || SCIPisGT(scip, xl * yu, wu) )
6836  {
6837  xl = MAX(xl, 0.0);
6838  yu = MIN(yu, 0.0);
6839  }
6840  else if( xu <= 0.0 || yl >= 0.0 || SCIPisGT(scip, xu * yl, wu))
6841  {
6842  xu = MIN(xu, 0.0);
6843  yl = MAX(yl, 0.0);
6844  }
6845  else
6846  {
6847  /* both variables have mixed sign (xl < 0 && xu > 0 && yl < 0 && yu > 0) and both xl*yu and xu*yl are feasible
6848  * cannot generate cut for this
6849  */
6850  return;
6851  }
6852  }
6853 
6854  /* if x or y is fixed now or even infeasible, then do not think about a cut */
6855  if( SCIPisGE(scip, xl, xu) || SCIPisGE(scip, yl, yu) )
6856  return;
6857 
6858  /* reduce to positive orthant by flipping variables */
6859  if( xl < 0.0 )
6860  {
6861  flipx = TRUE;
6862  tmp = xu;
6863  xu = -xl;
6864  xl = -tmp;
6865  x0 = -x0;
6866  }
6867  else
6868  flipx = FALSE;
6869 
6870  if( yl < 0.0 )
6871  {
6872  flipy = TRUE;
6873  tmp = yu;
6874  yu = -yl;
6875  yl = -tmp;
6876  y0_ = -y0_;
6877  }
6878  else
6879  flipy = FALSE;
6880 
6881  if( flipx ^ flipy )
6882  {
6883  flipw = TRUE;
6884  tmp = wu;
6885  wu = -wl;
6886  wl = -tmp;
6887  w0 = -w0;
6888  }
6889  else
6890  flipw = FALSE;
6891 
6892  /* project refpoint into box not only for numerical reasons, but also due to preliminary bound tightening above */
6893  x0 = MIN(xu, MAX(x0, xl));
6894  y0_ = MIN(yu, MAX(y0_, yl));
6895  w0 = MIN(wu, MAX(w0, wl));
6896 
6897  SCIPdebugMsg(scip, "reduced points:\n");
6898  SCIPdebugMsg(scip, "x: %9g\t[%9g\t%9g]\n", x0, xl, xu);
6899  SCIPdebugMsg(scip, "y: %9g\t[%9g\t%9g]\n", y0_, yl, yu);
6900  SCIPdebugMsg(scip, "w: %9g\t[%9g\t%9g]\n", w0, wl, wu);
6901 
6902  if( SCIPisGE(scip, xl * yl, wl) && SCIPisLE(scip, xu * yu, wu) )
6903  {
6904  SCIPdebugMsg(scip, "box for x and y inside feasible region -> nothing to separate\n");
6905  return;
6906  }
6907  if( SCIPisGE(scip, x0 * y0_, w0) )
6908  {
6909  SCIPdebugMsg(scip, "point to separate not below curve -> cannot separate\n");
6910  return;
6911  }
6912 
6913  /* find intersections of halfline from origin
6914  * return if no proper point could be found
6915  */
6916  if( generateCutLTIfindIntersection(scip, 0.0, 0.0, x0, y0_, wl, wu, &xlow, &ylow, &xupp, &yupp) )
6917  return;
6918 
6919  SCIPdebugMsg(scip, "intersections:\n");
6920  SCIPdebugMsg(scip, "lower: %9g\t%9g\tprod %9g\n", xlow, ylow, xlow*ylow);
6921  SCIPdebugMsg(scip, "upper: %9g\t%9g\tprod %9g\n", xupp, yupp, xupp*yupp);
6922 
6923  /* Case 1: If both are outside of bounding box, either NW or SE, then McCormick is sufficient, so return */
6924  if( (xlow <= xl && yupp >= yu) || (ylow <= yl && xupp >= xu) )
6925  return;
6926 
6927  /* There will be at least one cut. Define coefficients and rhs ---will have to change them back if (flipX || flipY) */
6928  if( xlow >= xl && xupp <= xu && ylow >= yl && yupp <= yu )
6929  {
6930  /* Case 2: both are inside. Easy lifting... */
6931  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, FALSE, cx, cy, cw) )
6932  return;
6933 
6934  c0x = *cx * xlow;
6935  c0y = *cy * ylow;
6936  c0w = *cw * wl;
6937  }
6938  else if( xlow >= xl && ylow >= yl && (xupp > xu || yupp > yu) )
6939  {
6940  /* Case 3a and 3b: through lower curve, but not upper. */
6941  if( yupp > yu )
6942  {
6943  /* upper intersect is North; place it within box */
6944  assert(!SCIPisInfinity(scip, yu));
6945  yupp = yu;
6946  xupp = wu / yu;
6947  }
6948  else
6949  {
6950  /* upper intersect is East; place it within box */
6951  assert(!SCIPisInfinity(scip, xu));
6952  xupp = xu;
6953  yupp = wu / xu;
6954  }
6955 
6956  /* find intersection on low curve on half line through new point and (x0,y0_) */
6957  if( generateCutLTIfindIntersection(scip, xupp, yupp, x0, y0_, wl, SCIP_INVALID, &xlow, &ylow, NULL, NULL) )
6958  return;
6959 
6960  /* check whether McCormick is sufficient */
6961  if( xlow < xl || ylow < yl )
6962  return;
6963 
6964  /* lift inequality on lower point */
6965  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, FALSE, cx, cy, cw) )
6966  return;
6967 
6968  c0x = *cx * xlow;
6969  c0y = *cy * ylow;
6970  c0w = *cw * wl;
6971  }
6972  else if( xupp <= xu && yupp <= yu && (xlow < xl || ylow < yl) )
6973  {
6974  /* Case 4a and 4b: viceversa (lift for validity) */
6975  if( ylow < yl )
6976  {
6977  /* upper intersect is South; place it within box */
6978  assert(!SCIPisZero(scip, yl));
6979  ylow = yl;
6980  xlow = wl / yl;
6981  }
6982  else
6983  {
6984  /* upper intersect is West; place it within box */
6985  assert(!SCIPisZero(scip, xl));
6986  xlow = xl;
6987  ylow = wl / xl;
6988  }
6989 
6990  /* find intersection on low curve on half line through new point and (x0,y0) */
6991  if( generateCutLTIfindIntersection(scip, xlow, ylow, x0, y0_, SCIP_INVALID, wu, NULL, NULL, &xupp, &yupp) )
6992  return;
6993 
6994  /* check whether McCormick is sufficient */
6995  if( xupp > xu || yupp > yu )
6996  return;
6997 
6998  /* lift inequality on UPPER point */
6999  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, TRUE, cx, cy, cw) )
7000  return;
7001 
7002  c0x = *cx * xupp;
7003  c0y = *cy * yupp;
7004  c0w = *cw * wu;
7005  }
7006  else if( (xlow < xl && xupp > xu) || (ylow < yl && yupp > yu) )
7007  {
7008  /* Case 5: both outside of bounding box, N and S or W and E. */
7009 #ifdef SCIP_DISABLED_CODE
7010  SCIP_Real xlow2;
7011  SCIP_Real ylow2;
7012  SCIP_Real xupp2;
7013  SCIP_Real yupp2;
7014 #endif
7015 
7016  if( ylow < yl )
7017  {
7018  /* upper intersect is South; place it within box */
7019  assert(!SCIPisZero(scip, yl));
7020  assert(!SCIPisZero(scip, yu));
7021  ylow = yl;
7022  yupp = yu;
7023  xlow = wl / yl;
7024  xupp = wu / yu;
7025  }
7026  else
7027  {
7028  /* upper intersect is West; place it within box */
7029  assert(!SCIPisZero(scip, xl));
7030  assert(!SCIPisZero(scip, xu));
7031  xlow = xl;
7032  xupp = xu;
7033  ylow = wl / xl;
7034  yupp = wu / xu;
7035  }
7036 
7037  SCIPdebugMsg(scip, "New intersections:\n");
7038  SCIPdebugMsg(scip, "lower: %9g\t%9g\tprod %9g\n", xlow, ylow, xlow*ylow);
7039  SCIPdebugMsg(scip, "upper: %9g\t%9g\tprod %9g\n", xupp, yupp, xupp*yupp);
7040 
7041 #ifndef SCIP_DISABLED_CODE
7042  /* Nothing to find. Just separate two inequalities at the same point, just using different support */
7043  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, FALSE, cx, cy, cw) )
7044  {
7045  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, TRUE, cx, cy, cw) )
7046  return;
7047 
7048  c0x = *cx * xupp;
7049  c0y = *cy * yupp;
7050  c0w = *cw * wu;
7051  }
7052  else
7053  {
7054  c0x = *cx * xlow;
7055  c0y = *cy * ylow;
7056  c0w = *cw * wl;
7057  }
7058 
7059 #else
7060  /* find the intersection on the lower (upper) curve on the line through xLP and the upper (lower) point
7061  * this does not seem to work (cuts off solution at nous2), so it is disabled for now
7062  */
7063  if( generateCutLTIfindIntersection(scip, xlow, ylow, x0, y0_, SCIP_INVALID, wu, NULL, NULL, &xupp2, &yupp2) ||
7064  generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp2, yupp2, FALSE, cx, cx, cw) )
7065  {
7066  if( generateCutLTIfindIntersection(scip, xupp, yupp, x0, y0_, wl, SCIP_INVALID, &xlow2, &ylow2, NULL, NULL) ||
7067  generateCutLTIgenMulCoeff(scip, xlow2, ylow2, xupp, yupp, TRUE, cx, cy, cw) )
7068  return;
7069 
7070  c0x = *cx * xupp;
7071  c0y = *cy * yupp;
7072  c0w = *cw * wu;
7073  }
7074  else
7075  {
7076  c0x = *cx * xlow;
7077  c0y = *cy * ylow;
7078  c0w = *cw * wl;
7079  }
7080 #endif
7081  }
7082  else
7083  {
7084  SCIPdebugMsg(scip, "points are in a weird position:\n");
7085  SCIPdebugMsg(scip, "lower: %9g\t%9g\tprod %9g\n", xlow, ylow, xlow*ylow);
7086  SCIPdebugMsg(scip, "upper: %9g\t%9g\tprod %9g\n", xupp, yupp, xupp*yupp);
7087 
7088  return;
7089  }
7090 
7091  SCIPdebugMsg(scip, "cut w.r.t. reduced points: %gx-%g %+gy-%g %+gw-%g >= 0\n",
7092  *cx, c0x, *cy, c0y, *cw, c0w);
7093 
7094  /* re-transform back into original variables */
7095  if( flipx )
7096  *cx = -*cx;
7097  if( flipy )
7098  *cy = -*cy;
7099  if( flipw )
7100  *cw = -*cw;
7101 
7102  *c0 = c0x + c0y + c0w;
7103 
7104  *success = TRUE;
7105 }
7106 
7107 /** tries to generate a cut if constraint quadratic function is factorable and there are linear variables
7108  *
7109  * Computes what is called a lifted tangent inequality described in@n
7110  * Belotti, Miller, Namazifar, Lifted inequalities for bounded products of variables, SIAG/OPT Views-and-News 22:1, 2011
7111  */
7112 static
7114  SCIP* scip, /**< SCIP data structure */
7115  SCIP_CONS* cons, /**< constraint */
7116  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
7117  SCIP_Real* ref, /**< reference solution where to generate the cut */
7118  SCIP_SOL* sol, /**< solution that shall be cutoff, NULL for LP solution */
7119  SCIP_ROWPREP* rowprep, /**< rowprep to store cut data */
7120  SCIP_Bool* success /**< buffer to indicate whether a cut was successfully computed */
7121  )
7122 {
7123  SCIP_CONSDATA* consdata;
7124  SCIP_Real leftminactivity;
7125  SCIP_Real leftmaxactivity;
7126  SCIP_Real leftrefactivity;
7127  SCIP_Real rightminactivity;
7128  SCIP_Real rightmaxactivity;
7129  SCIP_Real rightrefactivity;
7130  SCIP_Real rhsminactivity;
7131  SCIP_Real rhsmaxactivity;
7132  SCIP_Real rhsrefactivity;
7133  SCIP_Real coefleft;
7134  SCIP_Real coefright;
7135  SCIP_Real coefrhs;
7136  SCIP_Real cutlhs;
7137  int i;
7138 
7139  assert(scip != NULL);
7140  assert(cons != NULL);
7141  assert(ref != NULL);
7142  assert(rowprep != NULL);
7143  assert(success != NULL);
7144  /* currently only separate LP solution or solutions given as SCIP_SOL, i.e., no cutgeneration during initlp */
7145  assert(sol != NULL || SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL);
7146 
7147  consdata = SCIPconsGetData(cons);
7148  assert(consdata != NULL);
7149  assert(consdata->nlinvars > 0);
7150  assert(consdata->factorleft != NULL);
7151  assert(consdata->factorright != NULL);
7152 
7153  *success = FALSE;
7154  rowprep->sidetype = SCIP_SIDETYPE_LEFT;
7155 
7156  /* write violated constraints as factorleft * factorright '==' rhs
7157  * where rhs are constraint sides - activity bound of linear part
7158  */
7159  rhsminactivity = consdata->lhs;
7160  rhsmaxactivity = consdata->rhs;
7161  rhsrefactivity = (violside == SCIP_SIDETYPE_LEFT ? consdata->lhs : consdata->rhs);
7162 
7163  for( i = 0; i < consdata->nlinvars; ++i )
7164  {
7165  if( !SCIPisInfinity(scip, -rhsminactivity) )
7166  {
7167  if( consdata->lincoefs[i] < 0.0 )
7168  {
7169  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i])) )
7170  rhsminactivity = -SCIPinfinity(scip);
7171  else
7172  rhsminactivity -= consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
7173  }
7174  else
7175  {
7176  assert(consdata->lincoefs[i] > 0.0);
7177  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i])) )
7178  rhsminactivity = -SCIPinfinity(scip);
7179  else
7180  rhsminactivity -= consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
7181  }
7182  }
7183  if( !SCIPisInfinity(scip, rhsmaxactivity) )
7184  {
7185  if( consdata->lincoefs[i] < 0.0 )
7186  {
7187  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i])) )
7188  rhsmaxactivity = SCIPinfinity(scip);
7189  else
7190  rhsmaxactivity -= consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
7191  }
7192  else
7193  {
7194  assert(consdata->lincoefs[i] > 0.0);
7195  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i])) )
7196  rhsmaxactivity = SCIPinfinity(scip);
7197  else
7198  rhsmaxactivity -= consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
7199  }
7200  }
7201  rhsrefactivity -= consdata->lincoefs[i] * SCIPgetSolVal(scip, sol, consdata->linvars[i]);
7202  }
7203 
7204  if( SCIPisInfinity(scip, -rhsminactivity) || SCIPisInfinity(scip, rhsmaxactivity) )
7205  {
7206  /* if right hand side is unbounded, then cannot do LTI */
7207  return SCIP_OKAY;
7208  }
7209 
7210  if( !SCIPisFeasPositive(scip, rhsminactivity) && !SCIPisFeasNegative(scip, rhsmaxactivity) )
7211  {
7212  /* if right hand side has 0 inside activity, then cannot do anything
7213  * if it has 0.0 as min or max activity, then a usual McCormick should be sufficient, too
7214  */
7215  return SCIP_OKAY;
7216  }
7217 
7218  leftminactivity = consdata->factorleft[consdata->nquadvars];
7219  leftmaxactivity = consdata->factorleft[consdata->nquadvars];
7220  leftrefactivity = consdata->factorleft[consdata->nquadvars];
7221  rightminactivity = consdata->factorright[consdata->nquadvars];
7222  rightmaxactivity = consdata->factorright[consdata->nquadvars];
7223  rightrefactivity = consdata->factorright[consdata->nquadvars];
7224  for( i = 0; i < consdata->nquadvars; ++i )
7225  {
7226  if( !SCIPisInfinity(scip, -leftminactivity) )
7227  {
7228  if( consdata->factorleft[i] > 0.0 )
7229  {
7230  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
7231  leftminactivity = -SCIPinfinity(scip);
7232  else
7233  leftminactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
7234  }
7235  else if( consdata->factorleft[i] < 0.0 )
7236  {
7237  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
7238  leftminactivity = -SCIPinfinity(scip);
7239  else
7240  leftminactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
7241  }
7242  }
7243  if( !SCIPisInfinity(scip, leftmaxactivity) )
7244  {
7245  if( consdata->factorleft[i] > 0.0 )
7246  {
7247  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
7248  leftmaxactivity = SCIPinfinity(scip);
7249  else
7250  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
7251  }
7252  else if( consdata->factorleft[i] < 0.0 )
7253  {
7254  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
7255  leftmaxactivity = SCIPinfinity(scip);
7256  else
7257  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
7258  }
7259  }
7260  leftrefactivity += consdata->factorleft[i] * ref[i];
7261 
7262  if( !SCIPisInfinity(scip, -rightminactivity) )
7263  {
7264  if( consdata->factorright[i] > 0.0 )
7265  {
7266  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
7267  rightminactivity = -SCIPinfinity(scip);
7268  else
7269  rightminactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
7270  }
7271  else if( consdata->factorright[i] < 0.0 )
7272  {
7273  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
7274  rightminactivity = -SCIPinfinity(scip);
7275  else
7276  rightminactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
7277  }
7278  }
7279  if( !SCIPisInfinity(scip, rightmaxactivity) )
7280  {
7281  if( consdata->factorright[i] > 0.0 )
7282  {
7283  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
7284  rightmaxactivity = SCIPinfinity(scip);
7285  else
7286  rightmaxactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
7287  }
7288  else if( consdata->factorright[i] < 0.0 )
7289  {
7290  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
7291  rightmaxactivity = SCIPinfinity(scip);
7292  else
7293  rightmaxactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
7294  }
7295  }
7296  rightrefactivity += consdata->factorright[i] * ref[i];
7297  }
7298 
7299  /* if activities exceed "opposite" infinity, huge bounds seem to be involved, for which the below method is not prepared */
7300  if( SCIPisInfinity(scip, leftminactivity) || SCIPisInfinity(scip, -leftmaxactivity) ||
7301  SCIPisInfinity(scip, rightminactivity) || SCIPisInfinity(scip, -rightmaxactivity) )
7302  return SCIP_OKAY;
7303 
7304  /* if activity in reference point exceeds value for infinity, then the below method will also not work properly */
7305  if( SCIPisInfinity(scip, REALABS(leftrefactivity)) || SCIPisInfinity(scip, REALABS(rightrefactivity)) )
7306  return SCIP_OKAY;
7307 
7308  /* if any of the factors is essentially fixed, give up and do usual method (numerically less sensitive, I hope) */
7309  if( SCIPisRelEQ(scip, leftminactivity, leftmaxactivity) || SCIPisRelEQ(scip, rightminactivity, rightmaxactivity) )
7310  return SCIP_OKAY;
7311 
7312  /* success can only be expected for separation of violated x*y <= w, assuming x>=0, y>=0
7313  * @todo we should check this early? */
7314 
7315  /* call Couenne magic */
7317  leftminactivity, leftmaxactivity, leftrefactivity,
7318  rightminactivity, rightmaxactivity, rightrefactivity,
7319  rhsminactivity, rhsmaxactivity, rhsrefactivity,
7320  &coefleft, &coefright, &coefrhs, &cutlhs,
7321  success);
7322 
7323  if( !*success )
7324  return SCIP_OKAY;
7325 
7326  SCIPdebugMsg(scip, "LTI for x[%g,%g] * y[%g,%g] = w[%g,%g]: %gx %+gy %+gw >= %g; feas: %g\n",
7327  leftminactivity, leftmaxactivity, rightminactivity, rightmaxactivity, rhsminactivity, rhsmaxactivity,
7328  coefleft, coefright, coefrhs, cutlhs,
7329  coefleft * leftrefactivity + coefright * rightrefactivity + coefrhs * rhsrefactivity - cutlhs
7330  );
7331 
7332  if( coefleft * leftrefactivity + coefright * rightrefactivity + coefrhs * rhsrefactivity >= cutlhs )
7333  {
7334  SCIPdebugMsg(scip, "does not cutoff point? :-(\n");
7335  *success = FALSE;
7336  return SCIP_OKAY;
7337  }
7338 
7339  /* setup cut coefs for
7340  * coefleft * leftfactor + coefright * rightfactor + coefrhs * w >= cutlhs, where conslhs - lincoefs <= w <= consrhs - lincoefs
7341  */
7342  for( i = 0; i < consdata->nquadvars; ++i )
7343  {
7344  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, consdata->quadvarterms[i].var, coefleft * consdata->factorleft[i] + coefright * consdata->factorright[i]) );
7345  }
7346  SCIPaddRowprepConstant(rowprep, coefleft * consdata->factorleft[i] + coefright * consdata->factorright[i]);
7347 
7348  for( i = 0; i < consdata->nlinvars; ++i )
7349  {
7350  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, consdata->linvars[i], -coefrhs * consdata->lincoefs[i]) );
7351  }
7352  if( coefrhs > 0.0 )
7353  {
7354  /* use coefrhs * w <= coefrhs * (consrhs - lincoefs) */
7355  assert(!SCIPisInfinity(scip, consdata->rhs));
7356  SCIPaddRowprepConstant(rowprep, coefrhs * consdata->rhs);
7357  }
7358  else
7359  {
7360  /* use coefrhs * w <= coeflhs * (conslhs - lincoefs) */
7361  assert(!SCIPisInfinity(scip, -consdata->lhs));
7362  SCIPaddRowprepConstant(rowprep, coefrhs * consdata->lhs);
7363  }
7364  SCIPaddRowprepSide(rowprep, cutlhs);
7365 
7366  rowprep->local = TRUE;
7367 
7368  (void) SCIPsnprintf(rowprep->name, SCIP_MAXSTRLEN, "%s_lti_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
7369 
7370  *success = TRUE;
7371 
7372  return SCIP_OKAY;
7373 }
7374 
7375 /** computes cut coefficients by linearizing a quadratic function */
7376 static
7378  SCIP* scip, /**< SCIP data structure */
7379  SCIP_CONS* cons, /**< constraint */
7380  SCIP_SIDETYPE violside, /**< side for which to generate cut */
7381  SCIP_Real* ref, /**< reference solution where to generate the cut */
7382  SCIP_ROWPREP* rowprep, /**< rowprep to store cut data */
7383  SCIP_Bool* success /**< buffer to indicate whether a cut was successfully computed */
7384  )
7385 {
7386  SCIP_CONSDATA* consdata;
7387  SCIP_BILINTERM* bilinterm;
7388  SCIP_Real constant;
7389  SCIP_Real coef;
7390  SCIP_Real coef2;
7391  SCIP_VAR* var;
7392  int var2pos;
7393  int j;
7394  int k;
7395 
7396  assert(scip != NULL);
7397  assert(cons != NULL);
7398  assert(ref != NULL);
7399  assert(success != NULL);
7400 
7401  consdata = SCIPconsGetData(cons);
7402  assert(consdata != NULL);
7403 
7404  *success = TRUE;
7405 
7406  /* do first-order Taylor for each term */
7407  for( j = 0; j < consdata->nquadvars && *success; ++j )
7408  {
7409  var = consdata->quadvarterms[j].var;
7410 
7411  /* initialize coefficients to linear coefficients of quadratic variables */
7412  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, consdata->quadvarterms[j].lincoef) );
7413 
7414  /* add linearization of square term */
7415  coef = 0.0;
7416  constant = 0.0;
7417  SCIPaddSquareLinearization(scip, consdata->quadvarterms[j].sqrcoef, ref[j],
7418  consdata->quadvarterms[j].nadjbilin == 0 && SCIPvarGetType(var) < SCIP_VARTYPE_CONTINUOUS, &coef, &constant, success);
7419  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, coef) );
7420  SCIPaddRowprepConstant(rowprep, constant);
7421 
7422  /* add linearization of bilinear terms that have var as first variable */
7423  for( k = 0; k < consdata->quadvarterms[j].nadjbilin && *success; ++k )
7424  {
7425  bilinterm = &consdata->bilinterms[consdata->quadvarterms[j].adjbilin[k]];
7426  if( bilinterm->var1 != var )
7427  continue;
7428  assert(bilinterm->var2 != var);
7429  assert(consdata->sepabilinvar2pos != NULL);
7430 
7431  var2pos = consdata->sepabilinvar2pos[consdata->quadvarterms[j].adjbilin[k]];
7432  assert(var2pos >= 0);
7433  assert(var2pos < consdata->nquadvars);
7434  assert(consdata->quadvarterms[var2pos].var == bilinterm->var2);
7435 
7436  coef = 0.0;
7437  coef2 = 0.0;
7438  constant = 0.0;
7439  SCIPaddBilinLinearization(scip, bilinterm->coef, ref[j], ref[var2pos], &coef, &coef2, &constant, success);
7440  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, coef) );
7441  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, bilinterm->var2, coef2) );
7442  SCIPaddRowprepConstant(rowprep, constant);
7443  }
7444  }
7445 
7446  if( !*success )
7447  {
7448  SCIPdebugMsg(scip, "no success in linearization of <%s> in reference point\n", SCIPconsGetName(cons));
7449  return SCIP_OKAY;
7450  }
7451 
7452  rowprep->sidetype = violside;
7453  SCIPaddRowprepSide(rowprep, violside == SCIP_SIDETYPE_LEFT ? consdata->lhs : consdata->rhs);
7454 
7455  (void) SCIPsnprintf(rowprep->name, SCIP_MAXSTRLEN, "%s_side%d_linearization_%d", SCIPconsGetName(cons), violside, SCIPgetNLPs(scip));
7456 
7457  return SCIP_OKAY;
7458 }
7459 
7460 /** helper function to update the best relaxation for a bilinear term when using valid linear inequalities */
7461 static
7463  SCIP* scip, /**< SCIP data structure */
7464  SCIP_VAR* RESTRICT x, /**< first variable */
7465  SCIP_VAR* RESTRICT y, /**< second variable */
7466  SCIP_Real bilincoef, /**< coefficient of the bilinear term */
7467  SCIP_SIDETYPE violside, /**< side of quadratic constraint that is violated */
7468  SCIP_Real refx, /**< reference point for the x variable */
7469  SCIP_Real refy, /**< reference point for the y variable */
7470  SCIP_Real* RESTRICT ineqs, /**< coefficients of each linear inequality; stored as triple (xcoef,ycoef,constant) */
7471  int nineqs, /**< total number of inequalities */
7472  SCIP_Real mccormickval, /**< value of the McCormick relaxation at the reference point */
7473  SCIP_Real* RESTRICT bestcoefx, /**< pointer to update the x coefficient */
7474  SCIP_Real* RESTRICT bestcoefy, /**< pointer to update the y coefficient */
7475  SCIP_Real* RESTRICT bestconst, /**< pointer to update the constant */
7476  SCIP_Real* RESTRICT bestval, /**< value of the best relaxation that have been found so far */
7477  SCIP_Bool* success /**< buffer to store whether we found a better relaxation */
7478  )
7479 {
7480  SCIP_Real constshift[2] = {0.0, 0.0};
7481  SCIP_Real constant;
7482  SCIP_Real xcoef;
7483  SCIP_Real ycoef;
7484  SCIP_Real lbx;
7485  SCIP_Real ubx;
7486  SCIP_Real lby;
7487  SCIP_Real uby;
7488  SCIP_Bool update;
7489  SCIP_Bool overestimate;
7490  int i;
7491 
7492  assert(x != y);
7493  assert(!SCIPisZero(scip, bilincoef));
7494  assert(nineqs >= 0 && nineqs <= 2);
7495  assert(bestcoefx != NULL);
7496  assert(bestcoefy != NULL);
7497  assert(bestconst != NULL);
7498  assert(bestval != NULL);
7499 
7500  /* no inequalities available */
7501  if( nineqs == 0 )
7502  return;
7503  assert(ineqs != NULL);
7504 
7505  lbx = SCIPvarGetLbLocal(x);
7506  ubx = SCIPvarGetUbLocal(x);
7507  lby = SCIPvarGetLbLocal(y);
7508  uby = SCIPvarGetUbLocal(y);
7509  overestimate = (violside == SCIP_SIDETYPE_LEFT);
7510 
7511  /* check cases for which we can't compute a tighter relaxation */
7512  if( SCIPisFeasLE(scip, refx, lbx) || SCIPisFeasGE(scip, refx, ubx)
7513  || SCIPisFeasLE(scip, refy, lby) || SCIPisFeasGE(scip, refy, uby) )
7514  return;
7515 
7516  /* due to the feasibility tolerances of the LP and NLP solver, it might possible that the reference point is
7517  * violating the linear inequalities; to ensure that we compute a valid underestimate, we relax the linear
7518  * inequality by changing its constant part
7519  */
7520  for( i = 0; i < nineqs; ++i )
7521  {
7522  constshift[i] = MAX(0.0, ineqs[3*i] * refx - ineqs[3*i+1] * refy - ineqs[3*i+2]);
7523  SCIPdebugMsg(scip, "constant shift of inequality %d = %.16f\n", constshift[i]);
7524  }
7525 
7526  /* try to use both inequalities */
7527  if( nineqs == 2 )
7528  {
7529  SCIPcomputeBilinEnvelope2(scip, bilincoef, lbx, ubx, refx, lby, uby, refy, overestimate, ineqs[0], ineqs[1],
7530  ineqs[2] + constshift[0], ineqs[3], ineqs[4], ineqs[5] + constshift[1], &xcoef, &ycoef, &constant, &update);
7531 
7532  if( update )
7533  {
7534  SCIP_Real val = xcoef * refx + ycoef * refy + constant;
7535  SCIP_Real relimpr = 1.0 - (REALABS(val - bilincoef * refx * refy) + 1e-4) / (REALABS(*bestval - bilincoef * refx * refy) + 1e-4);
7536  SCIP_Real absimpr = REALABS(val - (*bestval));
7537 
7538  /* update relaxation if possible */
7539  if( relimpr > 0.05 && absimpr > 1e-3 && ((overestimate && SCIPisRelLT(scip, val, *bestval)) || (!overestimate && SCIPisRelGT(scip, val, *bestval))) )
7540  {
7541  *bestcoefx = xcoef;
7542  *bestcoefy = ycoef;
7543  *bestconst = constant;
7544  *bestval = val;
7545  *success = TRUE;
7546  }
7547  }
7548  }
7549 
7550  /* use inequalities individually */
7551  for( i = 0; i < nineqs; ++i )
7552  {
7553  SCIPcomputeBilinEnvelope1(scip, bilincoef, lbx, ubx, refx, lby, uby, refy, overestimate, ineqs[3*i], ineqs[3*i+1],
7554  ineqs[3*i+2] + constshift[i], &xcoef, &ycoef, &constant, &update);
7555 
7556  if( update )
7557  {
7558  SCIP_Real val = xcoef * refx + ycoef * refy + constant;
7559  SCIP_Real relimpr = 1.0 - (REALABS(val - bilincoef * refx * refy) + 1e-4) / (REALABS(mccormickval - bilincoef * refx * refy) + 1e-4);
7560  SCIP_Real absimpr = REALABS(val - (*bestval));
7561 
7562  /* update relaxation if possible */
7563  if( relimpr > 0.05 && absimpr > 1e-3 && ((overestimate && SCIPisRelLT(scip, val, *bestval)) || (!overestimate && SCIPisRelGT(scip, val, *bestval))) )
7564  {
7565  *bestcoefx = xcoef;
7566  *bestcoefy = ycoef;
7567  *bestconst = constant;
7568  *bestval = val;
7569  *success = TRUE;
7570  }
7571  }
7572  }
7573 }
7574 
7575 /* returns the interiority of a reference point w.r.t. given bounds */
7576 static
7578  SCIP* scip, /**< SCIP data structure */
7579  SCIP_Real lbx, /**< lower bound of the first variable */
7580  SCIP_Real ubx, /**< upper bound of the first variable */
7581  SCIP_Real refx, /**< reference point of the first variable */
7582  SCIP_Real lby, /**< lower bound of the second variable */
7583  SCIP_Real uby, /**< upper bound of the second variable */
7584  SCIP_Real refy /**< reference point of the second variable */
7585  )
7586 {
7587  SCIP_Real interiorityx;
7588  SCIP_Real interiorityy;
7589 
7590  interiorityx = MIN(refx-lbx, ubx-refx) / MAX(ubx-lbx, SCIPepsilon(scip)); /*lint !e666*/
7591  interiorityy = MIN(refy-lby, uby-refy) / MAX(uby-lby, SCIPepsilon(scip)); /*lint !e666*/
7592 
7593  return 2.0*MIN(interiorityx, interiorityy);
7594 }
7595 
7596 /** computes cut coefficients for a nonconvex quadratic function */
7597 static
7599  SCIP* scip, /**< SCIP data structure */
7600  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7601  SCIP_CONS* cons, /**< constraint */
7602  SCIP_SIDETYPE violside, /**< side for which to generate cut */
7603  SCIP_Real* ref, /**< reference solution where to generate the cut */
7604  SCIP_ROWPREP* rowprep, /**< rowprep to store cut data */
7605  SCIP_Bool* success /**< buffer to indicate whether a cut was successfully computed */
7606  )
7607 {
7608  SCIP_CONSDATA* consdata;
7609  SCIP_BILINTERM* bilinterm;
7610  SCIP_Real sqrcoef;
7611  SCIP_Real coef;
7612  SCIP_Real coef2;
7613  SCIP_Real constant;
7614  SCIP_VAR* var;
7615  int var2pos;
7616  int j;
7617  int k;
7618 
7619  assert(scip != NULL);
7620  assert(conshdlrdata != NULL);
7621  assert(cons != NULL);
7622  assert(ref != NULL);
7623  assert(success != NULL);
7624 
7625  consdata = SCIPconsGetData(cons);
7626  assert(consdata != NULL);
7627 
7628  rowprep->local = TRUE;
7629  *success = TRUE;
7630 
7631  /* underestimate (secant, McCormick) or linearize each term separately */
7632  for( j = 0; j < consdata->nquadvars && *success; ++j )
7633  {
7634  var = consdata->quadvarterms[j].var;
7635 
7636  /* initialize coefficients to linear coefficients of quadratic variables */
7637  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, consdata->quadvarterms[j].lincoef) );
7638 
7639  sqrcoef = consdata->quadvarterms[j].sqrcoef;
7640  if( sqrcoef != 0.0 )
7641  {
7642  coef = 0.0;
7643  constant = 0.0;
7644  if( (violside == SCIP_SIDETYPE_LEFT && sqrcoef <= 0.0) || (violside == SCIP_SIDETYPE_RIGHT && sqrcoef > 0.0) )
7645  {
7646  /* convex -> linearize */
7647  SCIPaddSquareLinearization(scip, sqrcoef, ref[j], SCIPvarGetType(var) < SCIP_VARTYPE_CONTINUOUS, &coef,
7648  &constant, success);
7649  }
7650  else
7651  {
7652  /* not convex -> secant approximation */
7653  SCIPaddSquareSecant(scip, sqrcoef, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), ref[j], &coef,
7654  &constant, success);
7655  }
7656  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, coef) );
7657  SCIPaddRowprepConstant(rowprep, constant);
7658  }
7659 
7660  /* relax each bilinear term */
7661  for( k = 0; k < consdata->quadvarterms[j].nadjbilin && (*success); ++k )
7662  {
7663  SCIP_VAR* x;
7664  SCIP_VAR* y;
7665  SCIP_Real refx;
7666  SCIP_Real refy;
7667  SCIP_Real lbx;
7668  SCIP_Real ubx;
7669  SCIP_Real lby;
7670  SCIP_Real uby;
7671  int idx;
7672 
7673  idx = consdata->quadvarterms[j].adjbilin[k];
7674  bilinterm = &consdata->bilinterms[idx];
7675  if( bilinterm->var1 != var )
7676  continue;
7677  assert(bilinterm->var2 != var);
7678  assert(consdata->sepabilinvar2pos != NULL);
7679 
7680  var2pos = consdata->sepabilinvar2pos[consdata->quadvarterms[j].adjbilin[k]];
7681  assert(var2pos >= 0);
7682  assert(var2pos < consdata->nquadvars);
7683  assert(consdata->quadvarterms[var2pos].var == bilinterm->var2);
7684 
7685  /* get data of the variables in the bilinear term */
7686  x = var;
7687  y = bilinterm->var2;
7688  refx = ref[j];
7689  refy = ref[var2pos];
7690  lbx = SCIPvarGetLbLocal(x);
7691  ubx = SCIPvarGetUbLocal(x);
7692  lby = SCIPvarGetLbLocal(y);
7693  uby = SCIPvarGetUbLocal(y);
7694  SCIPdebugMsg(scip, "bilinear term %g %s %s with (%g,%g) in [%g,%g]x[%g,%g] overestimate=%u\n", bilinterm->coef,
7695  SCIPvarGetName(x), SCIPvarGetName(y), refx, refy, lbx, ubx, lby, uby, violside == SCIP_SIDETYPE_LEFT);
7696 
7697  /* use the McCormick relaxation for under- or overestimating the bilinear term */
7698  coef = 0.0;
7699  coef2 = 0.0;
7700  constant = 0.0;
7701  SCIPaddBilinMcCormick(scip, bilinterm->coef, lbx, ubx, refx, lby, uby, refy,
7702  violside == SCIP_SIDETYPE_LEFT, &coef, &coef2, &constant, success);
7703  SCIPdebugMsg(scip, "McCormick = %g (%u)\n", refx * coef + refy * coef2 + constant, *success);
7704 
7705  /* tries to compute a tighter relaxation for xy by using valid linear inequalities */
7706  if( consdata->bilintermsidx != NULL && conshdlrdata->bilinestimators != NULL
7707  && ubx - lbx >= 0.1 && uby - lby >= 0.1
7708  && (SCIPgetNSepaRounds(scip) <= conshdlrdata->bilinineqmaxseparounds || SCIPgetDepth(scip) == 0) )
7709  {
7710  BILINESTIMATOR* bilinestimator;
7711  SCIP_Real mccormick;
7712  SCIP_Real score;
7713  int bilintermidx;
7714 
7715  mccormick = refx * coef + refy * coef2 + constant;
7716  score = getInteriority(scip, lbx, ubx, refx, lby, uby, refy);
7717 
7718  /* get data for bilinear term */
7719  bilintermidx = consdata->bilintermsidx[idx];
7720  assert(conshdlrdata->bilinestimators != NULL);
7721  bilinestimator = &(conshdlrdata->bilinestimators[bilintermidx]);
7722  assert(bilinestimator->x == x);
7723  assert(bilinestimator->y == y);
7724 
7725  /* reset the last improvement factor (used for getting better branching decisions) */
7726  bilinestimator->lastimprfac = 0.0;
7727 
7728  /* compute tighter relaxation for xy if the current score is large enough */
7729  if( SCIPisGE(scip, score, conshdlrdata->minscorebilinterms)
7730  && bilinestimator->nineqoverest + bilinestimator->ninequnderest > 0 )
7731  {
7732  SCIP_Real bestval = mccormick;
7733  SCIP_Bool updaterelax = FALSE;
7734 
7735  /*
7736  * note that we check the sign of the bilinear coefficient together with violside in
7737  * updateBilinearRelaxation in order to decide whether a valid under- or overestimate can be computed
7738  */
7739 
7740  /* use overestimates */
7741  updateBilinearRelaxation(scip, x, y, bilinterm->coef, violside, refx, refy, bilinestimator->ineqoverest,
7742  bilinestimator->nineqoverest, mccormick, &coef, &coef2, &constant, &bestval, &updaterelax);
7743 
7744  /* use underestimates */
7745  updateBilinearRelaxation(scip, x, y, bilinterm->coef, violside, refx, refy, bilinestimator->inequnderest,
7746  bilinestimator->ninequnderest, mccormick, &coef, &coef2, &constant, &bestval, &updaterelax);
7747 
7748  SCIPdebugMsg(scip, "found better relaxation value: %u (%g)\n", updaterelax, bestval);
7749 
7750  /* check whether the new relaxation is under- or overestimating xy properly */
7751  if( updaterelax )
7752  {
7753  /* update improvement factor */
7754  bilinestimator->lastimprfac = 1.0 - REALABS(bestval - bilinterm->coef * refx * refy) / REALABS(mccormick - bilinterm->coef * refx * refy);
7755 
7756 #ifndef NDEBUG
7757  assert(SCIPisEQ(scip, bestval, coef * refx + coef2 * refy + constant));
7758  if( violside == SCIP_SIDETYPE_LEFT )
7759  {
7760  assert(SCIPisRelGE(scip, bestval, bilinterm->coef * refx * refy));
7761  assert(SCIPisRelLE(scip, bestval, mccormick));
7762  }
7763  else
7764  {
7765  assert(SCIPisRelLE(scip, bestval, bilinterm->coef * refx * refy));
7766  assert(SCIPisRelGE(scip, bestval, mccormick));
7767  }
7768 #endif
7769  }
7770  }
7771  }
7772 
7773  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, coef) );
7774  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, bilinterm->var2, coef2) );
7775  SCIPaddRowprepConstant(rowprep, constant);
7776  }
7777  }
7778 
7779  if( !*success )
7780  {
7781  SCIPdebugMsg(scip, "no success to find estimator for nonconvex <%s>\n", SCIPconsGetName(cons));
7782  return SCIP_OKAY;
7783  }
7784 
7785  rowprep->sidetype = violside;
7786  SCIPaddRowprepSide(rowprep, violside == SCIP_SIDETYPE_LEFT ? consdata->lhs : consdata->rhs);
7787 
7788  (void) SCIPsnprintf(rowprep->name, SCIP_MAXSTRLEN, "%s_side%d_estimation_%d", SCIPconsGetName(cons), violside, SCIPgetNLPs(scip));
7789 
7790  return SCIP_OKAY;
7791 }
7792 
7793 /** generates a cut based on linearization (if convex) or McCormick (if nonconvex) in a given reference point */
7794 static
7796  SCIP* scip, /**< SCIP data structure */
7797  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7798  SCIP_CONS* cons, /**< constraint */
7799  SCIP_Real* ref, /**< reference solution where to generate the cut */
7800  SCIP_SOL* sol, /**< point that we aim to separate, or NULL for LP solution */
7801  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
7802  SCIP_ROW** row, /**< storage for cut */
7803  SCIP_Real* efficacy, /**< buffer to store efficacy of row in reference solution, or NULL if not of interest */
7804  SCIP_Bool checkcurvmultivar, /**< are we allowed to check the curvature of a multivariate quadratic function, if not done yet */
7805  SCIP_Real minefficacy /**< minimal required efficacy */
7806  )
7807 {
7808  SCIP_CONSHDLRDATA* conshdlrdata;
7809  SCIP_CONSDATA* consdata;
7810  SCIP_ROWPREP* rowprep;
7811  SCIP_Bool success;
7812  SCIP_Real viol = 0.0;
7813 
7814  assert(scip != NULL);
7815  assert(conshdlr != NULL);
7816  assert(cons != NULL);
7817  assert(ref != NULL);
7818  assert(row != NULL);
7819 
7820  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7821  assert(conshdlrdata != NULL);
7822 
7823  consdata = SCIPconsGetData(cons);
7824  assert(consdata != NULL);
7825  assert(violside != SCIP_SIDETYPE_LEFT || !SCIPisInfinity(scip, -consdata->lhs));
7826  assert(violside != SCIP_SIDETYPE_RIGHT || !SCIPisInfinity(scip, consdata->rhs));
7827 
7828  *row = NULL;
7829 
7831  success = FALSE;
7832 
7833  /* if constraint function is factorable, then try to use factorable form to generate cut */
7834  if( consdata->factorleft != NULL )
7835  {
7836  if( consdata->nlinvars == 0 )
7837  {
7838  SCIP_CALL( generateCutFactorable(scip, cons, violside, ref, rowprep, &success) );
7839  }
7840  else if( sol != NULL || SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
7841  {
7842  /* generateCutLTI needs reference values also for the linear variables, which we only have if sol is given or LP has been solved */
7843  SCIP_CALL( generateCutLTI(scip, cons, violside, ref, sol, rowprep, &success) );
7844  }
7845  }
7846 
7847  /* if constraint is not factorable or failed to generate cut, try default method */
7848  if( !success )
7849  {
7850  SCIP_CALL( checkCurvature(scip, cons, checkcurvmultivar) );
7851 
7852  if( (violside == SCIP_SIDETYPE_LEFT && consdata->isconcave) || (violside == SCIP_SIDETYPE_RIGHT && consdata->isconvex) )
7853  {
7854  SCIP_CALL( generateCutConvex(scip, cons, violside, ref, rowprep, &success) );
7855  }
7856  else
7857  {
7858  SCIP_CALL( generateCutNonConvex(scip, conshdlrdata, cons, violside, ref, rowprep, &success) );
7859  }
7860 
7861  SCIP_CALL( SCIPaddRowprepTerms(scip, rowprep, consdata->nlinvars, consdata->linvars, consdata->lincoefs) );
7862  }
7863 
7864  /* check if reference point violates cut at least a little bit */
7865  if( success && !SCIPisInfinity(scip, -minefficacy) )
7866  {
7867  viol = SCIPgetRowprepViolation(scip, rowprep, sol);
7868  if( viol <= 0.0 ) /*lint !e644*/
7869  {
7870  SCIPdebugMsg(scip, "skip cut for constraint <%s> because efficacy %g too low (< %g)\n", SCIPconsGetName(cons), viol, minefficacy);
7871  success = FALSE;
7872  }
7873  }
7874 
7875  /* cleanup and improve cut */
7876  if( success )
7877  {
7878  SCIP_Real coefrange;
7879 
7880  /* merge terms */
7881  SCIPmergeRowprepTerms(scip, rowprep);
7882 
7883  /* improve coefficients */
7884  SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, conshdlrdata->cutmaxrange, minefficacy, &coefrange, &viol) );
7885  success = coefrange <= conshdlrdata->cutmaxrange;
7886  }
7887 
7888  /* check that side is finite */ /*lint --e{514} */
7889  success &= !SCIPisInfinity(scip, REALABS(rowprep->side)); /*lint !e514*/
7890 
7891  /* check whether maximal coef is finite, if any */ /*lint --e{514} */
7892  success &= (rowprep->nvars == 0) || !SCIPisInfinity(scip, REALABS(rowprep->coefs[0])); /*lint !e514*/
7893 
7894  /* check if reference point violates cut sufficiently */
7895  if( success && !SCIPisInfinity(scip, -minefficacy) && viol < minefficacy ) /*lint !e644*/
7896  {
7897  SCIPdebugMsg(scip, "skip cut for constraint <%s> because efficacy %g too low (< %g)\n", SCIPconsGetName(cons), viol, minefficacy);
7898  success = FALSE;
7899  }
7900 
7901  /* generate row */
7902  if( success )
7903  {
7904  SCIP_CALL( SCIPgetRowprepRowCons(scip, row, rowprep, cons) );
7905 
7906  SCIPdebugMsg(scip, "found cut <%s>, lhs=%g, rhs=%g, mincoef=%g, maxcoef=%g, range=%g, nnz=%d, efficacy=%g\n",
7907  SCIProwGetName(*row), SCIProwGetLhs(*row), SCIProwGetRhs(*row),
7908  rowprep->nvars > 0 ? rowprep->coefs[rowprep->nvars-1] : 0.0, rowprep->nvars > 0 ? rowprep->coefs[0] : 0.0,
7909  rowprep->nvars > 0 ? rowprep->coefs[0]/rowprep->coefs[rowprep->nvars-1] : 1.0,
7910  SCIProwGetNNonz(*row), viol); /*lint !e414 */
7911 
7912  if( efficacy != NULL )
7913  *efficacy = viol;
7914  }
7915 
7916  SCIPfreeRowprep(scip, &rowprep);
7917 
7918  return SCIP_OKAY;
7919 }
7920 
7921 /** computes eigen decomposition of A, where \f$ f(x) = x^T A x + b^T x \f$.
7922  *
7923  * The eigen decomposition is given by A = P D P^T, where D is diagonal formed by the eigenvalues and P is orthonormal
7924  * whose columns are the eigenvectors; we also compute b^T * P, in case one needs the change of variables P^T x = y <=>
7925  * 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
7926  * of P^T is stored in eigenvector[0..n-1], the second row is stored in eigenvectors[n..2n-1], etc; equivalently, the
7927  * first eigenvector is eigenvector[0..n-1], the second one is eigenvectors[n..2n-1], etc.
7928  *
7929  * @todo: - at the moment of writing, checkCurvature computes the eigenvalues (and vectors) for determining curvature
7930  * when it can't to it via other considerations. so one could try to merge both methods together.
7931  * - it seems that if A is of the form [I 0; 0 A'], one only needs to compute the decomposition for A' so one
7932  * could do better in terms of memory and speed. For instance, when the matrix is diagonal, the eigenvectors
7933  * are the identity matrix and the eigenvalues are readily available from the constraint, so one could adapt
7934  * the functions that uses the eigenvectors in this particular case. One could also think about storing the
7935  * eigenvectors in a sparse fashion, though eigenvectors are seldom sparse.
7936  */
7937 static
7939  SCIP* scip, /**< SCIP data structure */
7940  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7941  SCIP_CONS* cons /**< constraint */
7942  )
7943 {
7944  SCIP_CONSDATA* consdata;
7945  int n;
7946  int nn;
7947  int row;
7948  int col;
7949  int i;
7950  int j;
7951  double* matrix;
7952  SCIP_HASHMAP* var2index;
7953 
7954  SCIPdebugMsg(scip, "computing ED for cons %s\n", SCIPconsGetName(cons));
7955 
7956  assert(scip != NULL);
7957  assert(conshdlr != NULL);
7958  assert(cons != NULL);
7959 
7960  consdata = SCIPconsGetData(cons);
7961  assert(consdata != NULL);
7962 
7963  /* function has to be convex with finite rhs or concave with finite lhs */
7964  assert((consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
7965  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)));
7966 
7967  /* can't compute eigenvectors without IPOPT */
7968  if( !SCIPisIpoptAvailableIpopt() )
7969  {
7970  consdata->isedavailable = FALSE;
7971  return SCIP_OKAY;
7972  }
7973 
7974  /* @todo: - it seems that if A is of the form [I 0; 0 A'], one only needs to compute the decomposition for A'
7975  * so one could do better in terms of memory and speed
7976  * - if n too big don't compute SVD
7977  */
7978  n = consdata->nquadvars;
7979 
7980  /* do not compute eigendecomposition if n is too large */
7981  nn = n * n;
7982  if( nn < 0 || (unsigned) (int) nn > UINT_MAX / sizeof(SCIP_Real) )
7983  {
7984  SCIPdebugMsg(scip, "n is too large to compute eigendecomposition\n");
7985  consdata->isedavailable = FALSE;
7986  return SCIP_OKAY;
7987  }
7988 
7989  /* we just need to pass the upper triangle of A since it is symmetric; build it here */
7990  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->eigenvectors, nn) );
7991  matrix = consdata->eigenvectors;
7992  BMSclearMemoryArray(matrix, nn);
7993 
7994  /* @todo if we are called in solving stage (or late from initsol), we can avoid the hashmap by using sepabilinvar2pos */
7995  SCIP_CALL( SCIPhashmapCreate(&var2index, SCIPblkmem(scip), n) );
7996 
7997  for( i = 0; i < n; ++i )
7998  {
7999  SCIP_CALL( SCIPhashmapInsertInt(var2index, consdata->quadvarterms[i].var, i) );
8000  matrix[i*n + i] = consdata->quadvarterms[i].sqrcoef;
8001 #ifdef DEBUG_PROJ
8002  printf("inserting in position %d, value %g\n", i*n + i, consdata->quadvarterms[i].sqrcoef);
8003 #endif
8004  }
8005 
8006  for( i = 0; i < consdata->nbilinterms; ++i )
8007  {
8008  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var1));
8009  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var2));
8010  row = SCIPhashmapGetImageInt(var2index, consdata->bilinterms[i].var1);
8011  col = SCIPhashmapGetImageInt(var2index, consdata->bilinterms[i].var2);
8012  if( row < col )
8013  {
8014  matrix[row * n + col] = consdata->bilinterms[i].coef/2;
8015 #ifdef DEBUG_PROJ
8016  printf("inserting in position %d, value %g\n", row*n + col, consdata->bilinterms[i].coef/2);
8017 #endif
8018  }
8019  else
8020  {
8021  matrix[col * n + row] = consdata->bilinterms[i].coef/2;
8022 #ifdef DEBUG_PROJ
8023  printf("inserting in position %d, value %g\n", col*n + row, consdata->bilinterms[i].coef/2);
8024 #endif
8025  }
8026  }
8027 
8028 #ifdef DEBUG_PROJ
8029  printf("matrix built:\n");
8030  for( i = 0; i < n; i++ )
8031  {
8032  for( j = 0; j < n; j++ )
8033  printf("%g ", matrix[i*n + j]);
8034  printf("\n");
8035  }
8036 #endif
8037 
8038  /* compute eigenvalues and eigenvectors */
8039  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->eigenvalues, n) );
8040 
8041  if( LapackDsyev(TRUE, n, matrix, consdata->eigenvalues) != SCIP_OKAY )
8042  {
8043  SCIPdebugMsg(scip, "couldn't compute ED for cons %s\n", SCIPconsGetName(cons));
8044  consdata->isedavailable = FALSE;
8045  }
8046  else
8047  {
8048  consdata->isedavailable = TRUE;
8049 
8050  /* compute b^T*P */
8051  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &consdata->bp, n) );
8052  for( i = 0; i < n; i++ )
8053  for( j = 0; j < n; j++ )
8054  consdata->bp[i] += consdata->quadvarterms[j].lincoef * matrix[i*n + j];
8055 
8056 #ifdef DEBUG_PROJ
8057  printf("eigenvalues:\n");
8058  for( j = 0; j < n; j++ )
8059  printf("%g ", consdata->eigenvalues[j]);
8060 
8061  printf("\neigenvectors (P^T):\n");
8062  for( i = 0; i < n; i++ )
8063  {
8064  for( j = 0; j < n; j++ )
8065  printf("%g ", matrix[i*n + j]);
8066  printf("\n");
8067  }
8068 
8069  printf("b*P^T:\n");
8070  for( j = 0; j < n; j++ )
8071  printf("%g ", consdata->bp[j]);
8072  printf("svd computed successfully\n");
8073 #endif
8074  }
8075 
8076  SCIPhashmapFree(&var2index);
8077 
8078  return SCIP_OKAY;
8079 }
8080 
8081 /** computes an interior point for the quadratic part of the convex constraint
8082  *
8083  * There are different methods for computing the interior point
8084  * - 'a'ny: solves min 0, f(x) <= rhs, x in bounds
8085  * - 'm'ost interior: solves min f(x), x in bounds
8086  *
8087  * @todo: other methods for computing an interior point?
8088  */
8089 static
8091  SCIP* scip, /**< SCIP data structure */
8092  SCIP_CONS* cons, /**< constraint */
8093  char method, /**< method for computing interior point ('a' any point, 'm'ost interior) */
8094  SCIP_Bool* success /**< buffer to store if an interior point was found */
8095  )
8096 {
8097  SCIP_CONSDATA* consdata;
8098  SCIP_QUADELEM* nlrowquadelems;
8099  SCIP_NLPIPROBLEM* prob;
8100  SCIP_NLPI* nlpi;
8101  SCIP_Real* interiorpoint;
8102  SCIP_Real* lbs;
8103  SCIP_Real* ubs;
8104  SCIP_Real* lincoefs;
8105  SCIP_Real nlpiside;
8106  char probname[SCIP_MAXSTRLEN];
8107  int* lininds;
8108  int nlrownquadelems;
8109  int nquadvars;
8110  int i;
8111 
8112  assert(scip != NULL);
8113  assert(cons != NULL);
8114 
8115  assert(success != NULL);
8116  *success = FALSE;
8117 
8118  consdata = SCIPconsGetData(cons);
8119  assert(consdata != NULL);
8120 
8121  assert((consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
8122  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)));
8123 
8124  /* need an NLP solver */
8125  if( SCIPgetNNlpis(scip) == 0 )
8126  return SCIP_OKAY;
8127 
8128  prob = NULL;
8129  lbs = NULL;
8130  ubs = NULL;
8131  lincoefs = NULL;
8132  lininds = NULL;
8133 
8134 #ifdef SCIP_DEBUG_INT
8135  SCIPinfoMessage(scip, NULL, "Computing interior point for\n");
8136  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
8137  SCIPinfoMessage(scip, NULL, ";\n");
8138 #endif
8139 
8140  /* in the convex case, we try to find an interior point of x^T A x + b^T x <= rhs - maximum activity linear part
8141  * in the concave case: lhs - minimum activity linear part <= x^T A x + b^T x; we compute activities ourselves,
8142  * since consdata->max(min)linactivity are only computed when lhs (rhs) is finite and this not always holds
8143  */
8144  if( consdata->isconvex )
8145  {
8146  /* compute maximum activity */
8147  nlpiside = 0;
8148  for( i = 0; i < consdata->nlinvars; ++i )
8149  {
8150  if( consdata->lincoefs[i] >= 0.0 )
8151  {
8152  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i]) ) )
8153  nlpiside = SCIPinfinity(scip);
8154  else
8155  nlpiside += consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
8156  }
8157  else
8158  {
8159  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i]) ) )
8160  nlpiside = SCIPinfinity(scip);
8161  else
8162  nlpiside += consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
8163  }
8164 
8165  if( SCIPisInfinity(scip, nlpiside) )
8166  {
8167  SCIPdebugMsg(scip, "maximum activity is infinity: there is no interior point for fun <= rhs - maxlinactivity!\n");
8168  return SCIP_OKAY;
8169  }
8170  }
8171 
8172  if( consdata->nlinvars == 0 )
8173  nlpiside = INTERIOR_EPS;
8174 
8175  nlpiside = consdata->rhs - nlpiside;
8176  }
8177  else
8178  {
8179  /* compute minimum activity */
8180  nlpiside = 0;
8181  for( i = 0; i < consdata->nlinvars; ++i )
8182  {
8183  if( consdata->lincoefs[i] >= 0.0 )
8184  {
8185  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i])) )
8186  nlpiside = -SCIPinfinity(scip);
8187  else
8188  nlpiside += consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
8189  }
8190  else
8191  {
8192  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i])) )
8193  nlpiside = -SCIPinfinity(scip);
8194  else
8195  nlpiside += consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
8196  }
8197 
8198  if( SCIPisInfinity(scip, -nlpiside) )
8199  {
8200  SCIPdebugMsg(scip, "minimum activity is -infinity: there is no interior point for fun >= lhs - minlinactivity!\n");
8201  return SCIP_OKAY;
8202  }
8203  }
8204 
8205  if( consdata->nlinvars == 0 )
8206  nlpiside = INTERIOR_EPS;
8207 
8208  nlpiside = consdata->lhs - nlpiside;
8209  }
8210 
8211  nquadvars = consdata->nquadvars;
8212 
8213  /* if we are looking for any interior point and the 0 is one, then use it */
8214  if( method == 'a' && ((consdata->isconvex && SCIPisGE(scip, nlpiside, 0.0))
8215  || (consdata->isconcave && SCIPisLE(scip, nlpiside, 0.0))) )
8216  {
8217 #ifdef SCIP_DEBUG_INT
8218  SCIPinfoMessage(scip, NULL, "Computation successful, 0 is interior point.\n");
8219 #endif
8220 
8221  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &(consdata->interiorpoint), nquadvars) );
8222  *success = TRUE;
8223  return SCIP_OKAY;
8224  }
8225 
8226  /* build nlrow */
8227  if( consdata->nlrow == NULL )
8228  {
8229  SCIP_CALL( createNlRow(scip, cons) );
8230  assert(consdata->nlrow != NULL);
8231  }
8232 
8233  nlpi = SCIPgetNlpis(scip)[0];
8234  assert(nlpi != NULL);
8235 
8236  /* initializing the subproblem */
8237  (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "%s_subquad", SCIPgetProbName(scip));
8238  SCIP_CALL( SCIPnlpiCreateProblem(nlpi, &prob, probname) );
8239  if( prob == NULL )
8240  {
8241 #ifdef SCIP_DEBUG_INT
8242  SCIPinfoMessage(scip, NULL, "Creation of interior point problem failed..\n");
8243 #endif
8244  return SCIP_OKAY;
8245  }
8246  assert(prob != NULL);
8247 
8248 #ifdef SCIP_DEBUG_INT
8250 #endif
8251  /* TODO: maybe one should set some generous iteration limit and/or a timelimit (remaining scip solve time)? */
8252 
8253  /* ask for memory to store data needed to create vars and linear coefficients */
8254  SCIP_CALL( SCIPallocBufferArray(scip, &lbs, nquadvars) );
8255  SCIP_CALL( SCIPallocBufferArray(scip, &ubs, nquadvars) );
8256  SCIP_CALL( SCIPallocBufferArray(scip, &lininds, nquadvars) );
8257  SCIP_CALL( SCIPallocBufferArray(scip, &lincoefs, nquadvars) );
8258 
8259  /* get bounds and linear coefficients */
8260  for( i = 0; i < nquadvars; i++ )
8261  {
8262  lbs[i] = SCIPvarGetLbGlobal(consdata->quadvarterms[i].var);
8263  ubs[i] = SCIPvarGetUbGlobal(consdata->quadvarterms[i].var);
8264 
8265  lincoefs[i] = consdata->quadvarterms[i].lincoef;
8266  lininds[i] = i;
8267  }
8268 
8269  /* add vars */
8270  SCIP_CALL( SCIPnlpiAddVars(nlpi, prob, nquadvars, lbs, ubs, NULL) );
8271 
8272  /* get nlrow info */
8273  nlrownquadelems = SCIPnlrowGetNQuadElems(consdata->nlrow);
8274  nlrowquadelems = SCIPnlrowGetQuadElems(consdata->nlrow);
8275 
8276 #ifndef NDEBUG
8277  {
8278  SCIP_VAR** nlrowquadvars;
8279 
8280  nlrowquadvars = SCIPnlrowGetQuadVars(consdata->nlrow);
8281  for( i = 0; i < nlrownquadelems; i++ )
8282  {
8283  assert(nlrowquadvars[nlrowquadelems[i].idx1] == consdata->quadvarterms[nlrowquadelems[i].idx1].var);
8284  assert(nlrowquadvars[nlrowquadelems[i].idx2] == consdata->quadvarterms[nlrowquadelems[i].idx2].var);
8285  }
8286  }
8287 #endif
8288 
8289  (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "%s", SCIPconsGetName(cons));
8290 
8291  switch( method )
8292  {
8293  case 'a':
8294  /* add constraint */
8295  if( consdata->isconvex )
8296  {
8297  SCIP_CALL( SCIPnlpiAddConstraints(nlpi, prob, 1, NULL, &nlpiside, &nquadvars, &lininds, &lincoefs,
8298  &nlrownquadelems, &nlrowquadelems, NULL, NULL, NULL) );
8299  }
8300  else
8301  {
8302  SCIP_CALL( SCIPnlpiAddConstraints(nlpi, prob, 1, &nlpiside, NULL, &nquadvars, &lininds, &lincoefs,
8303  &nlrownquadelems, &nlrowquadelems, NULL, NULL, NULL) );
8304  }
8305  break;
8306 
8307  case 'm':
8308  /* add objective */
8309  if( consdata->isconvex )
8310  {
8311  SCIP_CALL( SCIPnlpiSetObjective(nlpi, prob, nquadvars, lininds, lincoefs,
8312  nlrownquadelems, nlrowquadelems, NULL, NULL, 0.0) );
8313  }
8314  else
8315  {
8316  /* NLPI assumes minimization: change signs */
8317  for( i = 0; i < nquadvars; i++ )
8318  lincoefs[i] *= -1;
8319 
8320  /* WARNING: this pointer is not ours, information should be restored! */
8321  for( i = 0; i < nlrownquadelems; i++ )
8322  nlrowquadelems->coef *= -1;
8323 
8324  SCIP_CALL( SCIPnlpiSetObjective(nlpi, prob, nquadvars, lininds, lincoefs,
8325  nlrownquadelems, nlrowquadelems, NULL, NULL, 0.0) );
8326 
8327  /* WARNING: restore information! */
8328  for( i = 0; i < nlrownquadelems; i++ )
8329  nlrowquadelems->coef *= -1;
8330  }
8331  break;
8332 
8333  default:
8334  SCIPerrorMessage("undefined method for computing interior point: %c\n", method);
8335  return SCIP_INVALIDDATA;
8336  }
8337 
8338  /* set NLP tolerances; we don't really need an optimal solution to this NLP */
8339  SCIP_CALL( SCIPnlpiSetRealPar(nlpi, prob, SCIP_NLPPAR_FEASTOL, SCIPfeastol(scip)) ); /*lint !e666*/
8340  SCIP_CALL( SCIPnlpiSetRealPar(nlpi, prob, SCIP_NLPPAR_RELOBJTOL, MAX(SCIPfeastol(scip), SCIPdualfeastol(scip))) ); /*lint !e666*/
8341 
8342  /* solve NLP problem */
8343  SCIP_CALL( SCIPnlpiSolve(nlpi, prob) );
8344 
8345  /* check termination status */
8346  if( SCIPnlpiGetTermstat(nlpi, prob) != SCIP_NLPTERMSTAT_OKAY )
8347  {
8348  SCIPdebugMsg(scip, "cons <%s>: NLP Solver termination status not okay: %d\n",
8349  SCIPconsGetName(cons), SCIPnlpiGetTermstat(nlpi, prob));
8350  *success = FALSE;
8351  goto TERMINATE;
8352  }
8353 
8354  /* check solution status */
8355  switch( SCIPnlpiGetSolstat(nlpi, prob) )
8356  {
8360  /* fallthrough */
8361  SCIPdebugMsg(scip, "cons <%s>: found an interior point. solution status: %d, termination status: %d\n",
8362  SCIPconsGetName(cons), SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
8363  break;
8364 
8368  /* fallthrough */
8369  /* TODO: we could still use the point, and let evaluateGauge decide whether the point is interior or not */
8370  SCIPdebugMsg(scip, "cons <%s>: failed to find an interior point. solution status: %d, termination status: %d\n",
8371  SCIPconsGetName(cons), SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
8372  goto TERMINATE;
8373 
8375  default:
8376  /* fallthrough */
8377  SCIPerrorMessage("cons <%s>: undefined behaviour of NLP Solver. solution status: %d, termination status: %d\n",
8378  SCIPconsGetName(cons), SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
8379  SCIPABORT();
8380  goto TERMINATE; /*lint !e527*/
8381  }
8382 
8383  /* fetch solution
8384  * note: nlpiGetSolution (at least for IPOPT) makes interiorpoint point to the internal solution stored in the
8385  * nlpi problem data structure; we need to copy it here because it will be destroyed once the problem is free'd
8386  */
8387  SCIP_CALL( SCIPnlpiGetSolution(nlpi, prob, &interiorpoint, NULL, NULL, NULL, NULL) );
8388 
8389  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(consdata->interiorpoint), nquadvars) );
8390 
8391  for( i = 0; i < nquadvars; i++ )
8392  {
8393  if( SCIPisFeasZero(scip, interiorpoint[i]) )
8394  consdata->interiorpoint[i] = 0.0;
8395  else
8396  consdata->interiorpoint[i] = interiorpoint[i];
8397  }
8398 
8399  *success = TRUE;
8400 
8401 TERMINATE:
8402 
8403 #ifdef SCIP_DEBUG_INT
8404  printf("Computation of interior point for cons <%s>:\n", SCIPconsGetName(cons));
8405  printf(" - has %d linear variables\n", consdata->nlinvars);
8406  if( consdata->isconvex )
8407  {
8408  printf(" - is convex. rhs: %g maximum activity of linear variables: %g\n", consdata->rhs, consdata->rhs - nlpiside);
8409  printf(" - searched for point whose quadratic part is <= %g\n", nlpiside);
8410  }
8411  else
8412  {
8413  printf(" - is concave. lhs: %g minimum activity of linear variables: %g\n", consdata->lhs, consdata->lhs - nlpiside);
8414  printf(" - searched for point whose quadratic part is >= %g\n", nlpiside);
8415  }
8416 
8417  if( *success )
8418  {
8419  printf("Computation successful, NLP soltat: %d, termstat: %d\nPoint found:\n",
8420  SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
8421  for( i = 0; i < nquadvars; i++ )
8422  {
8423  printf("%s = %g\n", SCIPvarGetName(consdata->quadvarterms[i].var), consdata->interiorpoint[i]);
8424  }
8425  }
8426  else
8427  {
8428  printf("Computation failed. NLP soltat: %d, termstat: %d\n",
8429  SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
8430  printf("run with SCIP_DEBUG for more info\n");
8431  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
8432  SCIPinfoMessage(scip, NULL, ";\n");
8433  /* FIXME: instance camshape100 says that there is no interior point (interior empty)
8434  * is there something intelligent that can be said?
8435  */
8436  }
8437 #endif
8438 
8439  /* free memory */
8440  SCIPfreeBufferArrayNull(scip, &lbs);
8441  SCIPfreeBufferArrayNull(scip, &ubs);
8442  SCIPfreeBufferArrayNull(scip, &lininds);
8443  SCIPfreeBufferArrayNull(scip, &lincoefs);
8444  SCIP_CALL( SCIPnlpiFreeProblem(nlpi, &prob) );
8445 
8446  return SCIP_OKAY;
8447 }
8448 
8449 /** 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$.
8450  *
8451  * Here, \f$ f(x) \f$ is a purely quadratic (i.e, all \f$x\f$ variables appear in a bilinear or quadratic term).
8452  * Explicitly, \f$ f(x) = \pm x^T A x \pm b^T x \f$ depending whether \f$A\f$
8453  * is positive semidefinite (+) or negative semidefinite (-).
8454  * The constant \f$c\f$ is rhs - maximum activity of the purely linear part of the constraint
8455  * if \f$A \succeq 0\f$ and minimum activity - lhs if \f$A \preceq 0\f$.
8456  * This is computed only at INITSOL.
8457  *
8458  * The method does:
8459  * 1. compute interior point
8460  * 2. compute gauge function
8461  */
8462 static
8464  SCIP* scip, /**< SCIP data structure */
8465  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8466  SCIP_CONS* cons /**< constraint */
8467  )
8468 {
8469  SCIP_CONSHDLRDATA* conshdlrdata;
8470  SCIP_CONSDATA* consdata;
8471  SCIP_QUADVARTERM* quadvarterm;
8472  SCIP_BILINTERM* bilinterm;
8473  SCIP_Bool success;
8474  SCIP_Bool convex;
8475  int i;
8476  int j;
8477 
8478  assert(scip != NULL);
8479  assert(conshdlr != NULL);
8480  assert(cons != NULL);
8481 
8482  consdata = SCIPconsGetData(cons);
8483  assert(consdata != NULL);
8484 
8485  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8486  assert(conshdlrdata != NULL);
8487  assert(conshdlrdata->gaugecuts);
8488 
8489  /* function has to be convex with finite rhs or concave with finite lhs */
8490  convex = consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs);
8491  assert(convex || (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)));
8492 
8493  SCIPdebugMsg(scip, "cons %s: is %s\n", SCIPconsGetName(cons), convex ? "convex" : "concave");
8494 
8495  /* 1. */
8496  SCIP_CALL( computeInteriorPoint(scip, cons, conshdlrdata->interiorcomputation, &success) );
8497 
8498  /* if success, compute gaugecoefs (b_gauge) and gaugeconst (c_gauge) */
8499  if( !success )
8500  {
8501  SCIPdebugMsg(scip, "failed to compute gauge function\n");
8502  consdata->isgaugeavailable = FALSE;
8503  return SCIP_OKAY;
8504  }
8505 
8506  /* 2.
8507  * we are going to evaluate the function at interiorpoint; so, we need to compute interiorpoint^T A interiorpoint;
8508  * therefore, we need a mechanism that for a given variable, it returns its interior point value
8509  * fortunately, sepabilinvar2pos in consdata gives us all the information that we need
8510  */
8511 
8512  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &(consdata->gaugecoefs), consdata->nquadvars) );
8513 
8514  /* compute value of quadratic part at interior point, build map and compute gaugeconst (c_gauge) */
8515  consdata->interiorpointval = 0;
8516  consdata->gaugeconst = 0;
8517  for( i = 0; i < consdata->nquadvars; i++ )
8518  {
8519  SCIP_Real val;
8520  SCIP_Real val2;
8521 
8522  val = consdata->interiorpoint[i];
8523  quadvarterm = &consdata->quadvarterms[i];
8524 
8525  consdata->interiorpointval += (quadvarterm->lincoef + quadvarterm->sqrcoef * val) * val;
8526  consdata->gaugeconst += quadvarterm->sqrcoef * val * val;
8527 
8528  for( j = 0; j < quadvarterm->nadjbilin; ++j )
8529  {
8530  int bilintermidx;
8531 
8532  bilintermidx = quadvarterm->adjbilin[j];
8533  bilinterm = &consdata->bilinterms[bilintermidx];
8534 
8535  if( bilinterm->var1 != quadvarterm->var )
8536  continue;
8537 
8538  /* the index of the variable associated with var2 in bilinterm should be given by sepabilinvar2pos */
8539  assert(consdata->sepabilinvar2pos != NULL); /* this should have been computed in INITSOL */
8540  assert(consdata->quadvarterms[consdata->sepabilinvar2pos[bilintermidx]].var == bilinterm->var2);
8541 
8542  val2 = consdata->interiorpoint[consdata->sepabilinvar2pos[bilintermidx]];
8543 
8544  consdata->interiorpointval += bilinterm->coef * val * val2;
8545  consdata->gaugeconst += bilinterm->coef * val * val2;
8546  }
8547  }
8548 
8549  /* compute gaugecoefs (b_gauge = b + 2 * A * interiorpoint) */
8550  for( i = 0; i < consdata->nquadvars; i++ )
8551  {
8552  quadvarterm = &consdata->quadvarterms[i];
8553  consdata->gaugecoefs[i] += quadvarterm->lincoef + 2.0 * quadvarterm->sqrcoef * consdata->interiorpoint[i];
8554 
8555  for( j = 0; j < quadvarterm->nadjbilin; j++ )
8556  {
8557  int varpos;
8558  int bilintermidx;
8559 
8560  bilintermidx = quadvarterm->adjbilin[j];
8561  bilinterm = &consdata->bilinterms[bilintermidx];
8562 
8563  if( bilinterm->var1 == quadvarterm->var )
8564  {
8565  varpos = consdata->sepabilinvar2pos[bilintermidx];
8566 
8567  /* the index of the variable associated with var2 in bilinterm should be given by sepabilinvar2pos */
8568  assert(consdata->quadvarterms[varpos].var == bilinterm->var2);
8569 
8570  consdata->gaugecoefs[i] += bilinterm->coef * consdata->interiorpoint[varpos];
8571  consdata->gaugecoefs[varpos] += bilinterm->coef * consdata->interiorpoint[i];
8572  }
8573  }
8574  }
8575 
8576 #ifdef SCIP_DEBUG_INT
8577  printf("quadratic part at interior point: %g\n", consdata->interiorpointval);
8578 
8579  for( j = 0; j < consdata->nquadvars; j++ )
8580  {
8581  printf("b_gauge[%s] = %g\n", SCIPvarGetName(consdata->quadvarterms[j].var), consdata->gaugecoefs[j]);
8582  }
8583  printf("c_gauge = %g\n", consdata->gaugeconst);
8584 #endif
8585 
8586  SCIPdebugMsg(scip, "gauge function computed successfully\n");
8587  consdata->isgaugeavailable = TRUE;
8588 
8589  return SCIP_OKAY;
8590 }
8591 
8592 /** 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$.
8593  *
8594  * \f$ S = \{ x : f(x) \le c \}\f$ at \f$sol - s_0\f$;
8595  * see computeGauge() for more details
8596  *
8597  * @todo Think about if user should tell that function is convex or ...
8598  */
8599 static
8601  SCIP* scip, /**< SCIP data structure */
8602  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8603  SCIP_CONS* cons, /**< constraint */
8604  SCIP_SOL* refsol, /**< reference point where to generate cut, or NULL if sol should be used */
8605  SCIP_Real* gaugeval, /**< buffer to store the value of the gauge function */
8606  SCIP_Bool* success /**< buffer to store if evaluation was successful */
8607  )
8608 {
8609  SCIP_CONSDATA* consdata;
8610  SCIP_Real side;
8611  SCIP_Real aterm;
8612  SCIP_Real bterm;
8613  SCIP_Real cterm;
8614  SCIP_Bool convex;
8615  int i;
8616 
8617  assert(scip != NULL);
8618  assert(conshdlr != NULL);
8619  assert(cons != NULL);
8620 
8621  consdata = SCIPconsGetData(cons);
8622  assert(consdata != NULL);
8623  assert(consdata->isgaugeavailable);
8624 
8625  *success = FALSE;
8626 
8627  convex = consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs);
8628 
8629  SCIPdebugMsg(scip, "cons %s: is %s\n", SCIPconsGetName(cons), convex ? "convex" : "concave");
8630 
8631  /* evaluate gauge function at x0 = (refsol - interior point)
8632  *
8633  * compute aterm = side - function(interior point)
8634  */
8635  if( convex )
8636  {
8637  side = consdata->rhs;
8638  for( i = 0; i < consdata->nlinvars; i++ )
8639  side -= SCIPgetSolVal(scip, refsol, consdata->linvars[i]) * consdata->lincoefs[i];
8640 
8641  aterm = side - consdata->interiorpointval;
8642 
8643  /* it can happen that the interior point is not really interior, since we are not so strict at the moment of
8644  * computing the interior point, which makes sense in the case that the constraint is quadratic <= linear expr,
8645  * since we compute a point in quadratic <= min linear expr and it might be that this set consists of a single
8646  * point which will not be interior. furthermore, if this set is empty, we could just take any point and it could
8647  * happen that for some value of linear expr, the point is actually interior, but for many it could not be.
8648  * also, if min linear expr = -infinity, we might have computed an interior point using some finite value.
8649  * the point will not be an interior point, if and only if aterm is negative.
8650  */
8651 #ifdef SCIP_DEBUG_GAUGE
8652  if( SCIPisLE(scip, aterm, 0.0) )
8653  {
8654  printf("For current level, there is no interior point. ");
8655  printf("rhs: %g level: %.15g interiorpointval: %.15g\n", consdata->rhs, side, consdata->interiorpointval);
8656  if( consdata->nlinvars == 1 )
8657  {
8658  SCIP_VAR* var;
8659 
8660  var = consdata->linvars[0];
8661  printf("var <%s> = %g in [%.15g, %.15g] is linpart\n", SCIPvarGetName(var),
8662  SCIPgetSolVal(scip, refsol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
8663  }
8664  }
8665  else
8666  {
8667  printf("For current level, there is interior point. ");
8668  printf("rhs: %g level: %.15g interiorpointval: %.15g\n", consdata->rhs, side, consdata->interiorpointval);
8669  }
8670 #endif
8671  if( !SCIPisPositive(scip, aterm) )
8672  {
8673  *gaugeval = -1.0;
8674  return SCIP_OKAY;
8675  }
8676  }
8677  else
8678  {
8679  side = consdata->lhs;
8680  for( i = 0; i < consdata->nlinvars; i++ )
8681  side -= SCIPgetSolVal(scip, refsol, consdata->linvars[i]) * consdata->lincoefs[i];
8682 
8683  aterm = side - consdata->interiorpointval;
8684 
8685 #ifdef SCIP_DEBUG_GAUGE
8686  if( SCIPisGE(scip, aterm, 0.0) )
8687  {
8688  printf("For current level, there is no interior point. ");
8689  printf("lhs: %g level: %.15g interiorpointval: %.15g\n", consdata->lhs, side, consdata->interiorpointval);
8690  if( consdata->nlinvars == 1 )
8691  {
8692  SCIP_VAR* var;
8693 
8694  var = consdata->linvars[0];
8695  printf("var <%s> = %g in [%.15g, %.15g] is linpart\n", SCIPvarGetName(var),
8696  SCIPgetSolVal(scip, refsol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
8697  }
8698  }
8699  else
8700  {
8701  printf("For current level, there is interior point. ");
8702  printf("lhs: %g level: %.15g interiorpointval: %.15g\n", consdata->lhs, side, consdata->interiorpointval);
8703  }
8704 #endif
8705  if( !SCIPisNegative(scip, aterm) )
8706  {
8707  *gaugeval = -1.0;
8708  return SCIP_OKAY;
8709  }
8710  }
8711 
8712  /* compute bterm = b_gauge^T * refsol - f(interiorpoint) - c_gauge
8713  * compute cterm = f(refsol) - b_gauge^T * refsol + c_gauge */
8714  bterm = -consdata->interiorpointval - consdata->gaugeconst;
8715  cterm = consdata->gaugeconst;
8716  for( i = 0; i < consdata->nquadvars; i++ )
8717  {
8718  SCIP_Real val;
8719 
8720  val = SCIPgetSolVal(scip, refsol, consdata->quadvarterms[i].var);
8721  bterm += consdata->gaugecoefs[i] * val;
8722  cterm -= consdata->gaugecoefs[i] * val;
8723  cterm += (consdata->quadvarterms[i].lincoef + consdata->quadvarterms[i].sqrcoef * val) * val;
8724  }
8725 
8726  for( i = 0; i < consdata->nbilinterms; i++ )
8727  {
8728  SCIP_VAR* var1;
8729  SCIP_VAR* var2;
8730 
8731  var1 = consdata->bilinterms[i].var1;
8732  var2 = consdata->bilinterms[i].var2;
8733  cterm += consdata->bilinterms[i].coef * SCIPgetSolVal(scip, refsol, var1) * SCIPgetSolVal(scip, refsol, var2);
8734  }
8735 
8736  /* now compute gauge */
8737  if( convex && cterm < 0.0 )
8738  {
8739  assert(SCIPisZero(scip, cterm));
8740  cterm = 0.0;
8741  }
8742  else if( !convex && cterm > 0.0 )
8743  {
8744  assert(SCIPisZero(scip, cterm));
8745  cterm = 0.0;
8746  }
8747  assert(bterm*bterm + 4*aterm*cterm >= 0);
8748 
8749  if( convex )
8750  {
8751  *gaugeval = bterm + sqrt(bterm*bterm + 4 * aterm * cterm);
8752  *gaugeval = *gaugeval / (2 * aterm);
8753  }
8754  else
8755  {
8756  *gaugeval = bterm - sqrt(bterm*bterm + 4 * aterm * cterm);
8757  *gaugeval = *gaugeval / (2 * aterm);
8758  }
8759  assert(!SCIPisNegative(scip, *gaugeval));
8760  *success = TRUE;
8761 
8762 #ifdef SCIP_DEBUG_GAUGE
8763  printf("Gauge's aterm = %g, bterm = %g, cterm = %g\n", aterm, bterm, cterm);
8764 #endif
8765  return SCIP_OKAY;
8766 }
8767 
8768 /** compute projection of refsol onto feasible region of cons; stores the projection in ref
8769  *
8770  * This method solves
8771  * \f[
8772  * \min \{ ||x - \bar x||^2 : x^T A x + 2 b^T x \le c \}
8773  * \f]
8774  * where \f$ \bar x \f$ is refsol.
8775  * Note that \f$ \bar x \f$ is not feasible, so the optimal solution actually satisfies
8776  * \f[
8777  * \min \{ ||x - \bar x||^2 : x^T A x + 2 b^T x = c \}
8778  * \f]
8779  * Using the eigendecomposition \f$ A = P D P^T \f$, the change of variables \f$ y = P^T x
8780  * \f$ and the optimality conditions, this reduces to finding \f$ \rho \f$ such that
8781  * \f[
8782  * y(\rho) = (I + \rho D)^{-1} (\bar y - \rho \bar b)
8783  * \f]
8784  * 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$
8785  * D \neq 0 \f$, the function
8786  * \f[
8787  * \varphi(\rho) := y(\rho)^T D y(\rho) + 2 \bar b^T y(\rho) - c
8788  * \f]
8789  * is strictly convex. So this method actually computes the unique 0 of this function using Newton's method.
8790  */
8791 static
8793  SCIP* scip, /**< SCIP data structure */
8794  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8795  SCIP_CONS* cons, /**< constraint */
8796  SCIP_SOL* refsol, /**< the given point to project, or NULL if LP solution should be used */
8797  SCIP_Real* ref /**< array to store reference point */
8798  )
8799 {
8800  SCIP_CONSDATA* consdata;
8801  SCIP_Real* pt; /* stores P^T */
8802  SCIP_Real* bp;
8803  SCIP_Real* D;
8804  SCIP_Real* y0_;
8805  SCIP_Real* yrho;
8806  SCIP_Real* yrhoprime;
8807  SCIP_Real c;
8808  SCIP_Real c1;
8809  SCIP_Real c2;
8810  SCIP_Real rho;
8811  SCIP_Real phirho;
8812  SCIP_Real phirhoprime;
8813  SCIP_Bool isconcave;
8814  int iter;
8815  int i;
8816  int j;
8817  int n;
8818 
8819  assert(scip != NULL);
8820  assert(conshdlr != NULL);
8821  assert(cons != NULL);
8822 
8823  consdata = SCIPconsGetData(cons);
8824  assert(consdata != NULL);
8825  assert(consdata->isedavailable);
8826 
8827  SCIPdebugMessage("computing projection\n");
8828 
8829  /* get the data we need */
8830  pt = consdata->eigenvectors;
8831  D = consdata->eigenvalues;
8832  n = consdata->nquadvars;
8833  bp = consdata->bp;
8834  c = consdata->rhs;
8835  c1 = 0;
8836  c2 = 0;
8837  for( i = 0; i < consdata->nlinvars; i++ )
8838  {
8839  c1 += consdata->lincoefs[i] * SCIPgetSolVal(scip, refsol, consdata->linvars[i]);
8840  c2 -= consdata->lincoefs[i] * consdata->lincoefs[i];
8841  }
8842  c2 /= 2.0;
8843 
8844  /* determine if convex or concave */
8845  isconcave = consdata->isconcave;
8846  assert((isconcave && !SCIPisInfinity(scip, -consdata->lhs)) || !SCIPisInfinity(scip, consdata->rhs));
8847 
8848  SCIP_CALL( SCIPallocClearBufferArray(scip, &y0_, n) );
8849  SCIP_CALL( SCIPallocBufferArray(scip, &yrho, n) );
8850  SCIP_CALL( SCIPallocBufferArray(scip, &yrhoprime, n) );
8851 
8852  /* change data if function is concave */
8853  if( isconcave )
8854  {
8855  c = -consdata->lhs;
8856  c1 = - c1;
8857  for( i = 0; i < n; i++ )
8858  {
8859  D[i] = -D[i];
8860  bp[i] = -bp[i];
8861  }
8862  }
8863 
8864  /* change coordinates: compute y(0) = x_0' * P */
8865  for( i = 0; i < n; i++ )
8866  for( j = 0; j < n; j++ )
8867  y0_[i] += SCIPgetSolVal(scip, refsol, consdata->quadvarterms[j].var) * pt[i*n + j];
8868 
8869 #ifdef DEBUG_PROJ
8870  /* debug output */
8871  printf("\nP^T:\n");
8872  for( i = 0; i < n; i++ )
8873  {
8874  for( j = 0; j < n; j++ )
8875  printf("%g ", pt[i*n + j]);
8876  printf("\n");
8877  }
8878  printf("x_0: ");
8879  for( i = 0; i < n; i++ )
8880  printf("%g ", SCIPgetSolVal(scip, refsol, consdata->quadvarterms[i].var));
8881  printf("\n");
8882  printf("P^T x_0: ");
8883  for( i = 0; i < n; i++ )
8884  printf("%g ", y0_[i]);
8885  printf("\n");
8886  printf("P^T b: ");
8887  for( i = 0; i < n; i++ )
8888  printf("%g ", bp[i]);
8889  printf("\n");
8890  printf("<d,linvars> = %g\n", c1);
8891  printf("-norm(d)^2/2 = %g\n", c2);
8892 #endif
8893 
8894  /* perform newton's method: rho^+ = rho - phi(rho)/phi'(rho) */
8895  rho = 0.0;
8896  phirho = c;
8897  phirhoprime = 1.0;
8898  for( iter = 0; iter < 9; iter++ )
8899  {
8900  assert(phirhoprime != 0.0);
8901  rho = rho - (phirho - c)/ phirhoprime;
8902 
8903  /* compute phi(rho) and phi'(rho):
8904  * note that formulas were deduced for constraints of the form x' A x + 2 b x, so we use b/2 in the formulas:
8905  * c1 = <lin_coefs, sol_lin_vars>
8906  * c2 = - norm(lin_coefs)^2/2
8907  * y(rho) = (I + rho * D)^-1 * (y(0) - rho * bp/2)
8908  * y'(rho) = -(I + rho * D)^-2 * (D y(0) + bp/2)
8909  * phi(rho) = <y(rho), D * y(rho) + pb> + c1 + c2*rho
8910  * phi'(rho) = <y'(rho), 2 * D * y(rho) + pb> + c2
8911  */
8912  phirho = 0.0;
8913  phirhoprime = 0.0;
8914  for( i = 0; i < n; i++ )
8915  {
8916  assert(1.0 + rho * D[i] != 0.0);
8917  yrho[i] = (y0_[i] - rho * bp[i]/2.0) / (1.0 + rho * D[i]);
8918  yrhoprime[i] = -(D[i] * y0_[i] + bp[i]/2.0) / ( (1.0 + rho * D[i])*(1.0 + rho * D[i]) );
8919  phirho += yrho[i] * (yrho[i] * D[i] + bp[i]);
8920  phirhoprime += yrhoprime[i] * (2 * D[i] * yrho[i] + bp[i]);
8921  }
8922  phirho += c2 * rho + c1;
8923  phirhoprime += c2;
8924 #ifdef DEBUG_PROJ
8925  printf("iteration %d: rho = %g, phirho = %g, phirho' = %g\n", iter, rho, phirho, phirhoprime);
8926 #endif
8927  }
8928 
8929  /* come back to the original coordinates: new ref point is P*yrho */
8930  for( i = 0; i < n; i++ )
8931  {
8932  ref[i] = 0.0;
8933 
8934  for( j = 0; j < n; j++ )
8935  ref[i] += pt[j*n + i] * yrho[j];
8936  }
8937 
8938  /* change data back if function is concave */
8939  if( isconcave )
8940  {
8941  for( i = 0; i < n; i++ )
8942  {
8943  D[i] = -D[i];
8944  bp[i] = -bp[i];
8945  }
8946  }
8947 
8948 #ifdef SCIP_DISABLED_CODE
8949  /* project onto bounds; this is important for some cut generation methods such as generateCutLTI */
8950  for( j = 0; j < consdata->nquadvars; ++j )
8951  {
8952  SCIP_Real lb;
8953  SCIP_Real ub;
8954  SCIP_VAR* var;
8955 
8956  var = consdata->quadvarterms[j].var;
8957  lb = SCIPvarGetLbLocal(var);
8958  ub = SCIPvarGetUbLocal(var);
8959  /* do not like variables at infinity */
8960  assert(!SCIPisInfinity(scip, lb));
8961  assert(!SCIPisInfinity(scip, -ub));
8962 
8963  ref[j] = MIN(ub, MAX(lb, ref[j])); /* project value into bounds */
8964  }
8965 #endif
8966 
8967 #ifdef DEBUG_PROJ
8968  printf("modified reference point by a projection:\n");
8969  for( j = 0; j < consdata->nquadvars; ++j )
8970  {
8971  printf("%s = %g\n", SCIPvarGetName(consdata->quadvarterms[j].var), ref[j]);
8972  }
8973 #endif
8974 
8975  SCIPfreeBufferArray(scip, &y0_);
8976  SCIPfreeBufferArray(scip, &yrho);
8977  SCIPfreeBufferArray(scip, &yrhoprime);
8978 
8979  return SCIP_OKAY;
8980 }
8981 
8982 /** compute reference point suggested by gauge function */
8983 static
8985  SCIP* scip, /**< SCIP data structure */
8986  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8987  SCIP_CONS* cons, /**< constraint */
8988  SCIP_SOL* refsol, /**< reference point where to compute gauge, or NULL if LP solution should be used */
8989  SCIP_Real* ref, /**< array to store reference point */
8990  SCIP_Bool* success /**< buffer to store whether we succeeded computing reference point */
8991  )
8992 {
8993  SCIP_CONSDATA* consdata;
8994  SCIP_Real gaugeval;
8995  SCIP_Real intpoint;
8996  SCIP_Real lb;
8997  SCIP_Real ub;
8998  SCIP_VAR* var;
8999  int j;
9000 
9001  assert(scip != NULL);
9002  assert(conshdlr != NULL);
9003  assert(cons != NULL);
9004 
9005  consdata = SCIPconsGetData(cons);
9006  assert(consdata != NULL);
9007  assert(consdata->isgaugeavailable);
9008 
9009  SCIPdebugMsg(scip, "evaluating gauge\n");
9010  SCIP_CALL( evaluateGauge(scip, conshdlr, cons, refsol, &gaugeval, success) );
9011 
9012  if( !(*success) )
9013  {
9014 #ifdef SCIP_DEBUG_GAUGE
9015  printf("Couldn't evaluate gauge!\n");
9016 #endif
9017  return SCIP_OKAY;
9018  }
9019 
9020 #ifdef SCIP_DEBUG_GAUGE
9021  {
9022  SCIP_Real level;
9023 
9024  level = consdata->rhs;
9025  for( j = 0; j < consdata->nlinvars; j++ )
9026  level -= SCIPgetSolVal(scip, refsol, consdata->linvars[j]) * consdata->lincoefs[j];
9027 
9028  printf("Summary:\n");
9029  printf("For cons <%s>: gauge at level %g evaluated at (refsol - intpoint) is %.10f\n",
9030  SCIPconsGetName(cons), level, gaugeval);
9031  printf("refsol - intpoint:\n");
9032 
9033  for( j = 0; j < consdata->nquadvars; ++j )
9034  {
9035  SCIP_VAR* vvar;
9036  vvar = consdata->quadvarterms[j].var;
9037  printf("%s: % 20.15g - %g = %g\n", SCIPvarGetName(vvar), SCIPgetSolVal(scip, refsol, vvar),
9038  consdata->interiorpoint[j], SCIPgetSolVal(scip, refsol, vvar) - consdata->interiorpoint[j]);
9039  }
9040  if( SCIPisFeasLE(scip, gaugeval, 1.0) )
9041  printf("refsol is in the closure of the region (gaugeval <= 1), don't modify reference point\n");
9042  }
9043 #endif
9044 
9045  /* scale gauge value so that final point is close to the boundary, but not on the boundary (weakens the cut) */
9046  gaugeval *= GAUGESCALE;
9047 
9048  /* if the point is not sufficiently violated, we don't modify it */
9049  if( SCIPisFeasLE(scip, gaugeval, 1.0) )
9050  {
9051  *success = FALSE;
9052  return SCIP_OKAY;
9053  }
9054 
9055  /* set reference to (refsol - interior point)/gaugeval + interior point and project onto bounds this is important for
9056  * some cut generation methods such as generateCutLTI
9057  * @todo remove the projection onto the bounds; generateCutLTI shouldn't be called for convex constraints
9058  */
9059  for( j = 0; j < consdata->nquadvars; ++j )
9060  {
9061  var = consdata->quadvarterms[j].var;
9062  lb = SCIPvarGetLbLocal(var);
9063  ub = SCIPvarGetUbLocal(var);
9064  /* do not like variables at infinity */
9065  assert(!SCIPisInfinity(scip, lb));
9066  assert(!SCIPisInfinity(scip, -ub));
9067 
9068  intpoint = consdata->interiorpoint[j];
9069  ref[j] = (SCIPgetSolVal(scip, refsol, var) - intpoint) / gaugeval + intpoint;
9070  ref[j] = MIN(ub, MAX(lb, ref[j])); /* project value into bounds */
9071  }
9072 
9073 #ifdef SCIP_DEBUG_GAUGE
9074  printf("successful application of guage: %g\n", gaugeval);
9075  printf("modified reference point:\n");
9076  for( j = 0; j < consdata->nquadvars; ++j )
9077  {
9078  printf("%s = % 20.15g\n", SCIPvarGetName(consdata->quadvarterms[j].var), ref[j]);
9079  }
9080 #endif
9081 
9082  return SCIP_OKAY;
9083 }
9084 
9085 /** generates a cut based on linearization (if convex) or McCormick (if nonconvex) in a solution
9086  * @note mode indicates whether we should modify the point we want to cutoff (sol) via gauge or projection,
9087  * or if just normal linearization should be use, or the default way (whatever is specified via settings)
9088  */
9089 static
9091  SCIP* scip, /**< SCIP data structure */
9092  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9093  SCIP_CONS* cons, /**< constraint */
9094  SCIP_SOL* sol, /**< solution where to generate cut, or NULL if LP solution should be used */
9095  SCIP_SOL* refsol, /**< reference point where to generate cut, or NULL if sol should be used */
9096  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
9097  SCIP_ROW** row, /**< storage for cut */
9098  SCIP_Real* efficacy, /**< buffer to store efficacy of row in reference solution, or NULL if not of interest */
9099  SCIP_Bool checkcurvmultivar, /**< are we allowed to check the curvature of a multivariate quadratic function, if not done yet */
9100  SCIP_Real minefficacy, /**< minimal required efficacy */
9101  char mode /**< mode of execution 'g'auge, 'p'rojection, 'l'inearization gradient, 'd'efault */
9102  )
9103 {
9104  SCIP_CONSHDLRDATA* conshdlrdata;
9105  SCIP_CONSDATA* consdata;
9106  SCIP_VAR* var;
9107  SCIP_Real lb;
9108  SCIP_Real ub;
9109  SCIP_Real* ref;
9110  SCIP_Bool success;
9111  int j;
9112 
9113  assert(scip != NULL);
9114  assert(conshdlr != NULL);
9115  assert(cons != NULL);
9116 
9117  consdata = SCIPconsGetData(cons);
9118  assert(consdata != NULL);
9119 
9120  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9121  assert(conshdlrdata != NULL);
9122 
9123  if( refsol == NULL )
9124  refsol = sol;
9125 
9126  /* get reference point */
9127  SCIP_CALL( SCIPallocBufferArray(scip, &ref, consdata->nquadvars) );
9128  success = FALSE;
9129 
9130  if( mode == 'd')
9131  {
9132  if( (consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) ||
9133  (consdata->isconcave && violside == SCIP_SIDETYPE_LEFT) )
9134  {
9135  if( conshdlrdata->gaugecuts && consdata->isgaugeavailable )
9136  {
9137  SCIP_CALL( computeReferencePointGauge(scip, conshdlr, cons, refsol, ref, &success) );
9138  }
9139  else if( conshdlrdata->projectedcuts && consdata->isedavailable )
9140  {
9141  SCIPdebugMessage("use the projection of refsol onto the region defined by the constraint as reference point\n");
9142  SCIP_CALL( computeReferencePointProjection(scip, conshdlr, cons, refsol, ref) );
9143  success = TRUE;
9144  }
9145  }
9146 
9147  if( success )
9148  {
9149  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
9150 
9151  /* if cut fails, try again without modifying reference point */
9152  if( *row == NULL || (efficacy != NULL && !SCIPisGT(scip, *efficacy, minefficacy)) || !SCIPisCutApplicable(scip, *row) ) /*lint !e644 */
9153  {
9154  SCIPdebugMsg(scip, "%s cut fail, try without modifying\n", conshdlrdata->gaugecuts ? "gauge" : "projected");
9155  success = FALSE;
9156  }
9157  }
9158 
9159  /* note that this is not the same as calling this method with mode 'l', 'l' assume convex/concave function */
9160  if( !success )
9161  {
9162  for( j = 0; j < consdata->nquadvars; ++j )
9163  {
9164  var = consdata->quadvarterms[j].var;
9165  lb = SCIPvarGetLbLocal(var);
9166  ub = SCIPvarGetUbLocal(var);
9167  /* do not like variables at infinity */
9168  assert(!SCIPisInfinity(scip, lb));
9169  assert(!SCIPisInfinity(scip, -ub));
9170 
9171  ref[j] = SCIPgetSolVal(scip, refsol, var);
9172  ref[j] = MIN(ub, MAX(lb, ref[j])); /* project value into bounds */
9173  }
9174 
9175  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
9176  }
9177  }
9178  /* gauge cut */
9179  if( mode == 'g' )
9180  {
9181  assert((consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) || (consdata->isconcave && violside == SCIP_SIDETYPE_LEFT));
9182  if( conshdlrdata->gaugecuts && consdata->isgaugeavailable )
9183  {
9184  SCIP_CALL( computeReferencePointGauge(scip, conshdlr, cons, refsol, ref, &success) );
9185  }
9186  if( success )
9187  {
9188  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
9189  }
9190  }
9191  /* projection cut */
9192  if( mode == 'p' )
9193  {
9194  assert((consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) || (consdata->isconcave && violside == SCIP_SIDETYPE_LEFT));
9195  if( conshdlrdata->projectedcuts && consdata->isedavailable )
9196  {
9197  SCIP_CALL( computeReferencePointProjection(scip, conshdlr, cons, refsol, ref) );
9198  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
9199  }
9200  }
9201  /* gradient linearization cut at refsol */
9202  if( mode == 'l' )
9203  {
9204  assert((consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) || (consdata->isconcave && violside == SCIP_SIDETYPE_LEFT));
9205  for( j = 0; j < consdata->nquadvars; ++j )
9206  {
9207  var = consdata->quadvarterms[j].var;
9208  lb = SCIPvarGetLbLocal(var);
9209  ub = SCIPvarGetUbLocal(var);
9210  /* do not like variables at infinity */
9211  assert(!SCIPisInfinity(scip, lb));
9212  assert(!SCIPisInfinity(scip, -ub));
9213 
9214  ref[j] = SCIPgetSolVal(scip, refsol, var);
9215  ref[j] = MIN(ub, MAX(lb, ref[j])); /* project value into bounds */
9216  }
9217  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
9218  }
9219 
9220  SCIPfreeBufferArray(scip, &ref);
9221 
9222  return SCIP_OKAY;
9223 }
9224 
9225 /** tries to find a cut that intersects with an unbounded ray of the LP
9226  *
9227  * For convex functions, we do this by linearizing in the feasible solution of the LPI.
9228  * For nonconvex functions, we just call generateCutSol with the unbounded solution as reference point.
9229  */
9230 static
9232  SCIP* scip, /**< SCIP data structure */
9233  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9234  SCIP_CONS* cons, /**< constraint */
9235  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
9236  SCIP_ROW** row, /**< storage for cut */
9237  SCIP_Real* rowrayprod, /**< buffer to store product of ray with row coefficients, or NULL if not of interest */
9238  SCIP_Bool checkcurvmultivar /**< are we allowed to check the curvature of a multivariate quadratic function, if not done yet */
9239  )
9240 {
9241  SCIP_CONSDATA* consdata;
9242  SCIP_BILINTERM* bilinterm;
9243  SCIP_VAR* var;
9244  SCIP_Real* ref;
9245  SCIP_Real matrixrayprod;
9246  SCIP_Real linrayprod;
9247  SCIP_Real quadrayprod;
9248  SCIP_Real rayval;
9249  int i;
9250  int j;
9251 
9252  assert(scip != NULL);
9253  assert(conshdlr != NULL);
9254  assert(cons != NULL);
9255  assert(row != NULL);
9257 
9258  consdata = SCIPconsGetData(cons);
9259  assert(consdata != NULL);
9260 
9261  *row = NULL;
9262 
9263  if( !SCIPhasPrimalRay(scip) )
9264  {
9265  SCIPdebugMsg(scip, "do not have primal ray, thus cannot resolve unboundedness\n");
9266  return SCIP_OKAY;
9267  }
9268 
9269  SCIP_CALL( checkCurvature(scip, cons, checkcurvmultivar) );
9270  if( (!consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) ||
9271  (!consdata->isconcave && violside == SCIP_SIDETYPE_LEFT) )
9272  {
9273  /* if not convex, just call generateCut and hope it's getting something useful */
9274  SCIP_CALL( generateCutSol(scip, conshdlr, cons, NULL, NULL, violside, row, NULL, FALSE, -SCIPinfinity(scip), 'd') );
9275 
9276  /* compute product of cut coefficients with ray, if required */
9277  if( *row != NULL && rowrayprod != NULL )
9278  {
9279  *rowrayprod = 0.0;
9280  for( i = 0; i < SCIProwGetNNonz(*row); ++i )
9281  {
9282  assert(SCIProwGetCols(*row)[i] != NULL);
9283  var = SCIPcolGetVar(SCIProwGetCols(*row)[i]);
9284  assert(var != NULL);
9285 
9286  *rowrayprod += SCIProwGetVals(*row)[i] * SCIPgetPrimalRayVal(scip, var);
9287  }
9288  }
9289 
9290  return SCIP_OKAY;
9291  }
9292 
9293  /* we seek for a linearization of the quadratic function such that it intersects with the unbounded ray
9294  * that is, we need a reference point ref such that for the gradient g of xAx+bx in ref, we have
9295  * <g, ray> > 0.0 if rhs is finite and <g, ray> < 0.0 if lhs is finite
9296  * Since g = 2*A*ref + b, we have <g, ray> = <2*A*ref + b, ray> = <ref, 2*A*ray> + <b,ray>
9297  * 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)
9298  * <ref, 2*A*ray> + <b,ray> is sufficiently larger 0.0, we call generateCut for this point, otherwise, we scale up ref
9299  */
9300 
9301  quadrayprod = 0.0; /* <ref, 2*A*ray> */
9302  linrayprod = 0.0; /* <b, ray> */
9303  SCIP_CALL( SCIPallocBufferArray(scip, &ref, consdata->nquadvars) );
9304  for( i = 0; i < consdata->nquadvars; ++i )
9305  {
9306  var = consdata->quadvarterms[i].var;
9307  rayval = SCIPgetPrimalRayVal(scip, var);
9308 
9309  /* compute i-th entry of (2*A*ray) */
9310  matrixrayprod = 2.0 * consdata->quadvarterms[i].sqrcoef * rayval;
9311  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
9312  {
9313  bilinterm = &consdata->bilinterms[consdata->quadvarterms[i].adjbilin[j]];
9314  matrixrayprod += bilinterm->coef * SCIPgetPrimalRayVal(scip, bilinterm->var1 == var ? bilinterm->var2 : bilinterm->var1);
9315  }
9316 
9317  if( SCIPisPositive(scip, matrixrayprod) )
9318  ref[i] = (violside == SCIP_SIDETYPE_RIGHT ? 1.0 : -1.0);
9319  else if( SCIPisNegative(scip, matrixrayprod) )
9320  ref[i] = (violside == SCIP_SIDETYPE_RIGHT ? -1.0 : 1.0);
9321  else
9322  ref[i] = 0.0;
9323 
9324  quadrayprod += matrixrayprod * ref[i];
9325  linrayprod += consdata->quadvarterms[i].lincoef * rayval;
9326  }
9327  assert((violside == SCIP_SIDETYPE_RIGHT && quadrayprod >= 0.0) || (violside == SCIP_SIDETYPE_LEFT && quadrayprod <= 0.0));
9328 
9329  if( SCIPisZero(scip, quadrayprod) )
9330  {
9331  SCIPdebugMsg(scip, "ray is zero along cons <%s>\n", SCIPconsGetName(cons));
9332  SCIPfreeBufferArray(scip, &ref);
9333  return SCIP_OKAY;
9334  }
9335 
9336  /* add linear part to linrayprod */
9337  for( i = 0; i < consdata->nlinvars; ++i )
9338  linrayprod += consdata->lincoefs[i] * SCIPgetPrimalRayVal(scip, consdata->linvars[i]);
9339 
9340  SCIPdebugMsg(scip, "initially have <b,ray> = %g and <ref, 2*A*ref> = %g\n", linrayprod, quadrayprod);
9341 
9342  /* 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
9343  * if <b,ray> is zero, then we scale refpoint up if |<ref, 2*A*ray>| < 1.0
9344  */
9345  if( (!SCIPisZero(scip, linrayprod) && violside == SCIP_SIDETYPE_RIGHT && quadrayprod < -2*linrayprod) ||
9346  ( !SCIPisZero(scip, linrayprod) && violside == SCIP_SIDETYPE_LEFT && quadrayprod > -2*linrayprod) ||
9347  (SCIPisZero(scip, linrayprod) && REALABS(quadrayprod) < 1.0) )
9348  {
9349  SCIP_Real scale;
9350 
9351  if( !SCIPisZero(scip, linrayprod) )
9352  scale = 2*REALABS(linrayprod/quadrayprod); /*lint !e795 */
9353  else
9354  scale = 1.0/REALABS(quadrayprod);
9355 
9356  SCIPdebugMsg(scip, "scale refpoint by %g\n", scale);
9357  for( i = 0; i < consdata->nquadvars; ++i )
9358  ref[i] *= scale;
9359  quadrayprod *= scale;
9360  }
9361 
9362  if( rowrayprod != NULL )
9363  *rowrayprod = quadrayprod + linrayprod;
9364 
9365  SCIPdebugMsg(scip, "calling generateCut, expecting ray product %g\n", quadrayprod + linrayprod);
9366  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, NULL, violside, row, NULL, FALSE, -SCIPinfinity(scip)) );
9367 
9368  SCIPfreeBufferArray(scip, &ref);
9369 
9370  return SCIP_OKAY;
9371 }
9372 
9373 /** processes a cut for constraint cons, i.e., checks numerics and possibly adds cut to sepastore */
9374 static
9376  SCIP* scip, /**< SCIP data structure */
9377  SCIP_ROW** row, /**< cut to process */
9378  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
9379  SCIP_CONS* cons, /**< constraint */
9380  SCIP_Real efficacy, /**< efficacy of row in reference solution */
9381  SCIP_Real minefficacy, /**< minimal efficacy */
9382  SCIP_Bool inenforcement, /**< whether we are in constraint enforcement */
9383  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 */
9384  SCIP_RESULT* result /**< result of separation */
9385  )
9386 {
9387  SCIP_CONSDATA* consdata;
9388  SCIP_CONSHDLRDATA* conshdlrdata;
9389 
9390  assert(scip != NULL);
9391  assert(row != NULL);
9392  assert(conshdlr != NULL);
9393  assert(result != NULL);
9394  assert(cons != NULL);
9395 
9396  /* no cut to process */
9397  if( *row == NULL )
9398  return SCIP_OKAY;
9399 
9400  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9401  assert(conshdlrdata != NULL);
9402 
9403  consdata = SCIPconsGetData(cons);
9404  assert(consdata != NULL);
9405 
9406  if( SCIPisGT(scip, efficacy, minefficacy) && SCIPisCutApplicable(scip, *row) ) /*lint !e644 */
9407  {
9408  SCIP_Bool infeasible;
9409 
9410  /* cut cuts off solution */
9411  SCIP_CALL( SCIPaddRow(scip, *row, FALSE /* forcecut */, &infeasible) );
9412  if( infeasible )
9413  {
9414  SCIPdebugMessage("cut for constraint <%s> is infeasible -> cutoff.\n", SCIPconsGetName(cons));
9415  *result = SCIP_CUTOFF;
9416  }
9417  else
9418  {
9419  SCIPdebugMessage("add cut with efficacy %g for constraint <%s> violated by %g\n", efficacy,
9420  SCIPconsGetName(cons), consdata->lhsviol+consdata->rhsviol);
9421  *result = SCIP_SEPARATED;
9422  }
9423  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9424 
9425  /* mark row as not removable from LP for current node, if in enforcement */
9426  if( inenforcement && !conshdlrdata->enfocutsremovable )
9427  SCIPmarkRowNotRemovableLocal(scip, *row);
9428  }
9429  if( bestefficacy != NULL && efficacy > *bestefficacy )
9430  *bestefficacy = efficacy;
9431 
9432  SCIP_CALL( SCIPreleaseRow (scip, row) );
9433  return SCIP_OKAY;
9434 }
9435 
9436 /** tries to separate solution or LP solution by a linear cut
9437  *
9438  * assumes that constraint violations have been computed
9439  */
9440 static
9442  SCIP* scip, /**< SCIP data structure */
9443  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
9444  SCIP_CONS** conss, /**< constraints */
9445  int nconss, /**< number of constraints */
9446  int nusefulconss, /**< number of constraints that seem to be useful */
9447  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
9448  SCIP_Real minefficacy, /**< minimal efficacy of a cut if it should be added to the LP */
9449  SCIP_Bool inenforcement, /**< whether we are in constraint enforcement */
9450  SCIP_RESULT* result, /**< result of separation */
9451  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 */
9452  )
9453 {
9454  SCIP_CONSHDLRDATA* conshdlrdata;
9455  SCIP_CONSDATA* consdata;
9456  SCIP_Real efficacy;
9457  SCIP_SIDETYPE violside;
9458  int c;
9459  SCIP_ROW* row;
9460 
9461  assert(scip != NULL);
9462  assert(conshdlr != NULL);
9463  assert(conss != NULL || nconss == 0);
9464  assert(nusefulconss <= nconss);
9465  assert(result != NULL);
9466 
9467  *result = SCIP_FEASIBLE;
9468 
9469  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9470  assert(conshdlrdata != NULL);
9471 
9472  if( bestefficacy != NULL )
9473  *bestefficacy = 0.0;
9474 
9475  row = NULL;
9476  /* loop over both sides of each constraint */
9477  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) )
9478  {
9479  assert(conss != NULL);
9480  consdata = SCIPconsGetData(conss[c]);
9481  assert(consdata != NULL);
9482 
9483  /* if side not violated, then go on */
9484  if( !SCIPisGT(scip, violside == SCIP_SIDETYPE_LEFT ? consdata->lhsviol : consdata->rhsviol, SCIPfeastol(scip)) )
9485  continue;
9486 
9487  /* we are not feasible anymore */
9488  if( *result == SCIP_FEASIBLE )
9489  *result = SCIP_DIDNOTFIND;
9490 
9491  /* generate cut */
9492  if( sol == NULL && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY )
9493  {
9494  /* if the LP is unbounded, then we need a cut that cuts into the direction of a hopefully existing primal ray
9495  * 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
9496  * given a cut lhs <= <c,x> <= rhs, we check whether it imposes an upper bound on t and thus bounds the ray
9497  * 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>
9498  * similar, lhs > -infinity and <c,r> < 0 is good
9499  */
9500  SCIP_Real rayprod;
9501 
9502  rayprod = 0.0; /* for compiler */
9503  SCIP_CALL( generateCutUnboundedLP(scip, conshdlr, conss[c], violside, &row, &rayprod, conshdlrdata->checkcurvature) );
9504 
9505  if( row != NULL )
9506  {
9507  if( !SCIPisInfinity(scip, SCIProwGetRhs(row)) && SCIPisPositive(scip, rayprod) )
9508  efficacy = rayprod;
9509  else if( !SCIPisInfinity(scip, -SCIProwGetLhs(row)) && SCIPisNegative(scip, rayprod) )
9510  efficacy = -rayprod;
9511  else
9512  efficacy = 0.0;
9513 
9514  SCIP_CALL( processCut(scip, &row, conshdlr, conss[c], efficacy, minefficacy, inenforcement, bestefficacy, result) );
9515  }
9516  continue;
9517  }
9518  else
9519  {
9520  SCIP_CALL( generateCutSol(scip, conshdlr, conss[c], sol, NULL, violside, &row, &efficacy,
9521  conshdlrdata->checkcurvature, minefficacy, 'd') );
9522 
9523  SCIP_CALL( processCut(scip, &row, conshdlr, conss[c], efficacy, minefficacy, inenforcement, bestefficacy, result) );
9524  }
9525 
9526  if( *result == SCIP_CUTOFF )
9527  break;
9528 
9529  /* enforce only useful constraints
9530  * others are only checked and enforced if we are still feasible or have not found a separating cut yet
9531  */
9532  if( c >= nusefulconss && *result == SCIP_SEPARATED )
9533  break;
9534  }
9535 
9536  return SCIP_OKAY;
9537 }
9538 
9539 /** adds linearizations cuts for convex constraints w.r.t. a given reference point to cutpool and sepastore
9540  *
9541  * - 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.
9542  * - If separatedlpsol is not NULL, but cut does not separate the LP solution, then it is added to the cutpool only.
9543  * - If separatedlpsol is NULL, then cut is added to cutpool only.
9544  */
9545 static
9547  SCIP* scip, /**< SCIP data structure */
9548  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
9549  SCIP_CONS** conss, /**< constraints */
9550  int nconss, /**< number of constraints */
9551  SCIP_SOL* ref, /**< reference point where to linearize, or NULL for LP solution */
9552  SCIP_Bool* separatedlpsol, /**< buffer to store whether a cut that separates the current LP solution was found and added to LP,
9553  * or NULL if adding to cutpool only */
9554  SCIP_Real minefficacy /**< minimal efficacy of a cut when checking for separation of LP solution */
9555  )
9556 {
9557  SCIP_CONSHDLRDATA* conshdlrdata;
9558  SCIP_CONSDATA* consdata;
9559  SCIP_Bool addedtolp;
9560  SCIP_ROW* row;
9561  int c;
9562 
9563  assert(scip != NULL);
9564  assert(conshdlr != NULL);
9565  assert(conss != NULL || nconss == 0);
9566 
9567  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9568  assert(conshdlrdata != NULL);
9569 
9570  if( separatedlpsol != NULL )
9571  *separatedlpsol = FALSE;
9572 
9573  for( c = 0; c < nconss; ++c )
9574  {
9575  assert(conss[c] != NULL); /*lint !e613 */
9576 
9577  if( SCIPconsIsLocal(conss[c]) || !SCIPconsIsEnabled(conss[c]) ) /*lint !e613 */
9578  continue;
9579 
9580  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
9581 
9582  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
9583  assert(consdata != NULL);
9584 
9585  if( consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs) )
9586  {
9587  SCIP_CALL( generateCutSol(scip, conshdlr, conss[c], NULL, ref, SCIP_SIDETYPE_RIGHT, &row, NULL,
9588  conshdlrdata->checkcurvature, -SCIPinfinity(scip), 'l') ); /*lint !e613 */
9589  }
9590  else if( consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs) )
9591  {
9592  SCIP_CALL( generateCutSol(scip, conshdlr, conss[c], NULL, ref, SCIP_SIDETYPE_LEFT, &row, NULL,
9593  conshdlrdata->checkcurvature, -SCIPinfinity(scip), 'l') ); /*lint !e613 */
9594  }
9595  else
9596  continue;
9597 
9598  if( row == NULL )
9599  continue;
9600 
9601  addedtolp = FALSE;
9602 
9603  /* if caller wants, then check if cut separates LP solution and add to sepastore if so */
9604  if( separatedlpsol != NULL )
9605  {
9606  SCIP_Real efficacy;
9607 
9608  efficacy = -SCIPgetRowLPFeasibility(scip, row);
9609  if( efficacy >= minefficacy )
9610  {
9611  SCIP_Bool infeasible;
9612 
9613  *separatedlpsol = TRUE;
9614  addedtolp = TRUE;
9615  SCIP_CALL( SCIPaddRow(scip, row, TRUE, &infeasible) );
9616  assert( ! infeasible );
9617  SCIPdebugMsg(scip, "added linearization cut <%s> to LP, efficacy = %g\n", SCIProwGetName(row), efficacy);
9618  }
9619  }
9620 
9621  if( !SCIProwIsLocal(row) && !addedtolp )
9622  {
9623  SCIP_CALL( SCIPaddPoolCut(scip, row) );
9624  SCIPdebugMsg(scip, "added linearization cut <%s> to cutpool\n", SCIProwGetName(row));
9625  }
9626 
9627  SCIP_CALL( SCIPreleaseRow(scip, &row) );
9628  }
9629 
9630  return SCIP_OKAY;
9631 }
9632 
9633 /** processes the event that a new primal solution has been found */
9634 static
9635 SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
9637  SCIP_CONSHDLRDATA* conshdlrdata;
9638  SCIP_CONSHDLR* conshdlr;
9639  SCIP_CONS** conss;
9640  int nconss;
9641  SCIP_SOL* sol;
9642 
9643  assert(scip != NULL);
9644  assert(event != NULL);
9645  assert(eventdata != NULL);
9646  assert(eventhdlr != NULL);
9647 
9648  assert((SCIPeventGetType(event) & SCIP_EVENTTYPE_SOLFOUND) != 0);
9649 
9650  conshdlr = (SCIP_CONSHDLR*)eventdata;
9651 
9652  nconss = SCIPconshdlrGetNConss(conshdlr);
9653 
9654  if( nconss == 0 )
9655  return SCIP_OKAY;
9656 
9657  sol = SCIPeventGetSol(event);
9658  assert(sol != NULL);
9659 
9660  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9661  assert(conshdlrdata != NULL);
9662 
9663  /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
9664  * the reason for ignoring trysol solutions is that they may come from an NLP solve in sepalp, where we already added linearizations,
9665  * or are from the tree, but postprocessed via proposeFeasibleSolution
9666  */
9667  if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
9668  return SCIP_OKAY;
9669 
9670  conss = SCIPconshdlrGetConss(conshdlr);
9671  assert(conss != NULL);
9672 
9673  SCIPdebugMsg(scip, "caught new sol event %" SCIP_EVENTTYPE_FORMAT " from heur <%s>; have %d conss\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)), nconss);
9674 
9675  SCIP_CALL( addLinearizationCuts(scip, conshdlr, conss, nconss, sol, NULL, 0.0) );
9676 
9677  return SCIP_OKAY;
9678 }
9679 
9680 /** registers branching candidates according to convexification gap rule
9681  *
9682  * That is, computes for every nonconvex term the gap between the terms value in the LP solution and the value of the underestimator
9683  * as it would be (and maybe has been) constructed by the separation routines of this constraint handler. Then it registers all
9684  * variables occurring in each term with the computed gap. If variables appear in more than one term, they are registered several times.
9685  */
9686 static
9688  SCIP* scip, /**< SCIP data structure */
9689  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9690  SCIP_CONS** conss, /**< constraints to check */
9691  int nconss, /**< number of constraints to check */
9692  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
9693  int* nnotify /**< counter for number of notifications performed */
9694  )
9695 {
9696  SCIP_CONSHDLRDATA* conshdlrdata;
9697  SCIP_CONSDATA* consdata;
9698  int c;
9699  int j;
9700  SCIP_Bool xbinary;
9701  SCIP_Bool ybinary;
9702  SCIP_Bool xunbounded;
9703  SCIP_Bool yunbounded;
9704  SCIP_VAR* x;
9705  SCIP_VAR* y;
9706  SCIP_Real xlb;
9707  SCIP_Real xub;
9708  SCIP_Real xval;
9709  SCIP_Real ylb;
9710  SCIP_Real yub;
9711  SCIP_Real yval;
9712  SCIP_Real gap;
9713  SCIP_Real coef_;
9714 
9715  assert(scip != NULL);
9716  assert(conshdlr != NULL);
9717  assert(conss != NULL || nconss == 0);
9718 
9719  *nnotify = 0;
9720  yval = SCIP_INVALID;
9721  xval = SCIP_INVALID;
9722 
9723  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9724  assert(conshdlr != NULL);
9725 
9726  for( c = 0; c < nconss; ++c )
9727  {
9728  assert(conss != NULL);
9729  consdata = SCIPconsGetData(conss[c]);
9730  assert(consdata != NULL);
9731 
9732  if( !consdata->nquadvars )
9733  continue;
9734 
9735  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || consdata->isconcave) &&
9736  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || consdata->isconvex ) )
9737  continue;
9738  SCIPdebugMsg(scip, "cons <%s> violation: %g %g convex: %u %u\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->isconvex, consdata->isconcave);
9739 
9740  /* square terms */
9741  for( j = 0; j < consdata->nquadvars; ++j )
9742  {
9743  x = consdata->quadvarterms[j].var;
9744  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && consdata->quadvarterms[j].sqrcoef < 0) ||
9745  ( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && consdata->quadvarterms[j].sqrcoef > 0) )
9746  {
9747  xlb = SCIPvarGetLbLocal(x);
9748  xub = SCIPvarGetUbLocal(x);
9749  if( SCIPisRelEQ(scip, xlb, xub) )
9750  {
9751  SCIPdebugMsg(scip, "ignore fixed variable <%s>[%g, %g], diff %g\n", SCIPvarGetName(x), xlb, xub, xub-xlb);
9752  continue;
9753  }
9754 
9755  xval = SCIPgetSolVal(scip, sol, x);
9756 
9757  /* if variable is at bounds, then no need to branch, since secant is exact there */
9758  if( SCIPisLE(scip, xval, xlb) || SCIPisGE(scip, xval, xub) )
9759  continue;
9760 
9761  if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) )
9762  gap = SCIPinfinity(scip);
9763  else
9764  gap = (xval-xlb)*(xub-xval)/(1+2*ABS(xval));
9765  assert(!SCIPisFeasNegative(scip, gap));
9766  SCIP_CALL( SCIPaddExternBranchCand(scip, x, MAX(gap, 0.0), SCIP_INVALID) );
9767  ++*nnotify;
9768  }
9769  }
9770 
9771  /* bilinear terms */
9772  for( j = 0; j < consdata->nbilinterms; ++j )
9773  {
9774  /* if any of the variables if fixed, then it actually behaves like a linear term, so we don't need to branch on it */
9775  x = consdata->bilinterms[j].var1;
9776  xlb = SCIPvarGetLbLocal(x);
9777  xub = SCIPvarGetUbLocal(x);
9778  if( SCIPisRelEQ(scip, xlb, xub) )
9779  continue;
9780 
9781  y = consdata->bilinterms[j].var2;
9782  ylb = SCIPvarGetLbLocal(y);
9783  yub = SCIPvarGetUbLocal(y);
9784  if( SCIPisRelEQ(scip, ylb, yub) )
9785  continue;
9786 
9787  xunbounded = SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub);
9788  yunbounded = SCIPisInfinity(scip, -ylb) || SCIPisInfinity(scip, yub);
9789 
9790  /* compute gap, if both variable are bounded */
9791  gap = SCIPinfinity(scip);
9792  if( !xunbounded && !yunbounded )
9793  {
9794  xval = SCIPgetSolVal(scip, sol, x);
9795  yval = SCIPgetSolVal(scip, sol, y);
9796 
9797  /* if both variables are at one of its bounds, then no need to branch, since McCormick is exact there */
9798  if( (SCIPisLE(scip, xval, xlb) || SCIPisGE(scip, xval, xub)) &&
9799  ( SCIPisLE(scip, yval, ylb) || SCIPisGE(scip, yval, yub)) )
9800  continue;
9801 
9802  xval = MAX(xlb, MIN(xval, xub));
9803  yval = MAX(ylb, MIN(yval, yub));
9804 
9805  coef_ = SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) ? -consdata->bilinterms[j].coef : consdata->bilinterms[j].coef;
9806  if( coef_ > 0.0 )
9807  {
9808  if( (xub-xlb)*yval + (yub-ylb)*xval <= xub*yub - xlb*ylb )
9809  gap = (xval*yval - xlb*yval - ylb*xval + xlb*ylb) / (1+sqrt(xval*xval + yval*yval));
9810  else
9811  gap = (xval*yval - xval*yub - yval*xub + xub*yub) / (1+sqrt(xval*xval + yval*yval));
9812  }
9813  else
9814  { /* coef_ < 0 */
9815  if( (xub-xlb)*yval - (yub-ylb)*xval <= xub*ylb - xlb*yub )
9816  gap = -(xval*yval - xval*ylb - yval*xub + xub*ylb) / (1+sqrt(xval*xval + yval*yval));
9817  else
9818  gap = -(xval*yval - xval*yub - yval*xlb + xlb*yub) / (1+sqrt(xval*xval + yval*yval));
9819  }
9820 
9821  assert(!SCIPisNegative(scip, gap / MAX3(MAX(REALABS(xlb), REALABS(xub)), MAX(REALABS(ylb), REALABS(yub)), 1.0))); /*lint !e666*/
9822  if( gap < 0.0 )
9823  gap = 0.0;
9824 
9825  /* use tighter relaxation when using linear inequalities to adjust the branching scores for bilinear terms */
9826  if( consdata->bilintermsidx != NULL && conshdlrdata->usebilinineqbranch )
9827  {
9828  BILINESTIMATOR* bilinestimator;
9829  int bilinidx;
9830 
9831  assert(conshdlrdata->bilinestimators != NULL);
9832 
9833  bilinidx = consdata->bilintermsidx[j];
9834  assert(bilinidx >= 0 && bilinidx < conshdlrdata->nbilinterms);
9835 
9836  bilinestimator = &conshdlrdata->bilinestimators[bilinidx];
9837  assert(bilinestimator != NULL);
9838  assert(bilinestimator->x == x);
9839  assert(bilinestimator->y == y);
9840 
9841  if( SCIPisGT(scip, bilinestimator->lastimprfac, 0.0) )
9842  gap *= MAX(0.0, 1.0 - bilinestimator->lastimprfac);
9843  }
9844  }
9845 
9846  /* if one of the variables is binary or integral with domain width 1, then branching on this makes the term linear, so prefer this */
9847  xbinary = SCIPvarIsBinary(x) || (SCIPvarIsIntegral(x) && xub - xlb < 1.5);
9848  ybinary = SCIPvarIsBinary(y) || (SCIPvarIsIntegral(y) && yub - ylb < 1.5);
9849  if( xbinary )
9850  {
9852  ++*nnotify;
9853  }
9854  if( ybinary )
9855  {
9857  ++*nnotify;
9858  }
9859  if( xbinary || ybinary )
9860  continue;
9861 
9862  /* if one of the variables is unbounded, then branch on it first */
9863  if( xunbounded )
9864  {
9866  ++*nnotify;
9867  }
9868  if( yunbounded )
9869  {
9871  ++*nnotify;
9872  }
9873  if( xunbounded || yunbounded )
9874  continue;
9875 
9876  /* if both variables are integral, prefer the one with the smaller domain, so variable gets fixed soon
9877  * does not seem to work well on tln instances, so disable for now and may look at it later again
9878  */
9879 #ifdef BRANCHTOLINEARITY
9880  if( SCIPvarIsIntegral(x) && SCIPvarIsIntegral(y) )
9881  {
9882  if( SCIPisLT(scip, xub-xlb, yub-ylb) )
9883  {
9885  ++*nnotify;
9886  continue;
9887  }
9888  if( SCIPisGT(scip, xub-xlb, yub-ylb) )
9889  {
9891  ++*nnotify;
9892  continue;
9893  }
9894  }
9895 #endif
9896 
9897  /* in the regular case, suggest those variables which are not at its bounds for branching
9898  * this is, because after branching both variables will be one the bounds, and McCormick will be exact then */
9899  if( !SCIPisLE(scip, xval, xlb) && !SCIPisGE(scip, xval, xub) )
9900  {
9902  ++*nnotify;
9903  }
9904  if( !SCIPisLE(scip, yval, ylb) && !SCIPisGE(scip, yval, yub) )
9905  {
9907  ++*nnotify;
9908  }
9909  }
9910  }
9911 
9912  SCIPdebugMsg(scip, "registered %d branching candidates\n", *nnotify);
9913 
9914  return SCIP_OKAY;
9915 }
9916 
9917 /** registers branching candidates according to constraint violation rule
9918  *
9919  * That is, registers all variables appearing in nonconvex terms^1 with a score that is the violation of the constraint.
9920  * This is the same rule as is applied in cons_nonlinear and other nonlinear constraint handlers.
9921  *
9922  * 1) We mean all quadratic variables that appear either in a nonconvex square term or in a bilinear term, if the constraint
9923  * itself is nonconvex. (and this under the assumption that the rhs is violated; for violated lhs, swap terms)
9924  */
9925 static
9927  SCIP* scip, /**< SCIP data structure */
9928  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9929  SCIP_CONS** conss, /**< constraints to check */
9930  int nconss, /**< number of constraints to check */
9931  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
9932  int* nnotify /**< counter for number of notifications performed */
9933  )
9934 {
9935  SCIP_CONSDATA* consdata;
9936  SCIP_QUADVARTERM* quadvarterm;
9937  int c;
9938  int j;
9939  SCIP_VAR* x;
9940  SCIP_Real xlb;
9941  SCIP_Real xub;
9942  SCIP_Real xval;
9943 
9944  assert(scip != NULL);
9945  assert(conshdlr != NULL);
9946  assert(conss != NULL || nconss == 0);
9947 
9948  *nnotify = 0;
9949 
9950  for( c = 0; c < nconss; ++c )
9951  {
9952  assert(conss != NULL);
9953  consdata = SCIPconsGetData(conss[c]);
9954  assert(consdata != NULL);
9955 
9956  if( !consdata->nquadvars )
9957  continue;
9958 
9959  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || consdata->isconcave) &&
9960  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || consdata->isconvex ) )
9961  continue;
9962  SCIPdebugMsg(scip, "cons %s violation: %g %g convex: %u %u\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->isconvex, consdata->isconcave);
9963 
9964  for( j = 0; j < consdata->nquadvars; ++j )
9965  {
9966  quadvarterm = &consdata->quadvarterms[j];
9967  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef < 0) ||
9968  (SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef > 0) ||
9969  quadvarterm->nadjbilin > 0 )
9970  {
9971  x = quadvarterm->var;
9972  xlb = SCIPvarGetLbLocal(x);
9973  xub = SCIPvarGetUbLocal(x);
9974 
9975  if( quadvarterm->nadjbilin == 0 )
9976  {
9977  xval = SCIPgetSolVal(scip, sol, x);
9978 
9979  /* if variable is at bounds and only in a nonconvex square term, then no need to branch, since secant is exact there */
9980  if( SCIPisLE(scip, xval, xlb) || SCIPisGE(scip, xval, xub) )
9981  continue;
9982  }
9983 
9984  if( SCIPisRelEQ(scip, xlb, xub) )
9985  {
9986  SCIPdebugMsg(scip, "ignore fixed variable <%s>[%g, %g], diff %g\n", SCIPvarGetName(x), xlb, xub, xub-xlb);
9987  continue;
9988  }
9989 
9990  SCIP_CALL( SCIPaddExternBranchCand(scip, x, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
9991  ++*nnotify;
9992  }
9993  }
9994  }
9995 
9996  SCIPdebugMsg(scip, "registered %d branching candidates\n", *nnotify);
9997 
9998  return SCIP_OKAY;
9999 }
10000 
10001 /** registers branching candidates according to centrality rule
10002  *
10003  * That is, registers all variables appearing in nonconvex terms^1 with a score that is given by the distance of the
10004  * variable value from its bounds. This rule should not make sense, as the distance to the bounds is also (often) considered
10005  * by the branching rule later on.
10006  *
10007  * 1) We mean all quadratic variables that appear either in a nonconvex square term or in a bilinear term, if the constraint
10008  * itself is nonconvex. (and this under the assumption that the rhs is violated; for violated lhs, swap terms)
10009  */
10010 static
10012  SCIP* scip, /**< SCIP data structure */
10013  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
10014  SCIP_CONS** conss, /**< constraints to check */
10015  int nconss, /**< number of constraints to check */
10016  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
10017  int* nnotify /**< counter for number of notifications performed */
10018  )
10019 {
10020  SCIP_CONSDATA* consdata;
10021  SCIP_QUADVARTERM* quadvarterm;
10022  int c;
10023  int j;
10024  SCIP_VAR* x;
10025  SCIP_Real xlb;
10026  SCIP_Real xub;
10027  SCIP_Real xval;
10028  SCIP_Real score;
10029 
10030  assert(scip != NULL);
10031  assert(conshdlr != NULL);
10032  assert(conss != NULL || nconss == 0);
10033 
10034  *nnotify = 0;
10035 
10036  for( c = 0; c < nconss; ++c )
10037  {
10038  assert(conss != NULL);
10039  consdata = SCIPconsGetData(conss[c]);
10040  assert(consdata != NULL);
10041 
10042  if( !consdata->nquadvars )
10043  continue;
10044 
10045  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || consdata->isconcave) &&
10046  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || consdata->isconvex ) )
10047  continue;
10048  SCIPdebugMsg(scip, "cons %s violation: %g %g convex: %u %u\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->isconvex, consdata->isconcave);
10049 
10050  for( j = 0; j < consdata->nquadvars; ++j )
10051  {
10052  quadvarterm = &consdata->quadvarterms[j];
10053  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef < 0) ||
10054  (SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef > 0) ||
10055  quadvarterm->nadjbilin > 0 )
10056  {
10057  x = quadvarterm->var;
10058  xlb = SCIPvarGetLbLocal(x);
10059  xub = SCIPvarGetUbLocal(x);
10060 
10061  if( SCIPisRelEQ(scip, xlb, xub) )
10062  {
10063  SCIPdebugMsg(scip, "ignore fixed variable <%s>[%g, %g], diff %g\n", SCIPvarGetName(x), xlb, xub, xub-xlb);
10064  continue;
10065  }
10066 
10067  xval = SCIPgetSolVal(scip, sol, x);
10068  xval = MAX(xlb, MIN(xub, xval));
10069 
10070  /* compute relative difference of xval to each of its bounds
10071  * and scale such that if xval were in the middle, we get a score of 1
10072  * and if xval is on one its bounds, the score is 0
10073  */
10074  if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) )
10075  {
10076  if( (!SCIPisInfinity(scip, -xlb) && SCIPisEQ(scip, xval, xlb)) || (!SCIPisInfinity(scip, xub) && SCIPisEQ(scip, xval, xub)) )
10077  score = 0.0;
10078  else
10079  score = 1.0;
10080  }
10081  else
10082  {
10083  score = 4.0 * (xval - xlb) * (xub - xval) / ((xub - xlb) * (xub - xlb));
10084  }
10085 
10086  SCIP_CALL( SCIPaddExternBranchCand(scip, x, score, SCIP_INVALID) );
10087  ++*nnotify;
10088  }
10089  }
10090  }
10091 
10092  SCIPdebugMsg(scip, "registered %d branching candidates\n", *nnotify);
10093 
10094  return SCIP_OKAY;
10095 }
10096 
10097 /** registers branching candidates */
10098 static
10100  SCIP* scip, /**< SCIP data structure */
10101  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
10102  SCIP_CONS** conss, /**< constraints to check */
10103  int nconss, /**< number of constraints to check */
10104  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
10105  int* nnotify /**< counter for number of notifications performed */
10106  )
10107 {
10108  SCIP_CONSHDLRDATA* conshdlrdata;
10109 
10110  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10111  assert(conshdlrdata != NULL);
10112 
10113  switch( conshdlrdata->branchscoring )
10114  {
10115  case 'g' :
10116  SCIP_CALL( registerBranchingCandidatesGap(scip, conshdlr, conss, nconss, sol, nnotify) );
10117  break;
10118 
10119  case 'v' :
10120  SCIP_CALL( registerBranchingCandidatesViolation(scip, conshdlr, conss, nconss, sol, nnotify) );
10121  break;
10122 
10123  case 'c' :
10124  SCIP_CALL( registerBranchingCandidatesCentrality(scip, conshdlr, conss, nconss, sol, nnotify) );
10125  break;
10126 
10127  default :
10128  SCIPerrorMessage("invalid branchscoring selection");
10129  SCIPABORT();
10130  return SCIP_ERROR; /*lint !e527*/
10131  }
10132 
10133  return SCIP_OKAY;
10134 }
10135 
10136 
10137 /** registers a quadratic variable from a violated constraint as branching candidate that has a large absolute value in the (LP) relaxation */
10138 static
10140  SCIP* scip, /**< SCIP data structure */
10141  SCIP_CONS** conss, /**< constraints */
10142  int nconss, /**< number of constraints */
10143  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
10144  SCIP_VAR** brvar /**< buffer to store branching variable */
10145  )
10146 {
10147  SCIP_CONSDATA* consdata;
10148  SCIP_Real val;
10149  SCIP_Real brvarval;
10150  int i;
10151  int c;
10152 
10153  assert(scip != NULL);
10154  assert(conss != NULL || nconss == 0);
10155 
10156  *brvar = NULL;
10157  brvarval = -1.0;
10158 
10159  for( c = 0; c < nconss; ++c )
10160  {
10161  assert(conss != NULL);
10162  consdata = SCIPconsGetData(conss[c]);
10163  assert(consdata != NULL);
10164 
10165  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
10166  continue;
10167 
10168  for( i = 0; i < consdata->nquadvars; ++i )
10169  {
10170  /* do not propose fixed variables */
10171  if( SCIPisRelEQ(scip, SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
10172  continue;
10173  val = SCIPgetSolVal(scip, sol, consdata->quadvarterms[i].var);
10174  if( ABS(val) > brvarval )
10175  {
10176  brvarval = ABS(val);
10177  *brvar = consdata->quadvarterms[i].var;
10178  }
10179  }
10180  }
10181 
10182  if( *brvar != NULL )
10183  {
10184  SCIP_CALL( SCIPaddExternBranchCand(scip, *brvar, brvarval, SCIP_INVALID) );
10185  }
10186 
10187  return SCIP_OKAY;
10188 }
10189 
10190 /** replaces violated quadratic constraints where all quadratic variables are fixed by linear constraints */
10191 static
10193  SCIP* scip, /**< SCIP data structure */
10194  SCIP_CONS** conss, /**< constraints */
10195  int nconss, /**< number of constraints */
10196  SCIP_Bool* addedcons, /**< buffer to store whether a linear constraint was added */
10197  SCIP_Bool* reduceddom, /**< whether a domain has been reduced */
10198  SCIP_Bool* infeasible /**< whether we detected infeasibility */
10199  )
10200 {
10201  SCIP_CONS* cons;
10202  SCIP_CONSDATA* consdata;
10203  SCIP_RESULT checkresult;
10204  SCIP_VAR* var;
10205  SCIP_Bool tightened;
10206  SCIP_Real constant;
10207  SCIP_Real val1;
10208  SCIP_Real val2;
10209  int i;
10210  int c;
10211 
10212  assert(scip != NULL);
10213  assert(conss != NULL || nconss == 0);
10214  assert(addedcons != NULL);
10215  assert(reduceddom != NULL);
10216  assert(infeasible != NULL);
10217 
10218  *addedcons = FALSE;
10219  *reduceddom = FALSE;
10220  *infeasible = FALSE;
10221 
10222  for( c = 0; c < nconss; ++c )
10223  {
10224  assert(conss != NULL);
10225  consdata = SCIPconsGetData(conss[c]);
10226  assert(consdata != NULL);
10227 
10228  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
10229  continue;
10230 
10231  constant = 0.0;
10232 
10233  for( i = 0; i < consdata->nquadvars; ++i )
10234  {
10235  var = consdata->quadvarterms[i].var;
10236 
10237  /* variables should be fixed if constraint is violated */
10238  assert(SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)));
10239 
10240  val1 = (SCIPvarGetUbLocal(var) + SCIPvarGetLbLocal(var)) / 2.0;
10241  constant += (consdata->quadvarterms[i].lincoef + consdata->quadvarterms[i].sqrcoef * val1) * val1;
10242 
10243  SCIPdebugMessage("<%s>: [%.15g, %.15g]\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
10244 
10245  /* if variable is not fixed w.r.t. absolute eps yet, then try to fix it
10246  * (SCIPfixVar() doesn't allow for small tightenings, so tighten lower and upper bound separately)
10247  */
10248  if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
10249  {
10250  SCIP_CALL( SCIPtightenVarLb(scip, var, val1, TRUE, infeasible, &tightened) );
10251  if( *infeasible )
10252  {
10253  SCIPdebugMsg(scip, "Fixing almost fixed variable <%s> lead to infeasibility.\n", SCIPvarGetName(var));
10254  return SCIP_OKAY;
10255  }
10256  if( tightened )
10257  {
10258  SCIPdebugMsg(scip, "Tightened lower bound of almost fixed variable <%s>.\n", SCIPvarGetName(var));
10259  *reduceddom = TRUE;
10260  }
10261 
10262  SCIP_CALL( SCIPtightenVarUb(scip, var, val1, TRUE, infeasible, &tightened) );
10263  if( *infeasible )
10264  {
10265  SCIPdebugMsg(scip, "Fixing almost fixed variable <%s> lead to infeasibility.\n", SCIPvarGetName(var));
10266  return SCIP_OKAY;
10267  }
10268  if( tightened )
10269  {
10270  SCIPdebugMsg(scip, "Tightened upper bound of almost fixed variable <%s>.\n", SCIPvarGetName(var));
10271  *reduceddom = TRUE;
10272  }
10273  }
10274  }
10275 
10276  /* if some quadratic variable was fixed now, then restart node (next enfo round) */
10277  if( *reduceddom )
10278  return SCIP_OKAY;
10279 
10280  for( i = 0; i < consdata->nbilinterms; ++i )
10281  {
10282  val1 = (SCIPvarGetUbLocal(consdata->bilinterms[i].var1) + SCIPvarGetLbLocal(consdata->bilinterms[i].var1)) / 2.0;
10283  val2 = (SCIPvarGetUbLocal(consdata->bilinterms[i].var2) + SCIPvarGetLbLocal(consdata->bilinterms[i].var2)) / 2.0;
10284  constant += consdata->bilinterms[i].coef * val1 * val2;
10285  }
10286 
10287  /* check if we have a bound change */
10288  if ( consdata->nlinvars == 1 )
10289  {
10290  SCIP_Real coef;
10291  SCIP_Real lhs;
10292  SCIP_Real rhs;
10293 
10294  coef = *consdata->lincoefs;
10295  var = *consdata->linvars;
10296 
10297  assert( ! SCIPisZero(scip, coef) );
10298 
10299  /* compute lhs/rhs, divide already by |coef| */
10300  if ( SCIPisInfinity(scip, -consdata->lhs) )
10301  lhs = -SCIPinfinity(scip);
10302  else
10303  lhs = (consdata->lhs - constant) / REALABS(coef);
10304 
10305  if ( SCIPisInfinity(scip, consdata->rhs) )
10306  rhs = SCIPinfinity(scip);
10307  else
10308  rhs = (consdata->rhs - constant) / REALABS(coef);
10309 
10310  SCIPdebugMsg(scip, "Linear constraint with one variable: %.15g <= %g <%s> <= %.15g\n", lhs, coef > 0.0 ? 1.0 : -1.0, SCIPvarGetName(var), rhs);
10311 
10312  SCIPdebugMessage("<%s>: [%.15g, %.15g]\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
10313 
10314  if ( coef < 0.0 )
10315  {
10316  /* swap lhs and rhs, with negated sign */
10317  SCIP_Real h;
10318  h = rhs;
10319  rhs = -lhs;
10320  lhs = -h;
10321  }
10322  SCIPdebugMsg(scip, "Linear constraint is a bound: %.15g <= <%s> <= %.15g\n", lhs, SCIPvarGetName(var), rhs);
10323 
10324  if( SCIPisInfinity(scip, -rhs) || SCIPisInfinity(scip, lhs) )
10325  {
10326  SCIPdebugMsg(scip, "node will marked as infeasible since lb/ub of %s is +/-infinity\n",
10327  SCIPvarGetName(var));
10328 
10329  *infeasible = TRUE;
10330  return SCIP_OKAY;
10331  }
10332 
10333  if ( ! SCIPisInfinity(scip, -lhs) )
10334  {
10335  SCIP_CALL( SCIPtightenVarLb(scip, var, lhs, TRUE, infeasible, &tightened) );
10336  if ( *infeasible )
10337  {
10338  SCIPdebugMsg(scip, "Lower bound leads to infeasibility.\n");
10339  return SCIP_OKAY;
10340  }
10341  if ( tightened )
10342  {
10343  SCIPdebugMsg(scip, "Lower bound changed.\n");
10344  *reduceddom = TRUE;
10345  return SCIP_OKAY;
10346  }
10347  }
10348 
10349  if ( ! SCIPisInfinity(scip, rhs) )
10350  {
10351  SCIP_CALL( SCIPtightenVarUb(scip, var, rhs, TRUE, infeasible, &tightened) );
10352  if ( *infeasible )
10353  {
10354  SCIPdebugMsg(scip, "Upper bound leads to infeasibility.\n");
10355  return SCIP_OKAY;
10356  }
10357  if ( tightened )
10358  {
10359  SCIPdebugMsg(scip, "Upper bound changed.\n");
10360  *reduceddom = TRUE;
10361  return SCIP_OKAY;
10362  }
10363  }
10364  }
10365  else
10366  {
10367  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, SCIPconsGetName(conss[c]),
10368  consdata->nlinvars, consdata->linvars, consdata->lincoefs,
10369  (SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : (consdata->lhs - constant)),
10370  (SCIPisInfinity(scip, consdata->rhs) ? SCIPinfinity(scip) : (consdata->rhs - constant)),
10371  SCIPconsIsInitial(conss[c]), SCIPconsIsSeparated(conss[c]), SCIPconsIsEnforced(conss[c]),
10372  SCIPconsIsChecked(conss[c]), SCIPconsIsPropagated(conss[c]), TRUE,
10373  SCIPconsIsModifiable(conss[c]), SCIPconsIsDynamic(conss[c]), SCIPconsIsRemovable(conss[c]),
10374  SCIPconsIsStickingAtNode(conss[c])) );
10375 
10376  SCIPdebugMsg(scip, "replace quadratic constraint <%s> by linear constraint after all quadratic vars have been fixed\n", SCIPconsGetName(conss[c]) );
10377  SCIPdebugPrintCons(scip, cons, NULL);
10378 
10379  SCIP_CALL( SCIPcheckCons(scip, cons, NULL, FALSE, FALSE, FALSE, &checkresult) );
10380 
10381  if( checkresult != SCIP_INFEASIBLE && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
10382  {
10383  SCIPdebugMsg(scip, "linear constraint is feasible and LP optimal, thus do not add\n");
10384  }
10385  else
10386  {
10387  SCIP_CALL( SCIPaddConsLocal(scip, cons, NULL) );
10388  *addedcons = TRUE;
10389  }
10390  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
10391  }
10392  SCIP_CALL( SCIPdelConsLocal(scip, conss[c]) );
10393  }
10394 
10395  return SCIP_OKAY;
10396 }
10397 
10398 /** tightens a lower bound on a variable and checks the result */
10399 static
10401  SCIP* scip, /**< SCIP data structure */
10402  SCIP_CONS* cons, /**< constraint where we currently propagate */
10403  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
10404  SCIP_VAR* var, /**< variable which domain we might reduce */
10405  SCIP_Real bnd, /**< new lower bound for variable */
10406  SCIP_RESULT* result, /**< result to update if there was a tightening or cutoff */
10407  int* nchgbds /**< counter to increase if a bound was tightened */
10408  )
10409 {
10410  SCIP_Bool infeas;
10411  SCIP_Bool tightened;
10412 
10413  assert(scip != NULL);
10414  assert(cons != NULL);
10415  assert(intervalinfty > 0.0);
10416  assert(bnd > -intervalinfty);
10417  assert(var != NULL);
10418  assert(result != NULL);
10419  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
10420  assert(nchgbds != NULL);
10421 
10422  /* new bound is no improvement */
10423  if( SCIPisHugeValue(scip, -bnd) || SCIPisLE(scip, bnd, SCIPvarGetLbLocal(var)) )
10424  return SCIP_OKAY;
10425 
10426  if( SCIPisInfinity(scip, bnd) )
10427  { /* domain will be outside [-infty, +infty] -> declare node infeasible */
10428  *result = SCIP_CUTOFF;
10429  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10430  return SCIP_OKAY;
10431  }
10432 
10433  /* new lower bound is very low (between -intervalinfty and -SCIPinfinity()) */
10434  if( SCIPisInfinity(scip, -bnd) )
10435  return SCIP_OKAY;
10436 
10437  bnd = SCIPadjustedVarLb(scip, var, bnd);
10438  SCIP_CALL( SCIPtightenVarLb(scip, var, bnd, FALSE, &infeas, &tightened) );
10439  if( infeas )
10440  {
10441  SCIPdebugMsg(scip, "%s found constraint <%s> infeasible due to tightened lower bound %g for variable <%s>\n",
10442  SCIPinProbing(scip) ? "in probing" : "", SCIPconsGetName(cons), bnd, SCIPvarGetName(var));
10443  *result = SCIP_CUTOFF;
10444  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10445  return SCIP_OKAY;
10446  }
10447  if( tightened )
10448  {
10449  SCIPdebugMsg(scip, "%s tightened lower bound of variable <%s> in constraint <%s> to %g\n",
10450  SCIPinProbing(scip) ? "in probing" : "", SCIPvarGetName(var), SCIPconsGetName(cons), bnd);
10451  ++*nchgbds;
10452  *result = SCIP_REDUCEDDOM;
10453  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10454  }
10455 
10456  return SCIP_OKAY;
10457 }
10458 
10459 /** tightens an upper bound on a variable and checks the result */
10460 static
10462  SCIP* scip, /**< SCIP data structure */
10463  SCIP_CONS* cons, /**< constraint where we currently propagate */
10464  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
10465  SCIP_VAR* var, /**< variable which domain we might reduce */
10466  SCIP_Real bnd, /**< new upper bound for variable */
10467  SCIP_RESULT* result, /**< result to update if there was a tightening or cutoff */
10468  int* nchgbds /**< counter to increase if a bound was tightened */
10469  )
10470 {
10471  SCIP_Bool infeas;
10472  SCIP_Bool tightened;
10473 
10474  assert(scip != NULL);
10475  assert(cons != NULL);
10476  assert(intervalinfty > 0.0);
10477  assert(bnd < intervalinfty);
10478  assert(var != NULL);
10479  assert(result != NULL);
10480  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
10481  assert(nchgbds != NULL);
10482 
10483  /* new bound is no improvement */
10484  if( SCIPisHugeValue(scip, bnd) || SCIPisGE(scip, bnd, SCIPvarGetUbLocal(var)) )
10485  return SCIP_OKAY;
10486 
10487  if( SCIPisInfinity(scip, -bnd) )
10488  { /* domain will be outside [-infty, +infty] -> declare node infeasible */
10489  *result = SCIP_CUTOFF;
10490  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10491  return SCIP_OKAY;
10492  }
10493 
10494  /* new upper bound is very high (between SCIPinfinity() and intervalinfty) */
10495  if( SCIPisInfinity(scip, bnd) )
10496  return SCIP_OKAY;
10497 
10498  bnd = SCIPadjustedVarUb(scip, var, bnd);
10499  SCIP_CALL( SCIPtightenVarUb(scip, var, bnd, FALSE, &infeas, &tightened) );
10500  if( infeas )
10501  {
10502  SCIPdebugMsg(scip, "%s found constraint <%s> infeasible due to tightened upper bound %g for variable <%s>\n",
10503  SCIPinProbing(scip) ? "in probing" : "", SCIPconsGetName(cons), bnd, SCIPvarGetName(var));
10504  *result = SCIP_CUTOFF;
10505  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10506  return SCIP_OKAY;
10507  }
10508  if( tightened )
10509  {
10510  SCIPdebugMsg(scip, "%s tightened upper bound of variable <%s> in constraint <%s> to %g\n",
10511  SCIPinProbing(scip) ? "in probing" : "", SCIPvarGetName(var), SCIPconsGetName(cons), bnd);
10512  ++*nchgbds;
10513  *result = SCIP_REDUCEDDOM;
10514  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10515  }
10516 
10517  return SCIP_OKAY;
10518 }
10519 
10520 /** 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 */
10521 static
10523  SCIP* scip, /**< SCIP data structure */
10524  SCIP_CONS* cons, /**< constraint where we currently propagate */
10525  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
10526  SCIP_VAR* var, /**< variable which bounds with might tighten */
10527  SCIP_Real a, /**< coefficient in square term */
10528  SCIP_INTERVAL b, /**< coefficient in linear term */
10529  SCIP_INTERVAL rhs, /**< right hand side of quadratic equation */
10530  SCIP_RESULT* result, /**< result of propagation */
10531  int* nchgbds /**< buffer where to add number of tightened bounds */
10532  )
10533 {
10534  SCIP_INTERVAL newrange;
10535 
10536  assert(scip != NULL);
10537  assert(cons != NULL);
10538  assert(var != NULL);
10539  assert(result != NULL);
10540  assert(nchgbds != NULL);
10541 
10542  /* compute solution of a*x^2 + b*x \in rhs */
10543  if( a == 0.0 && SCIPintervalGetInf(b) == 0.0 && SCIPintervalGetSup(b) == 0.0 )
10544  {
10545  /* relatively easy case: 0.0 \in rhs, thus check if infeasible or just redundant */
10546  if( SCIPintervalGetInf(rhs) > 0.0 || SCIPintervalGetSup(rhs) < 0.0 )
10547  {
10548  SCIPdebugMsg(scip, "found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(var));
10549  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10550  *result = SCIP_CUTOFF;
10551  }
10552  return SCIP_OKAY;
10553  }
10554  else
10555  {
10556  SCIP_INTERVAL a_;
10557  SCIP_INTERVAL xbnds;
10558 
10559  SCIPintervalSet(&a_, a);
10560  SCIPintervalSetBounds(&xbnds, -infty2infty(SCIPinfinity(scip), intervalinfty, -SCIPvarGetLbLocal(var)), infty2infty(SCIPinfinity(scip), intervalinfty, SCIPvarGetUbLocal(var))); /*lint !e666*/
10561  SCIPintervalSolveUnivariateQuadExpression(intervalinfty, &newrange, a_, b, rhs, xbnds);
10562  }
10563 
10564  /* SCIPdebugMsg(scip, "%g x^2 + [%g, %g] x in [%g, %g] and x in [%g,%g] -> [%g, %g]\n", a, b.inf, b.sup, rhs.inf, rhs.sup, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), newrange.inf, newrange.sup); */
10565 
10566  if( SCIPisInfinity(scip, SCIPintervalGetInf(newrange)) || SCIPisInfinity(scip, -SCIPintervalGetSup(newrange)) )
10567  {
10568  /* domain outside [-infty, +infty] -> declare node infeasible */
10569  SCIPdebugMsg(scip, "found <%s> infeasible because propagated domain of quadratic variable <%s> is outside of (-infty, +infty)\n",
10570  SCIPconsGetName(cons), SCIPvarGetName(var));
10571  *result = SCIP_CUTOFF;
10572  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10573  return SCIP_OKAY;
10574  }
10575 
10576  if( SCIPintervalIsEmpty(intervalinfty, newrange) )
10577  {
10578  SCIPdebugMsg(scip, "found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(var));
10579  *result = SCIP_CUTOFF;
10580  return SCIP_OKAY;
10581  }
10582 
10583  if( !SCIPisInfinity(scip, -SCIPintervalGetInf(newrange)) )
10584  {
10585  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, SCIPintervalGetInf(newrange), result, nchgbds) );
10586  if( *result == SCIP_CUTOFF )
10587  return SCIP_OKAY;
10588  }
10589 
10590  if( !SCIPisInfinity(scip, SCIPintervalGetSup(newrange)) )
10591  {
10592  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, SCIPintervalGetSup(newrange), result, nchgbds) );
10593  if( *result == SCIP_CUTOFF )
10594  return SCIP_OKAY;
10595  }
10596 
10597  return SCIP_OKAY;
10598 }
10599 
10600 /* The new version below computes potentially tighter bounds, but also always adds a small safety area since it is not implemented roundingsafe.
10601  * This may be a reason why it gives worse results on one of two instances.
10602  * Further, I have only very few instances where one can expect a difference.
10603  */
10604 #ifndef PROPBILINNEW
10605 /** tries to deduce domain reductions for x in xsqrcoef x^2 + xlincoef x + ysqrcoef y^2 + ylincoef y + bilincoef x y \\in rhs
10606  *
10607  * @note Domain reductions for y are not deduced.
10608  */
10609 static
10611  SCIP* scip, /**< SCIP data structure */
10612  SCIP_CONS* cons, /**< the constraint, where the bilinear term belongs to */
10613  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
10614  SCIP_VAR* x, /**< first variable */
10615  SCIP_Real xsqrcoef, /**< square coefficient of x */
10616  SCIP_Real xlincoef, /**< linear coefficient of x */
10617  SCIP_VAR* y, /**< second variable */
10618  SCIP_Real ysqrcoef, /**< square coefficient of y */
10619  SCIP_Real ylincoef, /**< linear coefficient of y */
10620  SCIP_Real bilincoef, /**< bilinear coefficient of x*y */
10621  SCIP_INTERVAL rhs, /**< right hand side of quadratic equation */
10622  SCIP_RESULT* result, /**< pointer to store result of domain propagation */
10623  int* nchgbds /**< counter to increment if domain reductions are found */
10624  )
10625 {
10626  SCIP_INTERVAL myrhs;
10627  SCIP_INTERVAL varbnds;
10628  SCIP_INTERVAL lincoef;
10629 
10630  assert(scip != NULL);
10631  assert(cons != NULL);
10632  assert(x != NULL);
10633  assert(y != NULL);
10634  assert(x != y);
10635  assert(result != NULL);
10636  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
10637  assert(nchgbds != NULL);
10638  assert(bilincoef != 0.0);
10639 
10640  if( SCIPintervalIsEntire(intervalinfty, rhs) )
10641  return SCIP_OKAY;
10642 
10643  /* try to find domain reductions for x */
10644  SCIPintervalSetBounds(&varbnds, MIN(SCIPvarGetLbLocal(y), SCIPvarGetUbLocal(y)), MAX(SCIPvarGetLbLocal(y), SCIPvarGetUbLocal(y))); /*lint !e666 */
10645 
10646  /* put ysqrcoef*y^2 + ylincoef * y into rhs */
10647  if( SCIPintervalGetSup(rhs) >= intervalinfty )
10648  {
10649  /* if rhs is unbounded by above, it is sufficient to get an upper bound on ysqrcoef*y^2 + ylincoef * y */
10650  SCIP_ROUNDMODE roundmode;
10651  SCIP_Real tmp;
10652 
10653  SCIPintervalSet(&lincoef, ylincoef);
10654  tmp = SCIPintervalQuadUpperBound(intervalinfty, ysqrcoef, lincoef, varbnds);
10655  roundmode = SCIPintervalGetRoundingMode();
10657  SCIPintervalSetBounds(&myrhs, SCIPintervalGetInf(rhs) - tmp, intervalinfty);
10658  SCIPintervalSetRoundingMode(roundmode);
10659  }
10660  else if( SCIPintervalGetInf(rhs) <= -intervalinfty )
10661  {
10662  /* if rhs is unbounded by below, it is sufficient to get a lower bound on ysqrcoef*y^2 + ylincoef * y */
10663  SCIP_ROUNDMODE roundmode;
10664  SCIP_Real tmp;
10665 
10666  SCIPintervalSet(&lincoef, -ylincoef);
10667  tmp = -SCIPintervalQuadUpperBound(intervalinfty, -ysqrcoef, lincoef, varbnds);
10668  roundmode = SCIPintervalGetRoundingMode();
10670  SCIPintervalSetBounds(&myrhs, -intervalinfty, SCIPintervalGetSup(rhs) - tmp);
10671  SCIPintervalSetRoundingMode(roundmode);
10672  }
10673  else
10674  {
10675  /* if rhs is bounded, we need both bounds on ysqrcoef*y^2 + ylincoef * y */
10676  SCIP_INTERVAL tmp;
10677 
10678  SCIPintervalSet(&lincoef, ylincoef);
10679  SCIPintervalQuad(intervalinfty, &tmp, ysqrcoef, lincoef, varbnds);
10680  SCIPintervalSub(intervalinfty, &myrhs, rhs, tmp);
10681  }
10682 
10683  /* create equation xsqrcoef * x^2 + (xlincoef + bilincoef * [ylb, yub]) * x \in myrhs */
10684  SCIPintervalMulScalar(intervalinfty, &lincoef, varbnds, bilincoef);
10685  SCIPintervalAddScalar(intervalinfty, &lincoef, lincoef, xlincoef);
10686 
10687  /* propagate bounds on x */
10688  SCIP_CALL( propagateBoundsQuadVar(scip, cons, intervalinfty, x, xsqrcoef, lincoef, myrhs, result, nchgbds) );
10689 
10690  return SCIP_OKAY;
10691 }
10692 #else
10693 /** tries to deduce domain reductions for x in xsqrcoef x^2 + xlincoef x + ysqrcoef y^2 + ylincoef y + bilincoef x y \\in rhs
10694  *
10695  * @note Domain reductions for y are not deduced.
10696  */
10697 static
10699  SCIP* scip, /**< SCIP data structure */
10700  SCIP_CONS* cons, /**< the constraint, where the bilinear term belongs to */
10701  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
10702  SCIP_VAR* x, /**< first variable */
10703  SCIP_Real xsqrcoef, /**< square coefficient of x */
10704  SCIP_Real xlincoef, /**< linear coefficient of x */
10705  SCIP_VAR* y, /**< second variable */
10706  SCIP_Real ysqrcoef, /**< square coefficient of y */
10707  SCIP_Real ylincoef, /**< linear coefficient of y */
10708  SCIP_Real bilincoef, /**< bilinear coefficient of x*y */
10709  SCIP_INTERVAL rhs, /**< right hand side of quadratic equation */
10710  SCIP_RESULT* result, /**< pointer to store result of domain propagation */
10711  int* nchgbds /**< counter to increment if domain reductions are found */
10712  )
10713 {
10714  SCIP_INTERVAL xbnds;
10715  SCIP_INTERVAL ybnds;
10716 
10717  assert(scip != NULL);
10718  assert(cons != NULL);
10719  assert(x != NULL);
10720  assert(y != NULL);
10721  assert(x != y);
10722  assert(result != NULL);
10723  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
10724  assert(nchgbds != NULL);
10725  assert(bilincoef != 0.0);
10726 
10727  if( SCIPintervalIsEntire(intervalinfty, rhs) )
10728  return SCIP_OKAY;
10729 
10730  SCIPintervalSetBounds(&xbnds,
10731  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(x), SCIPvarGetUbLocal(x))), /*lint !e666*/
10732  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(x), SCIPvarGetUbLocal(x)))); /*lint !e666*/
10733  SCIPintervalSetBounds(&ybnds,
10734  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(y), SCIPvarGetUbLocal(y))), /*lint !e666*/
10735  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(y), SCIPvarGetUbLocal(y)))); /*lint !e666*/
10736 
10737  /* try to find domain reductions for x */
10738  SCIPintervalSolveBivariateQuadExpressionAllScalar(intervalinfty, &xbnds, xsqrcoef, ysqrcoef, bilincoef, xlincoef, ylincoef, rhs, xbnds, ybnds);
10739 
10740  if( SCIPintervalIsEmpty(intervalinfty, xbnds) )
10741  {
10742  SCIPdebugMsg(scip, "found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(x));
10743  *result = SCIP_CUTOFF;
10744  return SCIP_OKAY;
10745  }
10746 
10747  if( !SCIPisInfinity(scip, -SCIPintervalGetInf(xbnds)) )
10748  {
10749  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, x, SCIPintervalGetInf(xbnds), result, nchgbds) );
10750  if( *result == SCIP_CUTOFF )
10751  return SCIP_OKAY;
10752  }
10753 
10754  if( !SCIPisInfinity(scip, SCIPintervalGetSup(xbnds)) )
10755  {
10756  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, x, SCIPintervalGetSup(xbnds), result, nchgbds) );
10757  if( *result == SCIP_CUTOFF )
10758  return SCIP_OKAY;
10759  }
10760 
10761  return SCIP_OKAY;
10762 }
10763 #endif
10764 
10765 /** computes the minimal and maximal activity for the quadratic part in a constraint data
10766  *
10767  * Only sums up terms that contribute finite values.
10768  * Gives the number of terms that contribute infinite values.
10769  * Only computes those activities where the corresponding side of the constraint is finite.
10770  */
10771 static
10773  SCIP* scip, /**< SCIP data structure */
10774  SCIP_CONSDATA* consdata, /**< constraint data */
10775  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
10776  SCIP_Real* minquadactivity, /**< minimal activity of quadratic variable terms where only terms with finite minimal activity contribute */
10777  SCIP_Real* maxquadactivity, /**< maximal activity of quadratic variable terms where only terms with finite maximal activity contribute */
10778  int* minactivityinf, /**< number of quadratic variables that contribute -infinity to minimal activity */
10779  int* maxactivityinf, /**< number of quadratic variables that contribute +infinity to maximal activity */
10780  SCIP_INTERVAL* quadactcontr /**< contribution of each quadratic variables to quadactivity */
10781  )
10782 { /*lint --e{666}*/
10783  SCIP_ROUNDMODE prevroundmode;
10784  int i;
10785  int j;
10786  int k;
10787  SCIP_INTERVAL tmp;
10788  SCIP_Real bnd;
10789  SCIP_INTERVAL xrng;
10790  SCIP_INTERVAL lincoef;
10791 
10792  assert(scip != NULL);
10793  assert(consdata != NULL);
10794  assert(minquadactivity != NULL);
10795  assert(maxquadactivity != NULL);
10796  assert(minactivityinf != NULL);
10797  assert(maxactivityinf != NULL);
10798  assert(quadactcontr != NULL);
10799 
10800  /* if lhs is -infinite, then we do not compute a maximal activity, so we set it to infinity
10801  * if rhs is infinite, then we do not compute a minimal activity, so we set it to -infinity
10802  */
10803  *minquadactivity = SCIPisInfinity(scip, consdata->rhs) ? -intervalinfty : 0.0;
10804  *maxquadactivity = SCIPisInfinity(scip, -consdata->lhs) ? intervalinfty : 0.0;
10805 
10806  *minactivityinf = 0;
10807  *maxactivityinf = 0;
10808 
10809  if( consdata->nquadvars == 0 )
10810  {
10811  SCIPintervalSet(&consdata->quadactivitybounds, 0.0);
10812  return;
10813  }
10814 
10815  for( i = 0; i < consdata->nquadvars; ++i )
10816  {
10817  /* there should be no quadratic variables fixed at -/+ infinity due to our locks */
10818  assert(!SCIPisInfinity(scip, SCIPvarGetLbLocal(consdata->quadvarterms[i].var)));
10819  assert(!SCIPisInfinity(scip, -SCIPvarGetUbLocal(consdata->quadvarterms[i].var)));
10820 
10821  SCIPintervalSetBounds(&quadactcontr[i], -intervalinfty, intervalinfty);
10822 
10823  SCIPintervalSetBounds(&xrng,
10824  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var))),
10825  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var))));
10826 
10827  SCIPintervalSet(&lincoef, consdata->quadvarterms[i].lincoef);
10828  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
10829  {
10830  k = consdata->quadvarterms[i].adjbilin[j];
10831  if( consdata->bilinterms[k].var1 != consdata->quadvarterms[i].var )
10832  continue; /* handle this term later */
10833 
10834  SCIPintervalSetBounds(&tmp,
10835  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
10836  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
10837  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
10838  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
10839  }
10840 
10841  if( !SCIPisInfinity(scip, -consdata->lhs) )
10842  {
10843  /* compute maximal activity only if there is a finite left hand side */
10844  bnd = SCIPintervalQuadUpperBound(intervalinfty, consdata->quadvarterms[i].sqrcoef, lincoef, xrng);
10845  if( bnd >= intervalinfty )
10846  {
10847  ++*maxactivityinf;
10848  }
10849  else if( SCIPisInfinity(scip, -bnd) )
10850  {
10851  /* if maximal activity is below value for -infinity, let's take -1e10 as upper bound on maximal activity
10852  * @todo Something better?
10853  */
10854  bnd = -sqrt(SCIPinfinity(scip));
10855  *maxquadactivity += bnd;
10856  quadactcontr[i].sup = bnd;
10857  }
10858  else
10859  {
10860  prevroundmode = SCIPintervalGetRoundingMode();
10862  *maxquadactivity += bnd;
10863  SCIPintervalSetRoundingMode(prevroundmode);
10864  quadactcontr[i].sup = bnd;
10865  }
10866  }
10867 
10868  if( !SCIPisInfinity(scip, consdata->rhs) )
10869  {
10870  /* compute minimal activity only if there is a finite right hand side */
10871  SCIPintervalSetBounds(&lincoef, -SCIPintervalGetSup(lincoef), -SCIPintervalGetInf(lincoef));
10872  bnd = -SCIPintervalQuadUpperBound(intervalinfty, -consdata->quadvarterms[i].sqrcoef, lincoef, xrng);
10873 
10874  if( bnd <= -intervalinfty )
10875  {
10876  ++*minactivityinf;
10877  }
10878  else if( SCIPisInfinity(scip, bnd) )
10879  {
10880  /* if minimal activity is above value for infinity, let's take 1e10 as lower bound on minimal activity
10881  * @todo Something better?
10882  */
10883  bnd = sqrt(SCIPinfinity(scip));
10884  *minquadactivity += bnd;
10885  quadactcontr[i].inf = bnd;
10886  }
10887  else
10888  {
10889  prevroundmode = SCIPintervalGetRoundingMode();
10891  *minquadactivity += bnd;
10892  SCIPintervalSetRoundingMode(prevroundmode);
10893  quadactcontr[i].inf = bnd;
10894  }
10895  }
10896  }
10897 
10898  SCIPintervalSetBounds(&consdata->quadactivitybounds,
10899  (*minactivityinf > 0 ? -intervalinfty : *minquadactivity),
10900  (*maxactivityinf > 0 ? intervalinfty : *maxquadactivity));
10901  assert(!SCIPintervalIsEmpty(intervalinfty, consdata->quadactivitybounds));
10902 }
10903 
10904 /** propagates bounds on a quadratic constraint */
10905 static
10907  SCIP* scip, /**< SCIP data structure */
10908  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
10909  SCIP_CONS* cons, /**< constraint to process */
10910  SCIP_RESULT* result, /**< pointer to store the result of the propagation call */
10911  int* nchgbds, /**< buffer where to add the the number of changed bounds */
10912  SCIP_Bool* redundant /**< buffer where to store whether constraint has been found to be redundant */
10913  )
10914 { /*lint --e{666}*/
10915  SCIP_CONSDATA* consdata;
10916  SCIP_INTERVAL consbounds; /* lower and upper bounds of constraint */
10917  SCIP_INTERVAL consactivity; /* activity of linear plus quadratic part */
10918  SCIP_Real intervalinfty; /* infinity used for interval computation */
10919  SCIP_Real minquadactivity; /* lower bound on finite activities of quadratic part */
10920  SCIP_Real maxquadactivity; /* upper bound on finite activities of quadratic part */
10921  int quadminactinf; /* number of quadratic variables that contribute -infinity to minimal activity of quadratic term */
10922  int quadmaxactinf; /* number of quadratic variables that contribute +infinity to maximal activity of quadratic term */
10923  SCIP_INTERVAL* quadactcontr; /* contribution of each quadratic variable term to quadactivity */
10924 
10925  SCIP_VAR* var;
10926  SCIP_INTERVAL rhs; /* right hand side of quadratic equation */
10927  SCIP_INTERVAL tmp;
10928  SCIP_ROUNDMODE roundmode;
10929  SCIP_Real bnd;
10930  int i;
10931 
10932  assert(scip != NULL);
10933  assert(conshdlr != NULL);
10934  assert(cons != NULL);
10935  assert(result != NULL);
10936  assert(nchgbds != NULL);
10937  assert(redundant != NULL);
10938 
10939  consdata = SCIPconsGetData(cons);
10940  assert(consdata != NULL);
10941 
10942  *result = SCIP_DIDNOTRUN;
10943  *redundant = FALSE;
10944 
10945  *result = SCIP_DIDNOTFIND;
10946 
10947  intervalinfty = 1000 * SCIPinfinity(scip) * SCIPinfinity(scip);
10948 
10949  quadactcontr = NULL;
10950  quadminactinf = -1;
10951  quadmaxactinf = -1;
10952 
10953  SCIPdebugMsg(scip, "start domain propagation for constraint <%s>\n", SCIPconsGetName(cons));
10954 
10955  /* make sure we have activity of linear term and that they are consistent */
10956  consdataUpdateLinearActivity(scip, consdata, intervalinfty);
10957  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
10958  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
10959  assert(consdata->minlinactivityinf >= 0);
10960  assert(consdata->maxlinactivityinf >= 0);
10961 
10962  /* sort quadratic variable terms, in case we need to search for terms occuring in bilinear terms later
10963  * we sort here already, since we rely on a constant variable order during this method
10964  */
10965  if( consdata->nbilinterms > 0 )
10966  {
10967  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
10968  }
10969 
10970  /* compute activity of quad term part, if not up to date
10971  * in that case, we also collect the contribution of each quad var term for later */
10972  if( SCIPintervalIsEmpty(intervalinfty, consdata->quadactivitybounds) )
10973  {
10974  SCIP_CALL( SCIPallocBufferArray(scip, &quadactcontr, consdata->nquadvars) );
10975  propagateBoundsGetQuadActivity(scip, consdata, intervalinfty, &minquadactivity, &maxquadactivity, &quadminactinf, &quadmaxactinf, quadactcontr);
10976  assert(!SCIPintervalIsEmpty(intervalinfty, consdata->quadactivitybounds));
10977  }
10978 
10979  SCIPdebugMsg(scip, "linear activity: [%g, %g] quadratic activity: [%g, %g]\n",
10980  (consdata->minlinactivityinf > 0 ? -intervalinfty : consdata->minlinactivity),
10981  (consdata->maxlinactivityinf > 0 ? intervalinfty : consdata->maxlinactivity),
10982  consdata->quadactivitybounds.inf, consdata->quadactivitybounds.sup);
10983 
10984  /* extend constraint bounds by epsilon to avoid some numerical difficulties */
10985  SCIPintervalSetBounds(&consbounds,
10986  -infty2infty(SCIPinfinity(scip), intervalinfty, -consdata->lhs+SCIPepsilon(scip)),
10987  +infty2infty(SCIPinfinity(scip), intervalinfty, consdata->rhs+SCIPepsilon(scip)));
10988 
10989  /* check redundancy and infeasibility */
10990  SCIPintervalSetBounds(&consactivity, consdata->minlinactivityinf > 0 ? -intervalinfty : consdata->minlinactivity,
10991  consdata->maxlinactivityinf > 0 ? intervalinfty : consdata->maxlinactivity);
10992  SCIPintervalAdd(intervalinfty, &consactivity, consactivity, consdata->quadactivitybounds);
10993  if( SCIPintervalIsSubsetEQ(intervalinfty, consactivity, consbounds) )
10994  {
10995  SCIPdebugMsg(scip, "found constraint <%s> to be redundant: sides: [%g, %g], activity: [%g, %g]\n",
10996  SCIPconsGetName(cons), consdata->lhs, consdata->rhs, SCIPintervalGetInf(consactivity), SCIPintervalGetSup(consactivity));
10997  *redundant = TRUE;
10998  goto CLEANUP;
10999  }
11000 
11001  /* was SCIPintervalAreDisjoint(consbounds, consactivity), but that would allow violations up to eps only
11002  * we need to decide feasibility w.r.t. feastol (but still want to propagate w.r.t. eps)
11003  */
11004  if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisGT(scip, consdata->lhs-SCIPfeastol(scip), SCIPintervalGetSup(consactivity))) ||
11005  (!SCIPisInfinity(scip, consdata->rhs) && SCIPisLT(scip, consdata->rhs+SCIPfeastol(scip), SCIPintervalGetInf(consactivity))) )
11006  {
11007  SCIPdebugMsg(scip, "found constraint <%s> to be infeasible; sides: [%g, %g], activity: [%g, %g], infeas: %g\n",
11008  SCIPconsGetName(cons), consdata->lhs, consdata->rhs, SCIPintervalGetInf(consactivity), SCIPintervalGetSup(consactivity),
11009  MAX(consdata->lhs - SCIPintervalGetSup(consactivity), SCIPintervalGetInf(consactivity) - consdata->rhs));
11010  *result = SCIP_CUTOFF;
11011  goto CLEANUP;
11012  }
11013 
11014  /* propagate linear part \in rhs = consbounds - quadactivity (use the one from consdata, since that includes infinities) */
11015  SCIPintervalSub(intervalinfty, &rhs, consbounds, consdata->quadactivitybounds);
11016  if( !SCIPintervalIsEntire(intervalinfty, rhs) )
11017  {
11018  SCIP_Real coef;
11019 
11020  for( i = 0; i < consdata->nlinvars; ++i )
11021  {
11022  coef = consdata->lincoefs[i];
11023  var = consdata->linvars[i];
11024 
11025  /* skip fixed variables
11026  * @todo is that a good or a bad idea?
11027  * we can't expect much more tightening, but may detect infeasiblity, but shouldn't the check on the constraints activity detect that?
11028  */
11029  if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
11030  continue;
11031 
11032  /* due to large variable bounds and large coefficients, it might happen that the activity of the linear part
11033  * exceeds +/-SCIPinfinity() after updating the activities in consdataUpdateLinearActivity{Lb,Ub}Change; in
11034  * order to detect this case we need to check whether the value of consdata->{min,max}linactivity is infinite
11035  * (see #1433)
11036  */
11037  if( coef > 0.0 )
11038  {
11039  if( SCIPintervalGetSup(rhs) < intervalinfty )
11040  {
11041  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
11042  /* try to tighten the upper bound on var x */
11043  if( consdata->minlinactivityinf == 0 && !SCIPisInfinity(scip, -consdata->minlinactivity) )
11044  {
11045  assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
11046  /* tighten upper bound on x to (rhs.sup - (minlinactivity - coef * xlb)) / coef */
11047  roundmode = SCIPintervalGetRoundingMode();
11049  bnd = SCIPintervalGetSup(rhs);
11050  bnd -= consdata->minlinactivity;
11051  bnd += coef * SCIPvarGetLbLocal(var);
11052  bnd /= coef;
11053  SCIPintervalSetRoundingMode(roundmode);
11054  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
11055  if( *result == SCIP_CUTOFF )
11056  break;
11057  }
11058  else if( consdata->minlinactivityinf == 1 && SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
11059  {
11060  /* x was the variable that made the minimal linear activity equal -infinity, so
11061  * we tighten upper bound on x to just (rhs.sup - minlinactivity) / coef */
11062  roundmode = SCIPintervalGetRoundingMode();
11064  bnd = SCIPintervalGetSup(rhs);
11065  bnd -= consdata->minlinactivity;
11066  bnd /= coef;
11067  SCIPintervalSetRoundingMode(roundmode);
11068  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
11069  if( *result == SCIP_CUTOFF )
11070  break;
11071  }
11072  /* otherwise the minimal activity is -infinity and x is not solely responsible for this */
11073  }
11074 
11075  if( SCIPintervalGetInf(rhs) > -intervalinfty )
11076  {
11077  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
11078  /* try to tighten the lower bound on var x */
11079  if( consdata->maxlinactivityinf == 0 && !SCIPisInfinity(scip, consdata->maxlinactivity) )
11080  {
11081  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
11082  /* tighten lower bound on x to (rhs.inf - (maxlinactivity - coef * xub)) / coef */
11083  roundmode = SCIPintervalGetRoundingMode();
11085  bnd = SCIPintervalGetInf(rhs);
11086  bnd -= consdata->maxlinactivity;
11087  bnd += coef * SCIPvarGetUbLocal(var);
11088  bnd /= coef;
11089  SCIPintervalSetRoundingMode(roundmode);
11090  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
11091  if( *result == SCIP_CUTOFF )
11092  break;
11093  }
11094  else if( consdata->maxlinactivityinf == 1 && SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
11095  {
11096  /* x was the variable that made the maximal linear activity equal infinity, so
11097  * we tighten upper bound on x to just (rhs.inf - maxlinactivity) / coef */
11098  roundmode = SCIPintervalGetRoundingMode();
11100  bnd = SCIPintervalGetInf(rhs);
11101  bnd -= consdata->maxlinactivity;
11102  bnd /= coef;
11103  SCIPintervalSetRoundingMode(roundmode);
11104  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
11105  if( *result == SCIP_CUTOFF )
11106  break;
11107  }
11108  /* otherwise the maximal activity is +infinity and x is not solely responsible for this */
11109  }
11110  }
11111  else
11112  {
11113  assert(coef < 0.0 );
11114  if( SCIPintervalGetInf(rhs) > -intervalinfty )
11115  {
11116  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
11117  /* try to tighten the upper bound on var x */
11118  if( consdata->maxlinactivityinf == 0 && !SCIPisInfinity(scip, consdata->maxlinactivity) )
11119  {
11120  assert(!SCIPisInfinity(scip, SCIPvarGetLbLocal(var)));
11121  /* compute upper bound on x to (maxlinactivity - coef * xlb) - rhs.inf / (-coef) */
11122  roundmode = SCIPintervalGetRoundingMode();
11124  bnd = consdata->maxlinactivity;
11125  bnd += (-coef) * SCIPvarGetLbLocal(var);
11126  bnd -= SCIPintervalGetInf(rhs);
11127  bnd /= (-coef);
11128  SCIPintervalSetRoundingMode(roundmode);
11129  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
11130  if( *result == SCIP_CUTOFF )
11131  break;
11132  }
11133  else if( consdata->maxlinactivityinf == 1 && SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
11134  {
11135  /* x was the variable that made the maximal linear activity equal infinity, so
11136  * we tighten upper bound on x to just (maxlinactivity - rhs.inf) / (-coef) */
11137  roundmode = SCIPintervalGetRoundingMode();
11139  bnd = consdata->maxlinactivity;
11140  bnd -= SCIPintervalGetInf(rhs);
11141  bnd /= (-coef);
11142  SCIPintervalSetRoundingMode(roundmode);
11143  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
11144  if( *result == SCIP_CUTOFF )
11145  break;
11146  }
11147  /* otherwise the maximal activity is infinity and x is not solely responsible for this */
11148  }
11149 
11150  if( SCIPintervalGetSup(rhs) < intervalinfty )
11151  {
11152  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
11153  /* try to tighten the lower bound on var x */
11154  if( consdata->minlinactivityinf == 0 && !SCIPisInfinity(scip, -consdata->minlinactivity) )
11155  {
11156  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
11157  /* compute lower bound on x to (minlinactivity - coef * xub) - rhs.sup / (-coef) */
11158  roundmode = SCIPintervalGetRoundingMode();
11160  bnd = consdata->minlinactivity;
11161  bnd += (-coef) * SCIPvarGetUbLocal(var);
11162  bnd -= SCIPintervalGetSup(rhs);
11163  bnd /= (-coef);
11164  SCIPintervalSetRoundingMode(roundmode);
11165  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
11166  if( *result == SCIP_CUTOFF )
11167  break;
11168  }
11169  else if( consdata->minlinactivityinf == 1 && SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
11170  {
11171  /* x was the variable that made the maximal linear activity equal -infinity, so
11172  * we tighten lower bound on x to just (minlinactivity - rhs.sup) / (-coef) */
11173  roundmode = SCIPintervalGetRoundingMode();
11175  bnd = consdata->minlinactivity;
11176  bnd -= SCIPintervalGetSup(rhs);
11177  bnd /= (-coef);
11178  SCIPintervalSetRoundingMode(roundmode);
11179  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
11180  if( *result == SCIP_CUTOFF )
11181  break;
11182  }
11183  /* otherwise the minimal activity is -infinity and x is not solely responsible for this */
11184  }
11185  }
11186  }
11187  if( *result == SCIP_CUTOFF )
11188  goto CLEANUP;
11189  }
11190 
11191  /* propagate quadratic part \in rhs = consbounds - linactivity */
11192  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
11193  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
11194  consdataUpdateLinearActivity(scip, consdata, intervalinfty); /* make sure, activities of linear part did not become invalid by above bound changes, if any */
11195  assert(consdata->minlinactivityinf > 0 || consdata->maxlinactivityinf > 0 || consdata->minlinactivity <= consdata->maxlinactivity);
11196  SCIPintervalSetBounds(&tmp,
11197  (consdata->minlinactivityinf > 0 ? -intervalinfty : consdata->minlinactivity),
11198  (consdata->maxlinactivityinf > 0 ? intervalinfty : consdata->maxlinactivity));
11199  SCIPintervalSub(intervalinfty, &rhs, consbounds, tmp);
11200  if( !SCIPintervalIsEntire(intervalinfty, rhs) )
11201  {
11202  if( consdata->nquadvars == 1 )
11203  {
11204  /* quadratic part is just a*x^2+b*x -> a common case that we treat directly */
11205  SCIP_INTERVAL lincoef; /* linear coefficient of quadratic equation */
11206 
11207  assert(consdata->nbilinterms == 0);
11208 
11209  var = consdata->quadvarterms[0].var;
11210  SCIPintervalSet(&lincoef, consdata->quadvarterms[0].lincoef);
11211 
11212  /* propagate a*x^2 + b*x \in rhs */
11213  SCIP_CALL( propagateBoundsQuadVar(scip, cons, intervalinfty, var, consdata->quadvarterms[0].sqrcoef, lincoef, rhs, result, nchgbds) );
11214  }
11215  else if( consdata->nbilinterms == 1 && consdata->nquadvars == 2 )
11216  {
11217  /* quadratic part is just ax*x^2+bx*x + ay*y^2+by*y + c*xy -> a common case that we treat directly */
11218  assert(consdata->bilinterms[0].var1 == consdata->quadvarterms[0].var || consdata->bilinterms[0].var1 == consdata->quadvarterms[1].var);
11219  assert(consdata->bilinterms[0].var2 == consdata->quadvarterms[0].var || consdata->bilinterms[0].var2 == consdata->quadvarterms[1].var);
11220 
11221  /* 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 */
11222  SCIP_CALL( propagateBoundsBilinearTerm(scip, cons, intervalinfty,
11223  consdata->quadvarterms[0].var, consdata->quadvarterms[0].sqrcoef, consdata->quadvarterms[0].lincoef,
11224  consdata->quadvarterms[1].var, consdata->quadvarterms[1].sqrcoef, consdata->quadvarterms[1].lincoef,
11225  consdata->bilinterms[0].coef,
11226  rhs, result, nchgbds) );
11227  if( *result != SCIP_CUTOFF )
11228  {
11229  /* 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 */
11230  SCIP_CALL( propagateBoundsBilinearTerm(scip, cons, intervalinfty,
11231  consdata->quadvarterms[1].var, consdata->quadvarterms[1].sqrcoef, consdata->quadvarterms[1].lincoef,
11232  consdata->quadvarterms[0].var, consdata->quadvarterms[0].sqrcoef, consdata->quadvarterms[0].lincoef,
11233  consdata->bilinterms[0].coef,
11234  rhs, result, nchgbds) );
11235  }
11236  }
11237  else
11238  {
11239  /* general case */
11240 
11241  /* compute "advanced" information on quad var term activities, if not up-to-date */
11242  if( quadminactinf == -1 )
11243  {
11244  assert(quadactcontr == NULL);
11245  SCIP_CALL( SCIPallocBufferArray(scip, &quadactcontr, consdata->nquadvars) );
11246  propagateBoundsGetQuadActivity(scip, consdata, intervalinfty, &minquadactivity, &maxquadactivity, &quadminactinf, &quadmaxactinf, quadactcontr);
11247  }
11248  assert(quadactcontr != NULL);
11249  assert(quadminactinf >= 0);
11250  assert(quadmaxactinf >= 0);
11251 
11252  /* if the quad activities are not hopelessly unbounded on useful sides, try to deduce domain reductions on quad vars */
11253  if( (SCIPintervalGetSup(rhs) < intervalinfty && quadminactinf <= 1) ||
11254  ( SCIPintervalGetInf(rhs) > -intervalinfty && quadmaxactinf <= 1) )
11255  {
11256  SCIP_INTERVAL lincoef;
11257  SCIP_INTERVAL rhs2;
11258  int j;
11259  int k;
11260 
11261  for( i = 0; i < consdata->nquadvars; ++i )
11262  {
11263  var = consdata->quadvarterms[i].var;
11264 
11265  /* skip fixed variables
11266  * @todo is that a good or a bad idea?
11267  * we can't expect much more tightening, but may detect infeasiblity, but shouldn't the check on the constraints activity detect that?
11268  */
11269  if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
11270  continue;
11271 
11272  /* compute rhs2 such that we can propagate quadvarterm(x_i) \in rhs2 */
11273 
11274  /* setup rhs2.sup = rhs.sup - (quadactivity.inf - quadactcontr[i].inf), if everything were finite
11275  * if only quadactcontr[i].inf is infinite (i.e., the other i are all finite), we just get rhs2.sup = rhs.sup
11276  * otherwise we get rhs2.sup = infinity */
11277  if( SCIPintervalGetSup(rhs) < intervalinfty )
11278  {
11279  if( quadminactinf == 0 || (quadminactinf == 1 && SCIPintervalGetInf(quadactcontr[i]) <= -intervalinfty) )
11280  {
11281  roundmode = SCIPintervalGetRoundingMode();
11283  rhs2.sup = rhs.sup - minquadactivity; /*lint !e644*/
11284  /* if the residual quad min activity w.r.t. quad var term i is finite and nonzero, so add it to right hand side */
11285  if( quadminactinf == 0 && SCIPintervalGetInf(quadactcontr[i]) != 0.0 )
11286  rhs2.sup += SCIPintervalGetInf(quadactcontr[i]);
11287  SCIPintervalSetRoundingMode(roundmode);
11288  }
11289  else
11290  {
11291  /* there are either >= 2 quad var terms contributing -infinity, or there is one which is not i */
11292  rhs2.sup = intervalinfty;
11293  }
11294  }
11295  else
11296  {
11297  rhs2.sup = intervalinfty;
11298  }
11299 
11300  /* setup rhs2.inf = rhs.inf - (quadactivity.sup - quadactcontr[i].sup), see also above */
11301  if( SCIPintervalGetInf(rhs) > -intervalinfty )
11302  {
11303  if( quadmaxactinf == 0 || (quadmaxactinf == 1 && SCIPintervalGetSup(quadactcontr[i]) >= intervalinfty) )
11304  {
11305  roundmode = SCIPintervalGetRoundingMode();
11307  rhs2.inf = rhs.inf - maxquadactivity; /*lint !e644*/
11308  /* if the residual quad max activity w.r.t. quad var term i is finite and nonzero, so add it to right hand side */
11309  if( quadmaxactinf == 0 && SCIPintervalGetSup(quadactcontr[i]) != 0.0 )
11310  rhs2.inf += SCIPintervalGetSup(quadactcontr[i]);
11311  SCIPintervalSetRoundingMode(roundmode);
11312  }
11313  else
11314  {
11315  /* there are either >= 2 quad var terms contributing infinity, or there is one which is not i */
11316  rhs2.inf = -intervalinfty;
11317  }
11318  }
11319  else
11320  {
11321  rhs2.inf = -intervalinfty;
11322  }
11323  assert(!SCIPintervalIsEmpty(intervalinfty, rhs2));
11324 
11325  /* if rhs2 is entire, then there is nothing we could propagate */
11326  if( SCIPintervalIsEntire(intervalinfty, rhs2) )
11327  continue;
11328 
11329  /* assemble linear coefficient for quad equation a*x^2 + b*x \in rhs2 */
11330  SCIPintervalSet(&lincoef, consdata->quadvarterms[i].lincoef);
11331  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
11332  {
11333  k = consdata->quadvarterms[i].adjbilin[j];
11334 #if 1
11335  if( consdata->bilinterms[k].var1 == var )
11336  {
11337  /* bilinear term k contributes to the activity of quad var term i, so just add bounds to linear coef */
11338  SCIPintervalSetBounds(&tmp,
11339  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
11340  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
11341  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
11342  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
11343  }
11344  else
11345  {
11346  /* bilinear term k does not contribute to the activity of quad var term i
11347  * so bounds on term k are contained in rhs2
11348  * if they are finite, we try to remove them from rhs2 and update lincoef instead
11349  * 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
11350  * HOWEVER: when computing rhs2, we may not just have added the bounds for the bilinear term, but for the associated quadratic term
11351  * for this complete term, we used SCIPintervalQuad to compute the bounds
11352  * since we do not want to repeat a call to SCIPintervalQuad for that quadratic term with bilinear term k removed,
11353  * we only remove the bounds for the bilinear term k from rhs2 if the associated quadratic term consists only of this bilinear term,
11354  * i.e., the quadratic term corresponding to var1 should be only var1*var2, but have no square or linear coefs or other bilinear terms
11355  * (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)
11356  */
11357  SCIP_INTERVAL me;
11358  SCIP_INTERVAL bilinbounds;
11359  int otherpos;
11360 
11361  assert(consdata->bilinterms[k].var2 == var);
11362 
11363  assert(consdata->quadvarssorted);
11364  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->bilinterms[k].var1, &otherpos) );
11365  assert(otherpos >= 0);
11366  assert(consdata->quadvarterms[otherpos].var == consdata->bilinterms[k].var1);
11367 
11368  if( (consdata->quadvarterms[otherpos].sqrcoef != 0.0) || consdata->quadvarterms[otherpos].lincoef != 0.0 ||
11369  consdata->quadvarterms[otherpos].nadjbilin > 1 )
11370  continue;
11371 
11372  /* set tmp to bounds of other variable and multiply with bilin coef */
11373  SCIPintervalSetBounds(&tmp,
11374  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var1), SCIPvarGetUbLocal(consdata->bilinterms[k].var1))),
11375  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var1), SCIPvarGetUbLocal(consdata->bilinterms[k].var1))));
11376  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
11377 
11378  /* set me to bounds of i'th variable */
11380  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
11381  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
11382 
11383  /* remove me*tmp from rhs2 */
11384 
11385  roundmode = SCIPintervalGetRoundingMode();
11386 
11387  if( rhs2.inf > -intervalinfty )
11388  {
11389  /* need upward rounding for SCIPintervalMulSup */
11391  SCIPintervalMulSup(intervalinfty, &bilinbounds, me, tmp);
11392  /* rhs2.inf += bilinbounds.sup, but we are in upward rounding */
11393  if( bilinbounds.sup < intervalinfty )
11394  rhs2.inf = SCIPintervalNegateReal(SCIPintervalNegateReal(rhs2.inf) - bilinbounds.sup);
11395  }
11396 
11397  if( rhs2.sup < intervalinfty )
11398  {
11399  /* need downward rounding for SCIPintervalMulInf */
11401  SCIPintervalMulInf(intervalinfty, &bilinbounds, me, tmp);
11402  /* rhs2.sup += bilinbounds.inf, but we are in downward rounding */
11403  if( bilinbounds.inf > -intervalinfty )
11404  rhs2.sup = SCIPintervalNegateReal(SCIPintervalNegateReal(rhs2.sup) - bilinbounds.inf);
11405  }
11406 
11407  SCIPintervalSetRoundingMode(roundmode);
11408 
11409  /* in theory, rhs2 should not be empty here
11410  * what we tried to do here is to remove the contribution of the k'th bilinear term (=bilinbounds) to [minquadactivity,maxquadactivity] from rhs2
11411  * however, quadactivity is computed differently (as x*(a1*y1+...+an*yn)) than bilinbounds (a*ak*yk) and since interval arithmetics do overestimation,
11412  * it can happen that bilinbounds is actually slightly larger than quadactivity, which results in rhs2 being (slightly) empty
11413  * a proper fix could be to compute the quadactivity also as x*a1*y1+...+x*an*yn in propagateBoundsGetQuadAcitivity if sqrcoef=0, but due to taking
11414  * also infinite bounds into account, this complicates the code even further
11415  * instead, I'll just work around this by turning an empty rhs2 into a small non-empty one
11416  */
11417  if( SCIPintervalIsEmpty(intervalinfty, rhs2) )
11418  {
11419  assert(SCIPrelDiff(rhs2.inf, rhs2.sup) < 1e-6);
11420  SCIPswapReals(&rhs2.inf, &rhs2.sup);
11421  }
11422 
11423  /* add tmp to lincoef */
11424  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
11425  }
11426 #else
11427  if( consdata->bilinterms[k].var1 != var )
11428  continue; /* this term does not contribute to the activity of quad var term i */
11429 
11430  SCIPintervalSetBounds(&tmp,
11431  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
11432  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
11433  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
11434  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
11435 #endif
11436  }
11437 
11438  /* deduce domain reductions for x_i */
11439  SCIP_CALL( propagateBoundsQuadVar(scip, cons, intervalinfty, var, consdata->quadvarterms[i].sqrcoef, lincoef, rhs2, result, nchgbds) );
11440  if( *result == SCIP_CUTOFF )
11441  goto CLEANUP;
11442  }
11443  }
11444  }
11445  }
11446 
11447  CLEANUP:
11448  SCIPfreeBufferArrayNull(scip, &quadactcontr);
11449 
11450  return SCIP_OKAY;
11451 }
11452 
11453 /** calls domain propagation for a set of constraints */
11454 static
11456  SCIP* scip, /**< SCIP data structure */
11457  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11458  SCIP_CONS** conss, /**< constraints to process */
11459  int nconss, /**< number of constraints */
11460  SCIP_RESULT* result, /**< pointer to store the result of the propagation calls */
11461  int* nchgbds /**< buffer where to add the the number of changed bounds */
11462  )
11463 {
11464  SCIP_CONSHDLRDATA* conshdlrdata;
11465  SCIP_RESULT propresult;
11466  SCIP_Bool redundant;
11467  int c;
11468  int roundnr;
11469  SCIP_Bool success;
11470  int maxproprounds;
11471 
11472  assert(scip != NULL);
11473  assert(conshdlr != NULL);
11474  assert(conss != NULL || nconss == 0);
11475  assert(result != NULL);
11476  assert(nchgbds != NULL);
11477 
11479 
11480  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11481  assert(conshdlrdata != NULL);
11482 
11483  *result = SCIP_DIDNOTFIND;
11484  roundnr = 0;
11485  if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING )
11486  maxproprounds = conshdlrdata->maxproproundspresolve;
11487  else
11488  maxproprounds = conshdlrdata->maxproprounds;
11489 
11490  do
11491  {
11492  success = FALSE;
11493  ++roundnr;
11494 
11495  SCIPdebugMsg(scip, "starting domain propagation round %d of %d for %d constraints\n", roundnr, maxproprounds, nconss);
11496 
11497  for( c = 0; c < nconss && *result != SCIP_CUTOFF; ++c )
11498  {
11499  assert(conss != NULL);
11500  if( !SCIPconsIsEnabled(conss[c]) )
11501  continue;
11502 
11503  if( SCIPconsIsMarkedPropagate(conss[c]) )
11504  {
11505  /* unmark constraint for propagation */
11506  SCIP_CALL( SCIPunmarkConsPropagate(scip, conss[c]) );
11507 
11508  SCIP_CALL( propagateBoundsCons(scip, conshdlr, conss[c], &propresult, nchgbds, &redundant) );
11509  if( propresult != SCIP_DIDNOTFIND && propresult != SCIP_DIDNOTRUN )
11510  {
11511  *result = propresult;
11512  success = TRUE;
11513  }
11514  if( redundant )
11515  {
11516  SCIPdebugMsg(scip, "deleting constraint <%s> locally\n", SCIPconsGetName(conss[c]));
11517  SCIP_CALL( SCIPdelConsLocal(scip, conss[c]) );
11518  }
11519  }
11520  }
11521  }
11522  while( success && *result != SCIP_CUTOFF && roundnr < maxproprounds );
11523 
11524  return SCIP_OKAY;
11525 }
11526 
11527 /** checks for a linear variable that can be increase or decreased without harming feasibility */
11528 static
11530  SCIP* scip, /**< SCIP data structure */
11531  SCIP_CONSDATA* consdata /**< constraint data */
11532  )
11533 {
11534  int i;
11535  int downlock;
11536  int uplock;
11537 
11538  consdata->linvar_maydecrease = -1;
11539  consdata->linvar_mayincrease = -1;
11540 
11541  /* check for a linear variable that can be increase or decreased without harming feasibility */
11542  for( i = 0; i < consdata->nlinvars; ++i )
11543  {
11544  /* compute locks of i'th linear variable */
11545  assert(consdata->lincoefs[i] != 0.0);
11546  if( consdata->lincoefs[i] > 0.0 )
11547  {
11548  downlock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0; /* lhs <= x -> downlock on x */
11549  uplock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0; /* x <= rhs -> uplock on x */
11550  }
11551  else
11552  {
11553  downlock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0; /* -x <= rhs -> downlock on x */
11554  uplock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0; /* lhs <= -x -> uplock on x */
11555  }
11556 
11557  if( SCIPvarGetNLocksDownType(consdata->linvars[i], SCIP_LOCKTYPE_MODEL) - downlock == 0 )
11558  {
11559  /* for a*x + q(y) \in [lhs, rhs], we can decrease x without harming other constraints */
11560  /* if we have already one candidate, then take the one where the loss in the objective function is less */
11561  if( (consdata->linvar_maydecrease < 0) ||
11562  (SCIPvarGetObj(consdata->linvars[consdata->linvar_maydecrease]) / consdata->lincoefs[consdata->linvar_maydecrease] > SCIPvarGetObj(consdata->linvars[i]) / consdata->lincoefs[i]) )
11563  consdata->linvar_maydecrease = i;
11564  }
11565 
11566  if( SCIPvarGetNLocksUpType(consdata->linvars[i], SCIP_LOCKTYPE_MODEL) - uplock == 0 )
11567  {
11568  /* for a*x + q(y) \in [lhs, rhs], we can increase x without harm */
11569  /* if we have already one candidate, then take the one where the loss in the objective function is less */
11570  if( (consdata->linvar_mayincrease < 0) ||
11571  (SCIPvarGetObj(consdata->linvars[consdata->linvar_mayincrease]) / consdata->lincoefs[consdata->linvar_mayincrease] > SCIPvarGetObj(consdata->linvars[i]) / consdata->lincoefs[i]) )
11572  consdata->linvar_mayincrease = i;
11573  }
11574  }
11575 
11576 #ifdef SCIP_DEBUG
11577  if( consdata->linvar_mayincrease >= 0 )
11578  {
11579  SCIPdebugMsg(scip, "may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvars[consdata->linvar_mayincrease]));
11580  }
11581  if( consdata->linvar_maydecrease >= 0 )
11582  {
11583  SCIPdebugMsg(scip, "may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvars[consdata->linvar_maydecrease]));
11584  }
11585 #endif
11586 }
11587 
11588 /** Given a solution where every quadratic constraint is either feasible or can be made feasible by
11589  * moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
11590  *
11591  * The method assumes that this is always possible and that not all constraints are feasible already.
11592  */
11593 static
11595  SCIP* scip, /**< SCIP data structure */
11596  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11597  SCIP_CONS** conss, /**< constraints to process */
11598  int nconss, /**< number of constraints */
11599  SCIP_SOL* sol, /**< solution to process */
11600  SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
11601  )
11602 {
11603  SCIP_CONSHDLRDATA* conshdlrdata;
11604  SCIP_CONSDATA* consdata;
11605  SCIP_SOL* newsol;
11606  SCIP_VAR* var;
11607  int c;
11608  SCIP_Real viol;
11609  SCIP_Real delta;
11610  SCIP_Real gap;
11611  SCIP_Bool solviolbounds;
11612  SCIP_Bool solchanged;
11613 
11614  assert(scip != NULL);
11615  assert(conshdlr != NULL);
11616  assert(conss != NULL || nconss == 0);
11617  assert(success != NULL);
11618 
11619  *success = FALSE;
11620 
11621  /* don't propose new solutions if not in presolve or solving */
11623  return SCIP_OKAY;
11624 
11625  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11626  assert(conshdlrdata != NULL);
11627 
11628  if( sol != NULL )
11629  {
11630  SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
11631  }
11632  else
11633  {
11634  SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
11635  }
11636  SCIP_CALL( SCIPunlinkSol(scip, newsol) );
11637  solchanged = FALSE;
11638 
11639  SCIPdebugMsg(scip, "attempt to make solution from <%s> feasible by shifting linear variable\n",
11640  sol != NULL ? (SCIPsolGetHeur(sol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(sol)) : "tree") : "LP");
11641 
11642  for( c = 0; c < nconss; ++c )
11643  {
11644  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
11645  assert(consdata != NULL);
11646 
11647  /* recompute violation of constraint in case newsol is not identical to sol anymore */
11648  if( solchanged )
11649  {
11650  SCIP_CALL( computeViolation(scip, conss[c], newsol, &solviolbounds) ); /*lint !e613*/
11651  assert(!solviolbounds);
11652  }
11653 
11654  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
11655  viol = consdata->lhs - consdata->activity;
11656  else if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
11657  viol = consdata->rhs - consdata->activity;
11658  else
11659  continue; /* constraint is satisfied */
11660 
11661  assert(viol != 0.0);
11662  if( consdata->linvar_mayincrease >= 0 &&
11663  ((viol > 0.0 && consdata->lincoefs[consdata->linvar_mayincrease] > 0.0) || (viol < 0.0 && consdata->lincoefs[consdata->linvar_mayincrease] < 0.0)) )
11664  {
11665  /* have variable where increasing makes the constraint less violated */
11666  var = consdata->linvars[consdata->linvar_mayincrease];
11667  /* compute how much we would like to increase var */
11668  delta = viol / consdata->lincoefs[consdata->linvar_mayincrease];
11669  assert(delta > 0.0);
11670  /* if var has an upper bound, may need to reduce delta */
11671  if( !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
11672  {
11673  gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
11674  delta = MIN(MAX(0.0, gap), delta);
11675  }
11676  if( SCIPisPositive(scip, delta) && !SCIPisInfinity(scip, REALABS(delta)) )
11677  {
11678  /* if variable is integral, round delta up so that it will still have an integer value */
11679  if( SCIPvarIsIntegral(var) )
11680  delta = SCIPceil(scip, delta);
11681 
11682  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
11683  /*lint --e{613} */
11684  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]));
11685 
11686  solchanged = TRUE;
11687 
11688  /* adjust constraint violation, if satisfied go on to next constraint */
11689  viol -= consdata->lincoefs[consdata->linvar_mayincrease] * delta;
11690  if( SCIPisZero(scip, viol) )
11691  continue;
11692  }
11693  }
11694 
11695  assert(viol != 0.0);
11696  if( consdata->linvar_maydecrease >= 0 &&
11697  ((viol > 0.0 && consdata->lincoefs[consdata->linvar_maydecrease] < 0.0) || (viol < 0.0 && consdata->lincoefs[consdata->linvar_maydecrease] > 0.0)) )
11698  {
11699  /* have variable where decreasing makes constraint less violated */
11700  var = consdata->linvars[consdata->linvar_maydecrease];
11701  /* compute how much we would like to decrease var */
11702  delta = viol / consdata->lincoefs[consdata->linvar_maydecrease];
11703  assert(delta < 0.0);
11704  /* if var has a lower bound, may need to reduce delta */
11705  if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) )
11706  {
11707  gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
11708  delta = MAX(MIN(0.0, gap), delta);
11709  }
11710  if( SCIPisNegative(scip, delta) && !SCIPisInfinity(scip, REALABS(delta)) )
11711  {
11712  /* if variable is integral, round delta down so that it will still have an integer value */
11713  if( SCIPvarIsIntegral(var) )
11714  delta = SCIPfloor(scip, delta);
11715  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
11716  /*lint --e{613} */
11717  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]));
11718 
11719  solchanged = TRUE;
11720 
11721  /* adjust constraint violation, if satisfied go on to next constraint */
11722  viol -= consdata->lincoefs[consdata->linvar_maydecrease] * delta;
11723  if( SCIPisZero(scip, viol) )
11724  continue;
11725  }
11726  }
11727 
11728  /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
11729  break;
11730  }
11731 
11732  /* if we have a solution that should satisfy all quadratic constraints and has a better objective than the current upper bound,
11733  * then pass it to the trysol heuristic
11734  */
11735  if( c == nconss && (SCIPisInfinity(scip, SCIPgetUpperbound(scip)) || SCIPisSumLT(scip, SCIPgetSolTransObj(scip, newsol), SCIPgetUpperbound(scip))) )
11736  {
11737  SCIPdebugMsg(scip, "pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
11738  assert(solchanged);
11739 
11740  assert(conshdlrdata->trysolheur != NULL);
11741  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
11742 
11743  *success = TRUE;
11744  }
11745 
11746  SCIP_CALL( SCIPfreeSol(scip, &newsol) );
11747 
11748  return SCIP_OKAY;
11749 }
11750 
11751 /** helper function to enforce constraints */
11752 static
11754  SCIP* scip, /**< SCIP data structure */
11755  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11756  SCIP_CONS** conss, /**< constraints to process */
11757  int nconss, /**< number of constraints */
11758  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
11759  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
11760  SCIP_Bool solinfeasible, /**< was the solution already declared infeasible by a constraint handler? */
11761  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
11762  )
11763 {
11764  SCIP_CONSHDLRDATA* conshdlrdata;
11765  SCIP_CONSDATA* consdata;
11766  SCIP_CONS* maxviolcon;
11767  SCIP_Real maxviol;
11768  SCIP_RESULT propresult;
11769  SCIP_RESULT separateresult;
11770  int nchgbds;
11771  int nnotify;
11772  SCIP_Real sepaefficacy;
11773  SCIP_Bool solviolbounds;
11774 
11775  assert(scip != NULL);
11776  assert(conshdlr != NULL);
11777  assert(conss != NULL || nconss == 0);
11778  assert(nconss >= 0);
11779  assert(nusefulconss >= 0);
11780  assert(result != NULL);
11781 
11782  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11783  assert(conshdlrdata != NULL);
11784 
11785  SCIP_CALL( computeViolations(scip, conss, nconss, sol, &solviolbounds, &maxviolcon) );
11786 
11787  if( maxviolcon == NULL )
11788  {
11789  *result = SCIP_FEASIBLE;
11790  return SCIP_OKAY;
11791  }
11792 
11793  *result = SCIP_INFEASIBLE;
11794 
11795  if( solviolbounds )
11796  {
11797  /* if LP solution violates variable bounds, then this should be because a row was added that
11798  * introduced this variable newly to the LP, in which case it gets value 0.0; the row should
11799  * have been added to resolve an infeasibility, so solinfeasible should be TRUE
11800  * see also issue #627
11801  */
11802  assert(solinfeasible);
11803  /* however, if solinfeasible is actually not TRUE, then better cut off the node to avoid that SCIP
11804  * stops because infeasible cannot be resolved */
11805  /*lint --e{774} */
11806  if( !solinfeasible )
11807  *result = SCIP_CUTOFF;
11808  return SCIP_OKAY;
11809  }
11810 
11811  consdata = SCIPconsGetData(maxviolcon);
11812  assert(consdata != NULL);
11813  maxviol = consdata->lhsviol + consdata->rhsviol;
11814  assert(SCIPisGT(scip, maxviol, SCIPfeastol(scip)));
11815 
11816  SCIPdebugMsg(scip, "enforcement with max violation %g in cons <%s> for %s solution\n", maxviol, SCIPconsGetName(maxviolcon),
11817  sol == NULL ? "LP" : "relaxation");
11818 
11819  /* if we are above the 100'th enforcement round for this node, something is strange
11820  * (maybe the LP / relaxator does not think that the cuts we add are violated, or we do ECP on a high-dimensional convex function)
11821  * 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
11822  * (in optimized more, returning SCIP_INFEASIBLE in *result would be sufficient, but in debug mode this would give an assert in scip.c)
11823  * the reason to wait for 100 rounds is to avoid calls to SCIPisStopped in normal runs, which may be expensive
11824  * we only increment nenforounds until 101 to avoid an overflow
11825  */
11826  if( conshdlrdata->lastenfonode == SCIPgetCurrentNode(scip) )
11827  {
11828  if( conshdlrdata->nenforounds > 100 )
11829  {
11830  if( SCIPisStopped(scip) )
11831  {
11832  SCIP_NODE* child;
11833 
11834  SCIP_CALL( SCIPcreateChild(scip, &child, 1.0, SCIPnodeGetEstimate(SCIPgetCurrentNode(scip))) );
11835  *result = SCIP_BRANCHED;
11836 
11837  return SCIP_OKAY;
11838  }
11839  }
11840 
11841  ++conshdlrdata->nenforounds;
11842 
11843  /* cut off the current subtree, if a limit on the enforcement rounds should be applied. At this point, feasible
11844  * solutions might get cut off; the enfolplimit parameter should therefore only be set if SCIP is used as a
11845  * heuristic solver and when the returned result (infeasible, optimal, the gap) can be ignored
11846  */
11847  if( conshdlrdata->enfolplimit != -1 && conshdlrdata->nenforounds > conshdlrdata->enfolplimit )
11848  {
11850  "cut off subtree because enforcement limit was reached; this might lead to incorrect results\n");
11851  *result = SCIP_CUTOFF;
11852  return SCIP_OKAY;
11853  }
11854  }
11855  else
11856  {
11857  conshdlrdata->lastenfonode = SCIPgetCurrentNode(scip);
11858  conshdlrdata->nenforounds = 0;
11859  }
11860 
11861  /* run domain propagation */
11862  nchgbds = 0;
11863  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, &propresult, &nchgbds) );
11864  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
11865  {
11866  SCIPdebugMsg(scip, "propagation succeeded (%s)\n", propresult == SCIP_CUTOFF ? "cutoff" : "reduceddom");
11867  *result = propresult;
11868  return SCIP_OKAY;
11869  }
11870 
11871  /* we would like a cut that is efficient enough that it is not redundant in the LP (>lpfeastol)
11872  * however, we also don't want very weak cuts, so try to reach at least feastol (=lpfeastol by default, though)
11873  */
11874  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, SCIPfeastol(scip), TRUE, &separateresult, &sepaefficacy) );
11875  if( separateresult == SCIP_CUTOFF )
11876  {
11877  SCIPdebugMsg(scip, "separation found cutoff\n");
11878  *result = SCIP_CUTOFF;
11879  return SCIP_OKAY;
11880  }
11881  if( separateresult == SCIP_SEPARATED )
11882  {
11883  SCIPdebugMsg(scip, "separation succeeded (bestefficacy = %g, minefficacy = %g)\n", sepaefficacy, SCIPfeastol(scip));
11884  *result = SCIP_SEPARATED;
11885  return SCIP_OKAY;
11886  }
11887 
11888  /* we are not feasible, the whole node is not infeasible, and we cannot find a good cut
11889  * -> collect variables for branching
11890  */
11891 
11892  SCIPdebugMsg(scip, "separation failed (bestefficacy = %g < %g = minefficacy ); max viol: %g\n", sepaefficacy, SCIPfeastol(scip), maxviol);
11893 
11894  /* find branching candidates */
11895  SCIP_CALL( registerBranchingCandidates(scip, conshdlr, conss, nconss, sol, &nnotify) );
11896 
11897  if( nnotify == 0 && !solinfeasible && SCIPfeastol(scip) > SCIPgetLPFeastol(scip) )
11898  {
11899  /* fallback 1: we also have no branching candidates, so try to find a weak cut */
11900  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, SCIPgetLPFeastol(scip), TRUE, &separateresult, &sepaefficacy) );
11901  if( separateresult == SCIP_CUTOFF )
11902  {
11903  SCIPdebugMsg(scip, "separation found cutoff\n");
11904  *result = SCIP_CUTOFF;
11905  return SCIP_OKAY;
11906  }
11907  if( separateresult == SCIP_SEPARATED )
11908  {
11909  SCIPdebugMsg(scip, "separation fallback succeeded, efficacy = %g\n", sepaefficacy);
11910  *result = SCIP_SEPARATED;
11911  return SCIP_OKAY;
11912  }
11913  }
11914 
11915  if( nnotify == 0 && !solinfeasible )
11916  {
11917  /* fallback 2: separation probably failed because of numerical difficulties with a convex constraint;
11918  * if noone declared solution infeasible yet and we had not even found a weak cut, try to resolve by branching
11919  */
11920  SCIP_VAR* brvar = NULL;
11921  SCIP_CALL( registerLargeRelaxValueVariableForBranching(scip, conss, nconss, sol, &brvar) );
11922  if( brvar == NULL )
11923  {
11924  /* fallback 3: all quadratic variables seem to be fixed -> replace by linear constraint */
11925  SCIP_Bool addedcons;
11926  SCIP_Bool reduceddom;
11927  SCIP_Bool infeasible;
11928 
11929  SCIP_CALL( replaceByLinearConstraints(scip, conss, nconss, &addedcons, &reduceddom, &infeasible) );
11930  /* if the linear constraints are actually feasible, then adding them and returning SCIP_CONSADDED confuses SCIP
11931  * when it enforces the new constraints again and nothing resolves the infeasibility that we declare here
11932  * thus, we only add them if considered violated, and otherwise claim the solution is feasible (but print a
11933  * warning) */
11934  if ( infeasible )
11935  *result = SCIP_CUTOFF;
11936  else if ( addedcons )
11937  *result = SCIP_CONSADDED;
11938  else if ( reduceddom )
11939  *result = SCIP_REDUCEDDOM;
11940  else
11941  {
11942  *result = SCIP_FEASIBLE;
11943  SCIPwarningMessage(scip, "could not enforce feasibility by separating or branching; declaring solution with viol %g as feasible\n", maxviol);
11944  assert(!SCIPisInfinity(scip, maxviol));
11945  }
11946  return SCIP_OKAY;
11947  }
11948  else
11949  {
11950  SCIPdebugMsg(scip, "Could not find any usual branching variable candidate. Proposed variable <%s> with LP value %g for branching.\n",
11951  SCIPvarGetName(brvar), SCIPgetSolVal(scip, sol, brvar));
11952  nnotify = 1;
11953  }
11954  }
11955 
11956  assert(*result == SCIP_INFEASIBLE && (solinfeasible || nnotify > 0));
11957  return SCIP_OKAY;
11958 }
11959 
11960 /** tries to upgrade a nonlinear constraint into a quadratic constraint */
11961 static
11962 SCIP_DECL_NONLINCONSUPGD(nonlinconsUpgdQuadratic)
11964  SCIP_EXPRGRAPH* exprgraph;
11965  SCIP_EXPRGRAPHNODE* node;
11966  int i;
11967 
11968  assert(nupgdconss != NULL);
11969  assert(upgdconss != NULL);
11970 
11971  *nupgdconss = 0;
11972 
11973  node = SCIPgetExprgraphNodeNonlinear(scip, cons);
11974 
11975  /* no interest in linear constraints */
11976  if( node == NULL )
11977  return SCIP_OKAY;
11978 
11979  /* if a quadratic expression has been simplified, then all children of the node should be variables */
11981  return SCIP_OKAY;
11982 
11983  switch( SCIPexprgraphGetNodeOperator(node) )
11984  {
11985  case SCIP_EXPR_VARIDX:
11986  case SCIP_EXPR_CONST:
11987  case SCIP_EXPR_PLUS:
11988  case SCIP_EXPR_MINUS:
11989  case SCIP_EXPR_SUM:
11990  case SCIP_EXPR_LINEAR:
11991  /* these should not appear as exprgraphnodes after constraint presolving */
11992  return SCIP_OKAY;
11993 
11994  case SCIP_EXPR_DIV:
11995  case SCIP_EXPR_SQRT:
11996  case SCIP_EXPR_REALPOWER:
11997  case SCIP_EXPR_INTPOWER:
11998  case SCIP_EXPR_SIGNPOWER:
11999  case SCIP_EXPR_EXP:
12000  case SCIP_EXPR_LOG:
12001  case SCIP_EXPR_SIN:
12002  case SCIP_EXPR_COS:
12003  case SCIP_EXPR_TAN:
12004  /* case SCIP_EXPR_ERF: */
12005  /* case SCIP_EXPR_ERFI: */
12006  case SCIP_EXPR_MIN:
12007  case SCIP_EXPR_MAX:
12008  case SCIP_EXPR_ABS:
12009  case SCIP_EXPR_SIGN:
12010  case SCIP_EXPR_PRODUCT:
12011  case SCIP_EXPR_POLYNOMIAL:
12012  case SCIP_EXPR_USER:
12013  /* these do not look like an quadratic expression (assuming the expression graph simplifier did run) */
12014  return SCIP_OKAY;
12015 
12016  case SCIP_EXPR_MUL:
12017  case SCIP_EXPR_SQUARE:
12018  case SCIP_EXPR_QUADRATIC:
12019  /* these mean that we have something quadratic */
12020  break;
12021 
12022  case SCIP_EXPR_PARAM:
12023  case SCIP_EXPR_LAST:
12024  default:
12025  SCIPwarningMessage(scip, "unexpected expression operator %d in nonlinear constraint <%s>\n", SCIPexprgraphGetNodeOperator(node), SCIPconsGetName(cons));
12026  return SCIP_OKAY;
12027  }
12028 
12029  /* setup a quadratic constraint */
12030 
12031  if( upgdconsssize < 1 )
12032  {
12033  /* request larger upgdconss array */
12034  *nupgdconss = -1;
12035  return SCIP_OKAY;
12036  }
12037 
12038  *nupgdconss = 1;
12039  SCIP_CALL( SCIPcreateConsQuadratic(scip, &upgdconss[0], SCIPconsGetName(cons),
12041  0, NULL, 0, NULL,
12042  SCIPgetLhsNonlinear(scip, cons), SCIPgetRhsNonlinear(scip, cons),
12046  assert(!SCIPconsIsStickingAtNode(cons));
12047 
12048  exprgraph = SCIPgetExprgraphNonlinear(scip, SCIPconsGetHdlr(cons));
12049 
12050  /* add variables from expression tree as "quadratic" variables to quadratic constraint */
12051  for( i = 0; i < SCIPexprgraphGetNodeNChildren(node); ++i )
12052  {
12053  assert(SCIPexprgraphGetNodeChildren(node)[i] != NULL);
12054  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, upgdconss[0], (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[i]), 0.0, 0.0) );
12055  }
12056 
12057  switch( SCIPexprgraphGetNodeOperator(node) )
12058  {
12059  case SCIP_EXPR_MUL:
12060  /* expression is product of two variables, so add bilinear term to constraint */
12061  assert(SCIPexprgraphGetNodeNChildren(node) == 2);
12062 
12063  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, upgdconss[0],
12066  1.0) );
12067 
12068  break;
12069 
12070  case SCIP_EXPR_SQUARE:
12071  /* expression is square of a variable, so change square coefficient of quadratic variable */
12072  assert(SCIPexprgraphGetNodeNChildren(node) == 1);
12073 
12074  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, upgdconss[0],
12076  1.0) );
12077 
12078  break;
12079 
12080  case SCIP_EXPR_QUADRATIC:
12081  {
12082  /* expression is quadratic */
12083  SCIP_QUADELEM* quadelems;
12084  int nquadelems;
12085  SCIP_Real* lincoefs;
12086 
12088  nquadelems = SCIPexprgraphGetNodeQuadraticNQuadElements(node);
12090 
12092 
12093  if( lincoefs != NULL )
12094  for( i = 0; i < SCIPexprgraphGetNodeNChildren(node); ++i )
12095  if( lincoefs[i] != 0.0 )
12096  {
12097  /* linear term */
12098  SCIP_CALL( SCIPaddQuadVarLinearCoefQuadratic(scip, upgdconss[0],
12100  lincoefs[i]) );
12101  }
12102 
12103  for( i = 0; i < nquadelems; ++i )
12104  {
12105  assert(quadelems[i].idx1 < SCIPexprgraphGetNodeNChildren(node));
12106  assert(quadelems[i].idx2 < SCIPexprgraphGetNodeNChildren(node));
12107 
12108  if( quadelems[i].idx1 == quadelems[i].idx2 )
12109  {
12110  /* square term */
12111  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, upgdconss[0],
12112  (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[quadelems[i].idx1]),
12113  quadelems[i].coef) );
12114  }
12115  else
12116  {
12117  /* bilinear term */
12118  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, upgdconss[0],
12119  (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[quadelems[i].idx1]),
12120  (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[quadelems[i].idx2]),
12121  quadelems[i].coef) );
12122  }
12123  }
12124 
12125  break;
12126  }
12127 
12128  default:
12129  SCIPerrorMessage("you should not be here\n");
12130  return SCIP_ERROR;
12131  } /*lint !e788 */
12132 
12133  return SCIP_OKAY;
12134 }
12135 
12136 /*
12137  * Callback methods of constraint handler
12138  */
12139 
12140 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
12141 static
12142 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyQuadratic)
12143 { /*lint --e{715}*/
12144  assert(scip != NULL);
12145  assert(conshdlr != NULL);
12146  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12147 
12148  /* call inclusion method of constraint handler */
12150 
12151  *valid = TRUE;
12152 
12153  return SCIP_OKAY;
12154 }
12155 
12156 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12157 static
12158 SCIP_DECL_CONSFREE(consFreeQuadratic)
12160  SCIP_CONSHDLRDATA* conshdlrdata;
12161  int i;
12162 
12163  assert(scip != NULL);
12164  assert(conshdlr != NULL);
12165 
12166  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12167  assert(conshdlrdata != NULL);
12168 
12169  for( i = 0; i < conshdlrdata->nquadconsupgrades; ++i )
12170  {
12171  assert(conshdlrdata->quadconsupgrades[i] != NULL);
12172  SCIPfreeBlockMemory(scip, &conshdlrdata->quadconsupgrades[i]); /*lint !e866*/
12173  }
12174  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->quadconsupgrades, conshdlrdata->quadconsupgradessize);
12175  SCIPfreeBlockMemory(scip, &conshdlrdata);
12176 
12177  return SCIP_OKAY;
12178 }
12179 
12180 /** initialization method of constraint handler (called after problem was transformed) */
12181 static
12182 SCIP_DECL_CONSINIT(consInitQuadratic)
12183 { /*lint --e{715} */
12184  SCIP_CONSHDLRDATA* conshdlrdata;
12185 
12186  assert(scip != NULL);
12187  assert(conshdlr != NULL);
12188 
12189  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12190  assert(conshdlrdata != NULL);
12191 
12192  conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
12193  conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
12194 
12195  return SCIP_OKAY;
12196 }
12197 
12198 
12199 /** deinitialization method of constraint handler (called before transformed problem is freed) */
12200 static
12201 SCIP_DECL_CONSEXIT(consExitQuadratic)
12202 { /*lint --e{715} */
12203  SCIP_CONSHDLRDATA* conshdlrdata;
12204 
12205  assert(scip != NULL);
12206  assert(conshdlr != NULL);
12207 
12208  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12209  assert(conshdlrdata != NULL);
12210 
12211  conshdlrdata->subnlpheur = NULL;
12212  conshdlrdata->trysolheur = NULL;
12213 
12214  return SCIP_OKAY;
12215 }
12216 
12217 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12218 static
12219 SCIP_DECL_CONSEXITPRE(consExitpreQuadratic)
12220 { /*lint --e{715}*/
12221  SCIP_CONSHDLRDATA* conshdlrdata;
12222  SCIP_CONSDATA* consdata;
12223  int c;
12224 #ifndef NDEBUG
12225  int i;
12226 #endif
12227 
12228  assert(scip != NULL);
12229  assert(conshdlr != NULL);
12230  assert(conss != NULL || nconss == 0);
12231 
12232  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12233  assert(conshdlrdata != NULL);
12234 
12235  for( c = 0; c < nconss; ++c )
12236  {
12237  assert(conss != NULL);
12238  consdata = SCIPconsGetData(conss[c]);
12239  assert(consdata != NULL);
12240 
12241  if( !consdata->isremovedfixings )
12242  {
12243  SCIP_CALL( removeFixedVariables(scip, conshdlrdata->eventhdlr, conss[c]) );
12244  }
12245 
12246  /* make sure we do not have duplicate bilinear terms, quad var terms, or linear vars */
12247  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
12248  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
12249  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
12250 
12251  assert(consdata->isremovedfixings);
12252  assert(consdata->linvarsmerged);
12253  assert(consdata->quadvarsmerged);
12254  assert(consdata->bilinmerged);
12255 
12256 #ifndef NDEBUG
12257  for( i = 0; i < consdata->nlinvars; ++i )
12258  assert(SCIPvarIsActive(consdata->linvars[i]));
12259 
12260  for( i = 0; i < consdata->nquadvars; ++i )
12261  assert(SCIPvarIsActive(consdata->quadvarterms[i].var));
12262 #endif
12263 
12264  /* tell SCIP that we have something nonlinear */
12265  if( SCIPconsIsAdded(conss[c]) && consdata->nquadvars > 0 )
12266  SCIPenableNLP(scip);
12267  }
12268 
12269  return SCIP_OKAY;
12270 }
12271 
12272 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin)
12273  *
12274  * @note Also called from consEnableQuadratic during solving stage.
12275  */
12276 static
12277 SCIP_DECL_CONSINITSOL(consInitsolQuadratic)
12279  SCIP_CONSHDLRDATA* conshdlrdata;
12280  SCIP_CONSDATA* consdata;
12281  int c;
12282  int i;
12283 
12284  assert(scip != NULL);
12285  assert(conshdlr != NULL);
12286  assert(conss != NULL || nconss == 0);
12287 
12288  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12289  assert(conshdlrdata != NULL);
12290 
12291  for( c = 0; c < nconss; ++c )
12292  {
12293  assert(conss != NULL);
12294  consdata = SCIPconsGetData(conss[c]);
12295  assert(consdata != NULL);
12296 
12297  /* check for a linear variable that can be increase or decreased without harming feasibility */
12298  consdataFindUnlockedLinearVar(scip, consdata);
12299 
12300  /* setup lincoefsmin, lincoefsmax */
12301  consdata->lincoefsmin = SCIPinfinity(scip);
12302  consdata->lincoefsmax = 0.0;
12303  for( i = 0; i < consdata->nlinvars; ++i )
12304  {
12305  consdata->lincoefsmin = MIN(consdata->lincoefsmin, REALABS(consdata->lincoefs[i])); /*lint !e666 */
12306  consdata->lincoefsmax = MAX(consdata->lincoefsmax, REALABS(consdata->lincoefs[i])); /*lint !e666 */
12307  }
12308 
12309  /* add nlrow representation to NLP, if NLP had been constructed */
12310  if( SCIPisNLPConstructed(scip) && SCIPconsIsEnabled(conss[c]) )
12311  {
12312  if( consdata->nlrow == NULL )
12313  {
12314  /* compute curvature for the quadratic constraint if not done yet */
12315  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) );
12316 
12317  SCIP_CALL( createNlRow(scip, conss[c]) );
12318  assert(consdata->nlrow != NULL);
12319  }
12320  if( !SCIPnlrowIsInNLP(consdata->nlrow) )
12321  {
12322  SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
12323  }
12324  }
12325 
12326  /* setup sepaquadvars and sepabilinvar2pos */
12327  assert(consdata->sepaquadvars == NULL);
12328  assert(consdata->sepabilinvar2pos == NULL);
12329  if( consdata->nquadvars > 0 )
12330  {
12331  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->sepaquadvars, consdata->nquadvars) );
12332  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->sepabilinvar2pos, consdata->nbilinterms) );
12333 
12334  /* make sure, quadratic variable terms are sorted */
12335  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
12336 
12337  for( i = 0; i < consdata->nquadvars; ++i )
12338  consdata->sepaquadvars[i] = consdata->quadvarterms[i].var;
12339 
12340  for( i = 0; i < consdata->nbilinterms; ++i )
12341  {
12342  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->bilinterms[i].var2, &consdata->sepabilinvar2pos[i]) );
12343  }
12344  }
12345 
12346  if( conshdlrdata->checkfactorable )
12347  {
12348  /* check if constraint function is factorable, i.e., can be written as product of two linear functions */
12349  SCIP_CALL( checkFactorable(scip, conss[c]) );
12350  }
12351 
12352  /* compute gauge function using interior points per constraint, only when there are quadratic variables */
12353  if( conshdlrdata->gaugecuts && SCIPgetSubscipDepth(scip) == 0 && consdata->nquadvars > 0 )
12354  {
12355  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
12356  if( (consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
12357  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)) )
12358  {
12359  SCIP_CALL( computeGauge(scip, conshdlr, conss[c]) );
12360  }
12361  }
12362 
12363  /* compute eigendecomposition for convex quadratics */
12364  if( conshdlrdata->projectedcuts && SCIPgetSubscipDepth(scip) == 0 && consdata->nquadvars > 0 )
12365  {
12366  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
12367  if( (consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
12368  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)) )
12369  {
12370  SCIP_CALL( computeED(scip, conshdlr, conss[c]) );
12371  }
12372  }
12373 
12374  /* mark constraint for propagation */
12375  SCIP_CALL( SCIPmarkConsPropagate(scip, conss[c]) );
12376  consdata->ispropagated = FALSE;
12377  }
12378 
12379  if( SCIPgetStage(scip) != SCIP_STAGE_INITSOLVE )
12380  {
12381  /* if called from consEnableQuadratic, then don't do below */
12382  return SCIP_OKAY;
12383  }
12384 
12385  conshdlrdata->newsoleventfilterpos = -1;
12386  if( nconss != 0 && conshdlrdata->linearizeheursol )
12387  {
12388  SCIP_EVENTHDLR* eventhdlr;
12389 
12390  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
12391  assert(eventhdlr != NULL);
12392 
12393  /* @todo Should we catch every new solution or only new *best* solutions */
12394  SCIP_CALL( SCIPcatchEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
12395  }
12396 
12397  if( nconss != 0 && !SCIPisIpoptAvailableIpopt() && !SCIPisInRestart(scip) )
12398  {
12399  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");
12400  }
12401 
12402  /* reset flags and counters */
12403  conshdlrdata->sepanlp = FALSE;
12404  conshdlrdata->lastenfonode = NULL;
12405  conshdlrdata->nenforounds = 0;
12406 
12407  return SCIP_OKAY;
12408 }
12409 
12410 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed)
12411  *
12412  * @note Also called from consDisableQuadratic during solving stage.
12413  */
12414 static
12415 SCIP_DECL_CONSEXITSOL(consExitsolQuadratic)
12416 { /*lint --e{715}*/
12417  SCIP_CONSHDLRDATA* conshdlrdata;
12418  SCIP_CONSDATA* consdata;
12419  int c;
12420 
12421  assert(scip != NULL);
12422  assert(conshdlr != NULL);
12423  assert(conss != NULL || nconss == 0);
12424 
12425  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12426  assert(conshdlrdata != NULL);
12427 
12428  for( c = 0; c < nconss; ++c )
12429  {
12430  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
12431  assert(consdata != NULL);
12432 
12433  /* free nonlinear row representation, if not called from consDisableQuadratic */
12434  if( consdata->nlrow != NULL && SCIPgetStage(scip) == SCIP_STAGE_EXITSOLVE )
12435  {
12436  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
12437  }
12438 
12439  assert(!SCIPconsIsEnabled(conss[c]) || consdata->sepaquadvars != NULL || consdata->nquadvars == 0); /*lint !e613 */
12440  assert(!SCIPconsIsEnabled(conss[c]) || consdata->sepabilinvar2pos != NULL || consdata->nquadvars == 0); /*lint !e613 */
12441  SCIPfreeBlockMemoryArrayNull(scip, &consdata->sepaquadvars, consdata->nquadvars);
12442  SCIPfreeBlockMemoryArrayNull(scip, &consdata->sepabilinvar2pos, consdata->nbilinterms);
12443 
12444  SCIPfreeBlockMemoryArrayNull(scip, &consdata->factorleft, consdata->nquadvars + 1);
12445  SCIPfreeBlockMemoryArrayNull(scip, &consdata->factorright, consdata->nquadvars + 1);
12446 
12447  SCIPfreeBlockMemoryArrayNull(scip, &consdata->interiorpoint, consdata->nquadvars);
12448  SCIPfreeBlockMemoryArrayNull(scip, &consdata->gaugecoefs, consdata->nquadvars);
12449  SCIPfreeBlockMemoryArrayNull(scip, &consdata->eigenvalues, consdata->nquadvars);
12450  SCIPfreeBlockMemoryArrayNull(scip, &consdata->eigenvectors, (int)(consdata->nquadvars*consdata->nquadvars));
12451  SCIPfreeBlockMemoryArrayNull(scip, &consdata->bp, consdata->nquadvars);
12452  }
12453 
12454  if( SCIPgetStage(scip) != SCIP_STAGE_EXITSOLVE )
12455  {
12456  /* if called from consDisableQuadratic, then don't do below */
12457  return SCIP_OKAY;
12458  }
12459 
12460  if( conshdlrdata->newsoleventfilterpos >= 0 )
12461  {
12462  SCIP_EVENTHDLR* eventhdlr;
12463 
12464  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
12465  assert(eventhdlr != NULL);
12466 
12467  SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
12468  conshdlrdata->newsoleventfilterpos = -1;
12469  }
12470 
12471  /* free all stored bilinear terms in the constraint handler and constraint data; note that we might not want to
12472  * recollect all bilinear terms and therefore keep them even if consDisableQuadratic is called
12473  */
12474  SCIP_CALL( freeAllBilinearTerms(scip, conshdlrdata, conss, nconss) );
12475 
12476  return SCIP_OKAY;
12477 }
12478 
12479 /** frees specific constraint data */
12480 static
12481 SCIP_DECL_CONSDELETE(consDeleteQuadratic)
12483  assert(scip != NULL);
12484  assert(conshdlr != NULL);
12485  assert(cons != NULL);
12486  assert(consdata != NULL);
12487  assert(SCIPconsGetData(cons) == *consdata);
12488 
12489  SCIP_CALL( consdataFree(scip, consdata) );
12490 
12491  assert(*consdata == NULL);
12492 
12493  return SCIP_OKAY;
12494 }
12495 
12496 /** transforms constraint data into data belonging to the transformed problem */
12497 static
12498 SCIP_DECL_CONSTRANS(consTransQuadratic)
12499 {
12500  SCIP_CONSDATA* sourcedata;
12501  SCIP_CONSDATA* targetdata;
12502  int i;
12503 
12504  sourcedata = SCIPconsGetData(sourcecons);
12505  assert(sourcedata != NULL);
12506 
12507  SCIP_CALL( consdataCreate(scip, &targetdata,
12508  sourcedata->lhs, sourcedata->rhs,
12509  sourcedata->nlinvars, sourcedata->linvars, sourcedata->lincoefs,
12510  sourcedata->nquadvars, sourcedata->quadvarterms,
12511  sourcedata->nbilinterms, sourcedata->bilinterms,
12512  FALSE) );
12513 
12514  for( i = 0; i < targetdata->nlinvars; ++i )
12515  {
12516  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->linvars[i], &targetdata->linvars[i]) );
12517  SCIP_CALL( SCIPcaptureVar(scip, targetdata->linvars[i]) );
12518  }
12519 
12520  for( i = 0; i < targetdata->nquadvars; ++i )
12521  {
12522  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->quadvarterms[i].var, &targetdata->quadvarterms[i].var) );
12523  SCIP_CALL( SCIPcaptureVar(scip, targetdata->quadvarterms[i].var) );
12524  }
12525 
12526  for( i = 0; i < targetdata->nbilinterms; ++i )
12527  {
12528  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->bilinterms[i].var1, &targetdata->bilinterms[i].var1) );
12529  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->bilinterms[i].var2, &targetdata->bilinterms[i].var2) );
12530 
12531  if( SCIPvarCompare(targetdata->bilinterms[i].var1, targetdata->bilinterms[i].var2) > 0 )
12532  {
12533  SCIP_VAR* tmp;
12534  tmp = targetdata->bilinterms[i].var2;
12535  targetdata->bilinterms[i].var2 = targetdata->bilinterms[i].var1;
12536  targetdata->bilinterms[i].var1 = tmp;
12537  }
12538  }
12539 
12540  /* create target constraint */
12541  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12542  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12543  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
12544  SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons),
12545  SCIPconsIsStickingAtNode(sourcecons)) );
12546 
12547  SCIPdebugMsg(scip, "created transformed quadratic constraint ");
12548  SCIPdebugPrintCons(scip, *targetcons, NULL);
12549 
12550  return SCIP_OKAY;
12551 }
12552 
12553 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
12554 static
12555 SCIP_DECL_CONSINITLP(consInitlpQuadratic)
12557  SCIP_CONSHDLRDATA* conshdlrdata;
12558  SCIP_CONSDATA* consdata;
12559  SCIP_VAR* var;
12560  SCIP_ROW* row;
12561  SCIP_Real* x;
12562  int c;
12563  int i;
12564 
12565  assert(scip != NULL);
12566  assert(conshdlr != NULL);
12567  assert(conss != NULL || nconss == 0);
12568 
12569  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12570  assert(conshdlrdata != NULL);
12571 
12572  *infeasible = FALSE;
12573 
12574  for( c = 0; c < nconss && !(*infeasible); ++c )
12575  {
12576  assert(conss[c] != NULL); /*lint !e613 */
12577 
12578  if( !SCIPconsIsEnabled(conss[c]) ) /*lint !e613 */
12579  continue;
12580 
12581  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
12582 
12583  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
12584  assert(consdata != NULL);
12585 
12586  row = NULL;
12587 
12588  if( consdata->nquadvars == 0 )
12589  {
12590  /* if we are actually linear, add the constraint as row to the LP */
12591  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conss[c], SCIPconsGetName(conss[c]), consdata->lhs, consdata->rhs,
12592  SCIPconsIsLocal(conss[c]), FALSE , TRUE) ); /*lint !e613 */
12593  SCIP_CALL( SCIPaddVarsToRow(scip, row, consdata->nlinvars, consdata->linvars, consdata->lincoefs) );
12594  SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
12595  SCIP_CALL( SCIPreleaseRow (scip, &row) );
12596  continue;
12597  }
12598 
12599  /* alloc memory for reference point */
12600  SCIP_CALL( SCIPallocBufferArray(scip, &x, consdata->nquadvars) );
12601 
12602  /* for convex parts, add linearizations in 5 points */
12603  if( (consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
12604  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)) )
12605  {
12606  SCIP_Real lb;
12607  SCIP_Real ub;
12608  SCIP_Real lambda;
12609  int k;
12610 
12611  for( k = 0; k < 5; ++k )
12612  {
12613  lambda = 0.1 * (k+1); /* lambda = 0.1, 0.2, 0.3, 0.4, 0.5 */
12614  for( i = 0; i < consdata->nquadvars; ++i )
12615  {
12616  var = consdata->quadvarterms[i].var;
12617  lb = SCIPvarGetLbGlobal(var);
12618  ub = SCIPvarGetUbGlobal(var);
12619 
12620  if( ub > -INITLPMAXVARVAL )
12621  lb = MAX(lb, -INITLPMAXVARVAL);
12622  if( lb < INITLPMAXVARVAL )
12623  ub = MIN(ub, INITLPMAXVARVAL);
12624 
12625  /* make bounds finite */
12626  if( SCIPisInfinity(scip, -lb) )
12627  lb = MIN(-10.0, ub - 0.1*REALABS(ub)); /*lint !e666 */
12628  if( SCIPisInfinity(scip, ub) )
12629  ub = MAX( 10.0, lb + 0.1*REALABS(lb)); /*lint !e666 */
12630 
12632  x[i] = lambda * ub + (1.0 - lambda) * lb;
12633  else
12634  x[i] = lambda * lb + (1.0 - lambda) * ub;
12635  }
12636 
12637  SCIP_CALL( generateCut(scip, conshdlr, conss[c], x, NULL, consdata->isconvex ? SCIP_SIDETYPE_RIGHT : SCIP_SIDETYPE_LEFT, &row, NULL,
12638  FALSE, -SCIPinfinity(scip)) ); /*lint !e613 */
12639  if( row != NULL )
12640  {
12641  SCIPdebugMsg(scip, "initlp adds row <%s> for lambda = %g of conss <%s>\n", SCIProwGetName(row), lambda, SCIPconsGetName(conss[c])); /*lint !e613 */
12642  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
12643 
12644  SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
12645  SCIP_CALL( SCIPreleaseRow (scip, &row) );
12646  }
12647  }
12648  }
12649 
12650  /* for concave parts, add underestimator w.r.t. at most 2 reference points */
12651  if( !(*infeasible) && ((! consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs))
12652  || (! consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs))) )
12653  {
12654  SCIP_Bool unbounded;
12655  SCIP_Bool possquare;
12656  SCIP_Bool negsquare;
12657  SCIP_Real lb;
12658  SCIP_Real ub;
12659  SCIP_Real lambda;
12660  int k;
12661 
12662  unbounded = FALSE; /* whether there are unbounded variables */
12663  possquare = FALSE; /* whether there is a positive square term */
12664  negsquare = FALSE; /* whether there is a negative square term */
12665  for( k = 0; k < 2; ++k )
12666  {
12667  /* Set reference point to 0 projected on bounds for unbounded variables or in between lower and upper bound
12668  * for bounded variables in the first round, we set it closer to the best bound for one part of the
12669  * variables, in the second closer to the best bound for the other part of the variables.
12670  * Additionally, we use slightly different weights for each variable.
12671  * The reason for the latter is, that for a bilinear term with bounded variables, there are always two linear underestimators
12672  * if the same weight is used for both variables of a product, then rounding and luck decides which underestimator is chosen
12673  * of course, the possible number of cuts is something in the order of 2^nquadvars, and we choose two of them here.
12674  */
12675  for( i = 0; i < consdata->nquadvars; ++i )
12676  {
12677  var = consdata->quadvarterms[i].var;
12678  lb = SCIPvarGetLbGlobal(var);
12679  ub = SCIPvarGetUbGlobal(var);
12680 
12681  if( SCIPisInfinity(scip, -lb) )
12682  {
12683  if( SCIPisInfinity(scip, ub) )
12684  x[i] = 0.0;
12685  else
12686  x[i] = MIN(0.0, ub);
12687  unbounded = TRUE;
12688  }
12689  else
12690  {
12691  if( SCIPisInfinity(scip, ub) )
12692  {
12693  x[i] = MAX(0.0, lb);
12694  unbounded = TRUE;
12695  }
12696  else
12697  {
12698  lambda = 0.4 + 0.2 * ((i+k)%2) + 0.01 * i / (double)consdata->nquadvars;
12699  x[i] = lambda * SCIPvarGetBestBoundLocal(var) + (1.0-lambda) * SCIPvarGetWorstBoundLocal(var);
12700  }
12701  }
12702 
12703  possquare |= consdata->quadvarterms[i].sqrcoef > 0.0; /*lint !e514 */
12704  negsquare |= consdata->quadvarterms[i].sqrcoef < 0.0; /*lint !e514 */
12705  }
12706 
12707  if( !consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs) )
12708  {
12709  SCIP_CALL( generateCut(scip, conshdlr, conss[c], x, NULL, SCIP_SIDETYPE_RIGHT, &row, NULL,
12710  conshdlrdata->checkcurvature, -SCIPinfinity(scip)) ); /*lint !e613 */
12711  if( row != NULL )
12712  {
12713  SCIPdebugMsg(scip, "initlp adds row <%s> for rhs of conss <%s>, round %d\n", SCIProwGetName(row), SCIPconsGetName(conss[c]), k); /*lint !e613 */
12714  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
12715 
12716  SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
12717  SCIP_CALL( SCIPreleaseRow (scip, &row) );
12718  }
12719  }
12720  if( !(*infeasible) && !consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs) )
12721  {
12722  SCIP_CALL( generateCut(scip, conshdlr, conss[c], x, NULL, SCIP_SIDETYPE_LEFT, &row, NULL,
12723  conshdlrdata->checkcurvature, -SCIPinfinity(scip)) ); /*lint !e613 */
12724  if( row != NULL )
12725  {
12726  SCIPdebugMsg(scip, "initlp adds row <%s> for lhs of conss <%s>, round %d\n", SCIProwGetName(row), SCIPconsGetName(conss[c]), k); /*lint !e613 */
12727  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
12728 
12729  SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
12730  SCIP_CALL( SCIPreleaseRow (scip, &row) );
12731  }
12732  }
12733 
12734  /* if there are unbounded variables, then there is typically only at most one possible underestimator, so don't try another round
12735  * 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 */
12736  if( unbounded ||
12737  (consdata->nbilinterms == 0 && (!possquare || SCIPisInfinity(scip, consdata->rhs))) ||
12738  (consdata->nbilinterms == 0 && (!negsquare || SCIPisInfinity(scip, -consdata->lhs))) )
12739  break;
12740  }
12741  }
12742 
12743  SCIPfreeBufferArray(scip, &x);
12744  }
12745 
12746  /* store all bilinear terms into constraint handler data; this code is not in initsolve because the sub-NLP
12747  * heuristic triggers this callback and should not collect all bilinear terms
12748  */
12749  SCIP_CALL( storeAllBilinearTerms(scip, conshdlrdata, conss, nconss) );
12750 
12751  return SCIP_OKAY;
12752 }
12753 
12754 /** separation method of constraint handler for LP solutions */
12755 static
12756 SCIP_DECL_CONSSEPALP(consSepalpQuadratic)
12757 {
12758  SCIP_CONSHDLRDATA* conshdlrdata;
12759  SCIP_Bool solviolbounds;
12760  SCIP_CONS* maxviolcon;
12761 
12762  assert(scip != NULL);
12763  assert(conshdlr != NULL);
12764  assert(conss != NULL || nconss == 0);
12765  assert(result != NULL);
12766 
12767  *result = SCIP_DIDNOTFIND;
12768 
12769  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12770  assert(conshdlrdata != NULL);
12771 
12772  SCIP_CALL( computeViolations(scip, conss, nconss, NULL, &solviolbounds, &maxviolcon) );
12773 
12774  /* don't try to separate solutions that violate variable bounds */
12775  if( solviolbounds )
12776  return SCIP_OKAY;
12777 
12778  /* if nothing violated, then nothing to separate */
12779  if( maxviolcon == NULL )
12780  return SCIP_OKAY;
12781 
12782  /* at root, check if we want to solve the NLP relaxation and use its solutions as reference point
12783  * if there is something convex, then linearizing in the solution of the NLP relaxation can be very useful
12784  */
12785  if( SCIPgetDepth(scip) == 0 && !conshdlrdata->sepanlp &&
12786  (SCIPgetNContVars(scip) >= conshdlrdata->sepanlpmincont * SCIPgetNVars(scip) ||
12787  (SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY && conshdlrdata->sepanlpmincont <= 1.0)) &&
12788  SCIPisNLPConstructed(scip) && SCIPgetNNlpis(scip) > 0 )
12789  {
12790  SCIP_CONSDATA* consdata;
12791  SCIP_NLPSOLSTAT solstat;
12792  SCIP_Bool solvednlp;
12793  int c;
12794 
12795  solstat = SCIPgetNLPSolstat(scip);
12796  solvednlp = FALSE;
12797  if( solstat == SCIP_NLPSOLSTAT_UNKNOWN )
12798  {
12799  /* NLP is not solved yet, so we might want to do this
12800  * but first check whether there is a violated constraint side which corresponds to a convex function
12801  */
12802  for( c = 0; c < nconss; ++c )
12803  {
12804  assert(conss[c] != NULL); /*lint !e613 */
12805 
12806  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
12807  assert(consdata != NULL);
12808 
12809  /* skip feasible constraints */
12810  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
12811  continue;
12812 
12813  /* make sure curvature has been checked */
12814  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
12815 
12816  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && consdata->isconvex) ||
12817  ( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && consdata->isconcave) )
12818  break;
12819  }
12820 
12821  if( c < nconss )
12822  {
12823  /* try to solve NLP and update solstat */
12824 
12825  /* ensure linear conss are in NLP */
12826  if( conshdlrdata->subnlpheur != NULL )
12827  {
12828  SCIP_CALL( SCIPaddLinearConsToNlpHeurSubNlp(scip, conshdlrdata->subnlpheur, TRUE, TRUE) );
12829  }
12830 
12831  /* set LP solution as starting values, if available */
12833  {
12835  }
12836 
12837  /* SCIP_CALL( SCIPsetNLPIntPar(scip, SCIP_NLPPAR_VERBLEVEL, 1) ); */
12838  SCIP_CALL( SCIPsolveNLP(scip) );
12839 
12840  solstat = SCIPgetNLPSolstat(scip);
12841  SCIPdebugMsg(scip, "solved NLP relax, solution status: %d\n", solstat);
12842 
12843  solvednlp = TRUE;
12844  }
12845  }
12846 
12847  conshdlrdata->sepanlp = TRUE;
12848 
12849  if( solstat == SCIP_NLPSOLSTAT_GLOBINFEASIBLE )
12850  {
12851  SCIPdebugMsg(scip, "NLP relaxation is globally infeasible, thus can cutoff node\n");
12852  *result = SCIP_CUTOFF;
12853  return SCIP_OKAY;
12854  }
12855 
12856  if( solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
12857  {
12858  /* if we have feasible NLP solution, generate linearization cuts there */
12859  SCIP_Bool lpsolseparated;
12860  SCIP_SOL* nlpsol;
12861 
12862  SCIP_CALL( SCIPcreateNLPSol(scip, &nlpsol, NULL) );
12863  assert(nlpsol != NULL);
12864 
12865  /* if we solved the NLP and solution is integral, then pass it to trysol heuristic */
12866  if( solvednlp && conshdlrdata->trysolheur != NULL )
12867  {
12868  int nfracvars;
12869 
12870  nfracvars = 0;
12871  if( SCIPgetNBinVars(scip) > 0 || SCIPgetNIntVars(scip) > 0 )
12872  {
12873  SCIP_CALL( SCIPgetNLPFracVars(scip, NULL, NULL, NULL, &nfracvars, NULL) );
12874  }
12875 
12876  if( nfracvars == 0 )
12877  {
12878  SCIPdebugMsg(scip, "pass solution with obj. value %g to trysol\n", SCIPgetSolOrigObj(scip, nlpsol));
12879  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, nlpsol) );
12880  }
12881  }
12882 
12883  SCIP_CALL( addLinearizationCuts(scip, conshdlr, conss, nconss, nlpsol, &lpsolseparated, SCIPgetSepaMinEfficacy(scip)) );
12884 
12885  SCIP_CALL( SCIPfreeSol(scip, &nlpsol) );
12886 
12887  /* if a cut that separated the LP solution was added, then return, otherwise continue with usual separation in LP solution */
12888  if( lpsolseparated )
12889  {
12890  SCIPdebugMsg(scip, "linearization cuts separate LP solution\n");
12891  *result = SCIP_SEPARATED;
12892 
12893  return SCIP_OKAY;
12894  }
12895  }
12896  }
12897  /* if we do not want to try solving the NLP, or have no NLP, or have no NLP solver, or solving the NLP failed,
12898  * or separating with NLP solution as reference point failed, then try (again) with LP solution as reference point
12899  */
12900 
12901  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, NULL, SCIPgetSepaMinEfficacy(scip), FALSE, result, NULL) );
12902 
12903  return SCIP_OKAY;
12904 }
12905 
12906 /** separation method of constraint handler for arbitrary primal solutions */
12907 static
12908 SCIP_DECL_CONSSEPASOL(consSepasolQuadratic)
12910  SCIP_Bool solviolbounds;
12911  SCIP_CONS* maxviolcon;
12912 
12913  assert(scip != NULL);
12914  assert(conshdlr != NULL);
12915  assert(conss != NULL || nconss == 0);
12916  assert(sol != NULL);
12917  assert(result != NULL);
12918 
12919  *result = SCIP_DIDNOTFIND;
12920 
12921  SCIP_CALL( computeViolations(scip, conss, nconss, sol, &solviolbounds, &maxviolcon) );
12922 
12923  /* don't separate solution that are outside variable bounds */
12924  if( solviolbounds )
12925  return SCIP_OKAY;
12926 
12927  /* if nothing violated, then nothing to separate */
12928  if( maxviolcon == NULL )
12929  return SCIP_OKAY;
12930 
12931  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, SCIPgetSepaMinEfficacy(scip), FALSE, result, NULL) );
12932 
12933  return SCIP_OKAY;
12934 }
12935 
12936 /** constraint enforcing method of constraint handler for LP solutions */
12937 static
12938 SCIP_DECL_CONSENFOLP(consEnfolpQuadratic)
12939 { /*lint --e{715}*/
12940  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, solinfeasible, result) );
12941 
12942  return SCIP_OKAY;
12943 }
12944 
12945 /** constraint enforcing method of constraint handler for relaxation solutions */
12946 static
12947 SCIP_DECL_CONSENFORELAX(consEnforelaxQuadratic)
12948 { /*lint --e{715}*/
12949  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, solinfeasible, result) );
12950 
12951  return SCIP_OKAY;
12952 }
12953 
12954 /** constraint enforcing method of constraint handler for pseudo solutions */
12955 static
12956 SCIP_DECL_CONSENFOPS(consEnfopsQuadratic)
12957 { /*lint --e{715}*/
12958  SCIP_Bool solviolbounds;
12959  SCIP_CONS* maxviolcon;
12960  SCIP_CONSDATA* consdata;
12961  SCIP_RESULT propresult;
12962  SCIP_VAR* var;
12963  int c;
12964  int i;
12965  int nchgbds;
12966  int nnotify;
12967 
12968  assert(scip != NULL);
12969  assert(conss != NULL || nconss == 0);
12970 
12971  SCIP_CALL( computeViolations(scip, conss, nconss, NULL, &solviolbounds, &maxviolcon) );
12972 
12973  /* pseudo solutions should be within bounds by definition */
12974  assert(!solviolbounds);
12975 
12976  if( maxviolcon == NULL )
12977  {
12978  *result = SCIP_FEASIBLE;
12979  return SCIP_OKAY;
12980  }
12981 
12982  *result = SCIP_INFEASIBLE;
12983 
12984  SCIPdebugMsg(scip, "enfops with max violation in cons <%s>\n", SCIPconsGetName(maxviolcon));
12985 
12986  /* run domain propagation */
12987  nchgbds = 0;
12988  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, &propresult, &nchgbds) );
12989  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
12990  {
12991  *result = propresult;
12992  return SCIP_OKAY;
12993  }
12994 
12995  /* we are not feasible and we cannot proof that the whole node is infeasible
12996  * -> collect all variables in violated constraints for branching
12997  */
12998  nnotify = 0;
12999  for( c = 0; c < nconss; ++c )
13000  {
13001  assert(conss != NULL);
13002  consdata = SCIPconsGetData(conss[c]);
13003  assert(consdata != NULL);
13004 
13005  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
13006  continue;
13007 
13008  for( i = 0; i < consdata->nlinvars; ++i )
13009  {
13010  var = consdata->linvars[i];
13011  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
13012  {
13013  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
13014  ++nnotify;
13015  }
13016  }
13017 
13018  for( i = 0; i < consdata->nquadvars; ++i )
13019  {
13020  var = consdata->quadvarterms[i].var;
13021  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
13022  {
13023  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
13024  ++nnotify;
13025  }
13026  }
13027  }
13028 
13029  if( nnotify == 0 )
13030  {
13031  SCIP_Bool addedcons;
13032  SCIP_Bool reduceddom;
13033  SCIP_Bool infeasible;
13034 
13035  /* if no branching candidate found, then all variables are almost fixed
13036  * calling replaceByLinearConstraints() should lead to fix all almost-fixed quadratic variables, and possibly replace some quad. conss by linear ones
13037  */
13038  SCIP_CALL( replaceByLinearConstraints(scip, conss, nconss, &addedcons, &reduceddom, &infeasible) );
13039  if( addedcons )
13040  {
13041  *result = SCIP_CONSADDED;
13042  return SCIP_OKAY;
13043  }
13044  if( reduceddom )
13045  {
13046  *result = SCIP_REDUCEDDOM;
13047  return SCIP_OKAY;
13048  }
13049  if( infeasible )
13050  {
13051  *result = SCIP_CUTOFF;
13052  return SCIP_OKAY;
13053  }
13054 
13055  SCIPdebugMsg(scip, "All variables in violated constraints fixed (up to epsilon). Cannot find branching candidate. Forcing solution of LP.\n");
13056  *result = SCIP_SOLVELP;
13057  }
13058 
13059  assert(*result == SCIP_SOLVELP || (*result == SCIP_INFEASIBLE && nnotify > 0));
13060  return SCIP_OKAY;
13061 }
13062 
13063 /** domain propagation method of constraint handler */
13064 static
13065 SCIP_DECL_CONSPROP(consPropQuadratic)
13067  int nchgbds;
13068 
13069  assert(scip != NULL);
13070  assert(conshdlr != NULL);
13071  assert(conss != NULL || nconss == 0);
13072  assert(result != NULL);
13073 
13074  nchgbds = 0;
13075  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nmarkedconss, result, &nchgbds) );
13076 
13077  return SCIP_OKAY;
13078 } /*lint !e715 */
13079 
13080 /** presolving method of constraint handler */
13081 static
13082 SCIP_DECL_CONSPRESOL(consPresolQuadratic)
13083 { /*lint --e{715,788}*/
13084  SCIP_CONSHDLRDATA* conshdlrdata;
13085  SCIP_CONSDATA* consdata;
13086  SCIP_RESULT solveresult;
13087  SCIP_Bool redundant;
13088  SCIP_Bool havechange;
13089  SCIP_Bool doreformulations;
13090  int c;
13091  int i;
13092 
13093  assert(scip != NULL);
13094  assert(conshdlr != NULL);
13095  assert(conss != NULL || nconss == 0);
13096  assert(result != NULL);
13097 
13098  *result = SCIP_DIDNOTFIND;
13099 
13100  /* if other presolvers did not find enough changes for another presolving round and we are in exhaustive presolving,
13101  * then try the reformulations (replacing products with binaries, disaggregation, setting default variable bounds)
13102  * otherwise, we wait with these
13103  */
13104  doreformulations = ((presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0) && SCIPisPresolveFinished(scip);
13105  SCIPdebugMsg(scip, "presolving will %swait with reformulation\n", doreformulations ? "not " : "");
13106 
13107  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13108  assert(conshdlrdata != NULL);
13109 
13110  for( c = 0; c < nconss; ++c )
13111  {
13112  assert(conss != NULL);
13113  consdata = SCIPconsGetData(conss[c]);
13114  assert(consdata != NULL);
13115 
13116  SCIPdebugMsg(scip, "process constraint <%s>\n", SCIPconsGetName(conss[c]));
13117  SCIPdebugPrintCons(scip, conss[c], NULL);
13118 
13119  if( !consdata->initialmerge )
13120  {
13121  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
13122  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
13123  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
13124  consdata->initialmerge = TRUE;
13125 
13126  if( SCIPisInfinity(scip, consdata->lhs) || SCIPisInfinity(scip, -consdata->rhs) )
13127  {
13128  SCIPdebugMsg(scip, "lhs or rhs at wrong side of infinity -> declaring cutoff\n");
13129  *result = SCIP_CUTOFF;
13130  return SCIP_OKAY;
13131  }
13132  }
13133 
13134  havechange = FALSE;
13135 #ifdef CHECKIMPLINBILINEAR
13136  if( consdata->isimpladded && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
13137  {
13138  int nbilinremoved;
13139  SCIP_CALL( presolveApplyImplications(scip, conss[c], &nbilinremoved) );
13140  if( nbilinremoved > 0 )
13141  {
13142  *nchgcoefs += nbilinremoved;
13143  havechange = TRUE;
13144  *result = SCIP_SUCCESS;
13145  }
13146  assert(!consdata->isimpladded);
13147  }
13148 #endif
13149  /* 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
13150  * we want to do this before (multi)aggregated variables are replaced, since that may change structure, e.g., introduce bilinear terms
13151  */
13152  if( !consdata->ispresolved || !consdata->ispropagated || nnewchgvartypes > 0 )
13153  {
13154  SCIP_Bool upgraded;
13155 
13156  SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss, presoltiming) );
13157  if( upgraded )
13158  {
13159  *result = SCIP_SUCCESS;
13160  continue;
13161  }
13162  }
13163 
13164  if( !consdata->isremovedfixings )
13165  {
13166  SCIP_CALL( removeFixedVariables(scip, conshdlrdata->eventhdlr, conss[c]) );
13167  assert(consdata->isremovedfixings);
13168  havechange = TRUE;
13169  }
13170 
13171  /* try to "solve" the constraint, e.g., reduce to a variable aggregation */
13172  SCIP_CALL( presolveSolve(scip, conss[c], &solveresult, &redundant, naggrvars) );
13173  if( solveresult == SCIP_CUTOFF )
13174  {
13175  SCIPdebugMsg(scip, "solving constraint <%s> says problem is infeasible in presolve\n", SCIPconsGetName(conss[c]));
13176  *result = SCIP_CUTOFF;
13177  return SCIP_OKAY;
13178  }
13179  if( redundant )
13180  {
13181  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
13182  ++*ndelconss;
13183  *result = SCIP_SUCCESS;
13184  break;
13185  }
13186  if( solveresult == SCIP_SUCCESS )
13187  {
13188  *result = SCIP_SUCCESS;
13189  havechange = TRUE;
13190  }
13191 
13192  /* @todo divide constraint by gcd of coefficients if all are integral */
13193 
13194  if( doreformulations )
13195  {
13196  int naddconss_old;
13197 
13198  naddconss_old = *naddconss;
13199 
13200  SCIP_CALL( presolveTryAddAND(scip, conshdlr, conss[c], naddconss) );
13201  assert(*naddconss >= naddconss_old);
13202 
13203  if( *naddconss == naddconss_old )
13204  {
13205  /* user not so empathic about AND, or we don't have products of two binaries, so try this more general reformulation */
13206  SCIP_CALL( presolveTryAddLinearReform(scip, conshdlr, conss[c], naddconss) );
13207  assert(*naddconss >= naddconss_old);
13208  }
13209 
13210  if( conshdlrdata->maxdisaggrsize > 1 )
13211  {
13212  /* try disaggregation, if enabled */
13213  SCIP_CALL( presolveDisaggregate(scip, conshdlr, conss[c], naddconss) );
13214  }
13215 
13216  if( *naddconss > naddconss_old )
13217  {
13218  /* if something happened, report success and cleanup constraint */
13219  *result = SCIP_SUCCESS;
13220  havechange = TRUE;
13221  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
13222  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
13223  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
13224  }
13225  }
13226 
13227  if( consdata->nlinvars == 0 && consdata->nquadvars == 0 )
13228  {
13229  /* all variables fixed or removed, constraint function is 0.0 now */
13230  if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasPositive(scip, consdata->lhs)) ||
13231  ( !SCIPisInfinity(scip, consdata->rhs) && SCIPisFeasNegative(scip, consdata->rhs)) )
13232  { /* left hand side positive or right hand side negative */
13233  SCIPdebugMsg(scip, "constraint <%s> is constant and infeasible\n", SCIPconsGetName(conss[c]));
13234  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
13235  ++*ndelconss;
13236  *result = SCIP_CUTOFF;
13237  return SCIP_OKAY;
13238  }
13239 
13240  /* left and right hand side are consistent */
13241  SCIPdebugMsg(scip, "constraint <%s> is constant and feasible, deleting\n", SCIPconsGetName(conss[c]));
13242  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
13243  ++*ndelconss;
13244  *result = SCIP_SUCCESS;
13245  continue;
13246  }
13247 
13248  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 && !consdata->ispropagated )
13249  {
13250  /* try domain propagation if there were bound changes or constraint has changed (in which case, processVarEvents may have set ispropagated to false) */
13251  SCIP_RESULT propresult;
13252  int roundnr;
13253 
13254  roundnr = 0;
13255  do
13256  {
13257  ++roundnr;
13258 
13259  SCIPdebugMsg(scip, "starting domain propagation round %d of %d\n", roundnr, conshdlrdata->maxproproundspresolve);
13260 
13261  if( !consdata->ispropagated )
13262  {
13263  consdata->ispropagated = TRUE;
13264 
13265  SCIP_CALL( propagateBoundsCons(scip, conshdlr, conss[c], &propresult, nchgbds, &redundant) );
13266 
13267  if( propresult == SCIP_CUTOFF )
13268  {
13269  SCIPdebugMsg(scip, "propagation on constraint <%s> says problem is infeasible in presolve\n",
13270  SCIPconsGetName(conss[c]));
13271  *result = SCIP_CUTOFF;
13272  return SCIP_OKAY;
13273  }
13274 
13275  /* delete constraint if found redundant by bound tightening */
13276  if( redundant )
13277  {
13278  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
13279  ++*ndelconss;
13280  *result = SCIP_SUCCESS;
13281  break;
13282  }
13283 
13284  if( propresult == SCIP_REDUCEDDOM )
13285  {
13286  *result = SCIP_SUCCESS;
13287  havechange = TRUE;
13288  }
13289  }
13290  }
13291  while( !consdata->ispropagated && roundnr < conshdlrdata->maxproproundspresolve );
13292 
13293  if( redundant )
13294  continue;
13295  }
13296 
13297  /* check if we have a single linear continuous variable that we can make implicit integer */
13298  if( (nnewchgvartypes != 0 || havechange || !consdata->ispresolved)
13299  && (SCIPisEQ(scip, consdata->lhs, consdata->rhs) && SCIPisIntegral(scip, consdata->lhs)) )
13300  {
13301  int ncontvar;
13302  SCIP_VAR* candidate;
13303  SCIP_Bool fail;
13304 
13305  fail = FALSE;
13306  candidate = NULL;
13307  ncontvar = 0;
13308 
13309  for( i = 0; !fail && i < consdata->nlinvars; ++i )
13310  {
13311  if( !SCIPisIntegral(scip, consdata->lincoefs[i]) )
13312  {
13313  fail = TRUE;
13314  }
13315  else if( SCIPvarGetType(consdata->linvars[i]) == SCIP_VARTYPE_CONTINUOUS )
13316  {
13317  if( ncontvar > 0 ) /* now at 2nd continuous variable */
13318  fail = TRUE;
13319  else if( SCIPisEQ(scip, ABS(consdata->lincoefs[i]), 1.0) )
13320  candidate = consdata->linvars[i];
13321  ++ncontvar;
13322  }
13323  }
13324  for( i = 0; !fail && i < consdata->nquadvars; ++i )
13325  fail = SCIPvarGetType(consdata->quadvarterms[i].var) == SCIP_VARTYPE_CONTINUOUS ||
13326  !SCIPisIntegral(scip, consdata->quadvarterms[i].lincoef) ||
13327  !SCIPisIntegral(scip, consdata->quadvarterms[i].sqrcoef);
13328  for( i = 0; !fail && i < consdata->nbilinterms; ++i )
13329  fail = !SCIPisIntegral(scip, consdata->bilinterms[i].coef);
13330 
13331  if( !fail && candidate != NULL )
13332  {
13333  SCIP_Bool infeasible;
13334 
13335  SCIPdebugMsg(scip, "make variable <%s> implicit integer due to constraint <%s>\n", SCIPvarGetName(candidate), SCIPconsGetName(conss[c]));
13336 
13337  SCIP_CALL( SCIPchgVarType(scip, candidate, SCIP_VARTYPE_IMPLINT, &infeasible) );
13338  if( infeasible )
13339  {
13340  SCIPdebugMsg(scip, "infeasible upgrade of variable <%s> to integral type, domain is empty\n", SCIPvarGetName(candidate));
13341  *result = SCIP_CUTOFF;
13342 
13343  return SCIP_OKAY;
13344  }
13345 
13346  ++(*nchgvartypes);
13347  *result = SCIP_SUCCESS;
13348  havechange = TRUE;
13349  }
13350  }
13351 
13352  /* call upgrade methods again if constraint has been changed */
13353  if( havechange )
13354  {
13355  SCIP_Bool upgraded;
13356 
13357  SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss, presoltiming) );
13358  if( upgraded )
13359  {
13360  *result = SCIP_SUCCESS;
13361  continue;
13362  }
13363  }
13364 
13365  /* fix quadratic variables with proper square coefficients contained in a single quadratic constraint to their
13366  * upper or lower bounds
13367  */
13368  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 && conshdlrdata->checkquadvarlocks != 'd'
13369  && SCIPisPresolveFinished(scip) )
13370  {
13371  SCIP_CONS* cons;
13372  SCIP_VAR* vars[2];
13373  SCIP_BOUNDTYPE boundtypes[2];
13374  SCIP_Real bounds[2];
13375  char name[SCIP_MAXSTRLEN];
13376 
13377  /* merge variables in order to get correct locks for quadratic variables */
13378  if( !consdata->initialmerge )
13379  {
13380  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
13381  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
13382  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
13383  consdata->initialmerge = TRUE;
13384  }
13385 
13386  for( i = 0; i < consdata->nquadvars; ++i )
13387  {
13388  if( hasQuadvarHpProperty(scip, consdata, i) )
13389  {
13390  SCIP_VAR* var;
13391 
13392  var = consdata->quadvarterms[i].var;
13393  assert(var != NULL);
13394 
13395  /* try to change the variable type to binary */
13396  if( conshdlrdata->checkquadvarlocks == 't' && SCIPisEQ(scip, SCIPvarGetLbGlobal(var), 0.0) && SCIPisEQ(scip, SCIPvarGetUbGlobal(var), 1.0) )
13397  {
13398  SCIP_Bool infeasible;
13399 
13400  assert(SCIPvarGetType(var) != SCIP_VARTYPE_BINARY);
13401  SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, &infeasible) );
13402 
13403  if( infeasible )
13404  {
13405  SCIPdebugMsg(scip, "detect infeasibility after changing variable <%s> to binary type\n", SCIPvarGetName(var));
13406  *result = SCIP_CUTOFF;
13407  return SCIP_OKAY;
13408  }
13409  }
13410  /* add bound disjunction constraint if bounds of variable are finite */
13411  else if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
13412  {
13413  vars[0] = var;
13414  vars[1] = var;
13415  boundtypes[0] = SCIP_BOUNDTYPE_LOWER;
13416  boundtypes[1] = SCIP_BOUNDTYPE_UPPER;
13417  bounds[0] = SCIPvarGetUbGlobal(var);
13418  bounds[1] = SCIPvarGetLbGlobal(var);
13419 
13420  SCIPdebugMsg(scip, "add bound disjunction constraint for %s\n", SCIPvarGetName(var));
13421 
13422  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "quadvarbnddisj_%s", SCIPvarGetName(var));
13423  SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &cons, name, 2, vars, boundtypes, bounds, TRUE, TRUE,
13424  TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
13425 
13426  SCIP_CALL( SCIPaddCons(scip, cons) );
13427  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
13428  }
13429 
13430  *result = SCIP_SUCCESS;
13431  }
13432  }
13433  }
13434 
13435  consdata->ispresolved = TRUE;
13436  }
13437 
13438  return SCIP_OKAY;
13439 }
13440 
13441 /** variable rounding lock method of constraint handler */
13442 static
13443 SCIP_DECL_CONSLOCK(consLockQuadratic)
13444 { /*lint --e{715}*/
13445  SCIP_CONSDATA* consdata;
13446  SCIP_Bool haslb;
13447  SCIP_Bool hasub;
13448  int i;
13449 
13450  assert(scip != NULL);
13451  assert(cons != NULL);
13452  assert(locktype == SCIP_LOCKTYPE_MODEL);
13453 
13454  consdata = SCIPconsGetData(cons);
13455  assert(consdata != NULL);
13456 
13457  haslb = !SCIPisInfinity(scip, -consdata->lhs);
13458  hasub = !SCIPisInfinity(scip, consdata->rhs);
13459 
13460  for( i = 0; i < consdata->nlinvars; ++i )
13461  {
13462  if( consdata->lincoefs[i] > 0 )
13463  {
13464  if( haslb )
13465  {
13466  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->linvars[i], locktype, nlockspos, nlocksneg) );
13467  }
13468  if( hasub )
13469  {
13470  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->linvars[i], locktype, nlocksneg, nlockspos) );
13471  }
13472  }
13473  else
13474  {
13475  if( haslb )
13476  {
13477  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->linvars[i], locktype, nlocksneg, nlockspos) );
13478  }
13479  if( hasub )
13480  {
13481  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->linvars[i], locktype, nlockspos, nlocksneg) );
13482  }
13483  }
13484  }
13485 
13486  for( i = 0; i < consdata->nquadvars; ++i )
13487  {
13488  /* @todo try to be more clever, but variable locks that depend on the bounds of other variables are not trival to maintain */
13489  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->quadvarterms[i].var, SCIP_LOCKTYPE_MODEL, nlockspos+nlocksneg,
13490  nlockspos+nlocksneg) );
13491  }
13492 
13493  return SCIP_OKAY;
13494 }
13495 
13496 /** constraint enabling notification method of constraint handler */
13497 static
13498 SCIP_DECL_CONSENABLE(consEnableQuadratic)
13500  SCIP_CONSHDLRDATA* conshdlrdata;
13501 
13502  assert(scip != NULL);
13503  assert(conshdlr != NULL);
13504  assert(cons != NULL);
13505  assert(SCIPconsIsTransformed(cons));
13506  assert(SCIPconsIsActive(cons));
13507 
13508  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13509  assert(conshdlrdata != NULL);
13510 
13511  SCIPdebugMsg(scip, "enable cons <%s>\n", SCIPconsGetName(cons));
13512 
13513  /* catch variable events */
13514  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
13515 
13516  if( SCIPgetStage(scip) >= SCIP_STAGE_EXITPRESOLVE )
13517  {
13518  /* merge duplicate bilinear terms, move quad terms that are linear to linear vars */
13519  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
13520  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, cons) );
13521  SCIP_CALL( mergeAndCleanLinearVars(scip, cons) );
13522  }
13523 
13524  /* initialize solving data */
13525  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
13526  {
13527  SCIP_CALL( consInitsolQuadratic(scip, conshdlr, &cons, 1) );
13528  }
13529 
13530  return SCIP_OKAY;
13531 }
13532 
13533 /** constraint disabling notification method of constraint handler */
13534 static
13535 SCIP_DECL_CONSDISABLE(consDisableQuadratic)
13536 { /*lint --e{715}*/
13537  SCIP_CONSHDLRDATA* conshdlrdata;
13538 
13539  assert(scip != NULL);
13540  assert(conshdlr != NULL);
13541  assert(cons != NULL);
13542  assert(SCIPconsIsTransformed(cons));
13543 
13544  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13545  assert(conshdlrdata != NULL);
13546 
13547  SCIPdebugMsg(scip, "disable cons <%s>\n", SCIPconsGetName(cons));
13548 
13549  /* free solving data */
13550  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
13551  {
13552  SCIP_CALL( consExitsolQuadratic(scip, conshdlr, &cons, 1, FALSE) );
13553  }
13554 
13555  /* drop variable events */
13556  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
13557 
13558  return SCIP_OKAY;
13559 }
13560 
13561 /** constraint display method of constraint handler */
13562 static
13563 SCIP_DECL_CONSPRINT(consPrintQuadratic)
13564 { /*lint --e{715}*/
13565  SCIP_CONSDATA* consdata;
13566 
13567  assert(scip != NULL);
13568  assert(cons != NULL);
13569 
13570  consdata = SCIPconsGetData(cons);
13571  assert(consdata != NULL);
13572 
13573  /* print left hand side for ranged rows */
13574  if( !SCIPisInfinity(scip, -consdata->lhs)
13575  && !SCIPisInfinity(scip, consdata->rhs)
13576  && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
13577  SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
13578 
13579  /* print coefficients and variables */
13580  if( consdata->nlinvars == 0 && consdata->nquadvars == 0 )
13581  {
13582  SCIPinfoMessage(scip, file, "0 ");
13583  }
13584  else
13585  {
13586  SCIP_VAR*** monomialvars;
13587  SCIP_Real** monomialexps;
13588  SCIP_Real* monomialcoefs;
13589  int* monomialnvars;
13590  int nmonomials;
13591  int monomialssize;
13592  int j;
13593 
13594  monomialssize = consdata->nlinvars + 2 * consdata->nquadvars + consdata->nbilinterms;
13595  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars, monomialssize) );
13596  SCIP_CALL( SCIPallocBufferArray(scip, &monomialexps, monomialssize) );
13597  SCIP_CALL( SCIPallocBufferArray(scip, &monomialcoefs, monomialssize) );
13598  SCIP_CALL( SCIPallocBufferArray(scip, &monomialnvars, monomialssize) );
13599 
13600  nmonomials = 0;
13601  for( j = 0; j < consdata->nlinvars; ++j )
13602  {
13603  assert(nmonomials < monomialssize);
13604 
13605  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 1) ); /*lint !e866 */
13606 
13607  monomialvars[nmonomials][0] = consdata->linvars[j];
13608  monomialexps[nmonomials] = NULL;
13609  monomialcoefs[nmonomials] = consdata->lincoefs[j];
13610  monomialnvars[nmonomials] = 1;
13611  ++nmonomials;
13612  }
13613 
13614  for( j = 0; j < consdata->nquadvars; ++j )
13615  {
13616  if( consdata->quadvarterms[j].lincoef != 0.0 )
13617  {
13618  assert(nmonomials < monomialssize);
13619 
13620  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 1) ); /*lint !e866 */
13621 
13622  monomialvars[nmonomials][0] = consdata->quadvarterms[j].var;
13623  monomialexps[nmonomials] = NULL;
13624  monomialcoefs[nmonomials] = consdata->quadvarterms[j].lincoef;
13625  monomialnvars[nmonomials] = 1;
13626  ++nmonomials;
13627  }
13628 
13629  if( consdata->quadvarterms[j].sqrcoef != 0.0 )
13630  {
13631  assert(nmonomials < monomialssize);
13632 
13633  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 1) ); /*lint !e866 */
13634  SCIP_CALL( SCIPallocBufferArray(scip, &monomialexps[nmonomials], 1) ); /*lint !e866 */
13635 
13636  monomialvars[nmonomials][0] = consdata->quadvarterms[j].var;
13637  monomialexps[nmonomials][0] = 2.0;
13638  monomialcoefs[nmonomials] = consdata->quadvarterms[j].sqrcoef;
13639  monomialnvars[nmonomials] = 1;
13640  ++nmonomials;
13641  }
13642  }
13643 
13644  for( j = 0; j < consdata->nbilinterms; ++j )
13645  {
13646  assert(nmonomials < monomialssize);
13647 
13648  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 2) ); /*lint !e866 */
13649 
13650  monomialvars[nmonomials][0] = consdata->bilinterms[j].var1;
13651  monomialvars[nmonomials][1] = consdata->bilinterms[j].var2;
13652  monomialexps[nmonomials] = NULL;
13653  monomialcoefs[nmonomials] = consdata->bilinterms[j].coef;
13654  monomialnvars[nmonomials] = 2;
13655  ++nmonomials;
13656  }
13657 
13658  SCIP_CALL( SCIPwriteVarsPolynomial(scip, file, monomialvars, monomialexps, monomialcoefs, monomialnvars, nmonomials, TRUE) );
13659 
13660  for( j = nmonomials - 1; j >= 0 ; --j )
13661  {
13662  SCIPfreeBufferArrayNull(scip, &monomialexps[j]);
13663  SCIPfreeBufferArray(scip, &monomialvars[j]);
13664  }
13665 
13666  SCIPfreeBufferArray(scip, &monomialnvars);
13667  SCIPfreeBufferArray(scip, &monomialcoefs);
13668  SCIPfreeBufferArray(scip, &monomialexps);
13669  SCIPfreeBufferArray(scip, &monomialvars);
13670  }
13671 
13672  /* print right hand side */
13673  if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
13674  {
13675  SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
13676  }
13677  else if( !SCIPisInfinity(scip, consdata->rhs) )
13678  {
13679  SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
13680  }
13681  else if( !SCIPisInfinity(scip, -consdata->lhs) )
13682  {
13683  SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
13684  }
13685  else
13686  {
13687  /* should be ignored by parser */
13688  SCIPinfoMessage(scip, file, " [free]");
13689  }
13690 
13691  return SCIP_OKAY;
13692 }
13693 
13694 /** feasibility check method of constraint handler for integral solutions */
13695 static
13696 SCIP_DECL_CONSCHECK(consCheckQuadratic)
13697 { /*lint --e{715}*/
13698  SCIP_CONSHDLRDATA* conshdlrdata;
13699  SCIP_CONSDATA* consdata;
13700  SCIP_Real maxviol;
13701  int c;
13702  SCIP_Bool maypropfeasible; /* whether we may be able to propose a feasible solution */
13703  SCIP_Bool solviolbounds;
13704 
13705  assert(scip != NULL);
13706  assert(conss != NULL || nconss == 0);
13707  assert(result != NULL);
13708 
13709  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13710  assert(conshdlrdata != NULL);
13711 
13712  *result = SCIP_FEASIBLE;
13713 
13714  maxviol = 0.0;
13715  maypropfeasible = conshdlrdata->linfeasshift && (conshdlrdata->trysolheur != NULL) &&
13717  for( c = 0; c < nconss; ++c )
13718  {
13719  assert(conss != NULL);
13720  SCIP_CALL( computeViolation(scip, conss[c], sol, &solviolbounds) );
13721  assert(!solviolbounds); /* see also issue #627 */
13722 
13723  consdata = SCIPconsGetData(conss[c]);
13724  assert(consdata != NULL);
13725 
13726  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
13727  {
13728  *result = SCIP_INFEASIBLE;
13729  if( printreason )
13730  {
13731  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
13732  SCIPinfoMessage(scip, NULL, ";\n");
13733  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
13734  {
13735  SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g\n", consdata->lhsviol);
13736  }
13737  if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
13738  {
13739  SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g\n", consdata->rhsviol);
13740  }
13741  }
13742  if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible && !completely )
13743  return SCIP_OKAY;
13744  if( consdata->lhsviol > maxviol || consdata->rhsviol > maxviol )
13745  maxviol = consdata->lhsviol + consdata->rhsviol;
13746 
13747  /* do not try to shift linear variables if activity is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
13748  if( maypropfeasible && SCIPisInfinity(scip, REALABS(consdata->activity)) )
13749  maypropfeasible = FALSE;
13750 
13751  if( maypropfeasible )
13752  {
13753  /* update information on linear variables that may be in- or decreased, if initsolve has not done so yet */
13755  consdataFindUnlockedLinearVar(scip, consdata);
13756 
13757  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
13758  {
13759  /* check if there is a variable which may help to get the left hand side satisfied
13760  * if there is no such var, then we cannot get feasible */
13761  if( !(consdata->linvar_mayincrease >= 0 && consdata->lincoefs[consdata->linvar_mayincrease] > 0.0) &&
13762  ! (consdata->linvar_maydecrease >= 0 && consdata->lincoefs[consdata->linvar_maydecrease] < 0.0) )
13763  maypropfeasible = FALSE;
13764  }
13765  else
13766  {
13767  assert(SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)));
13768  /* check if there is a variable which may help to get the right hand side satisfied
13769  * if there is no such var, then we cannot get feasible */
13770  if( !(consdata->linvar_mayincrease >= 0 && consdata->lincoefs[consdata->linvar_mayincrease] < 0.0) &&
13771  ! (consdata->linvar_maydecrease >= 0 && consdata->lincoefs[consdata->linvar_maydecrease] > 0.0) )
13772  maypropfeasible = FALSE;
13773  }
13774  }
13775  }
13776  }
13777 
13778  if( *result == SCIP_INFEASIBLE && maypropfeasible )
13779  {
13780  SCIP_Bool success;
13781 
13782  SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
13783 
13784  /* do not pass solution to NLP heuristic if we made it feasible this way */
13785  if( success )
13786  return SCIP_OKAY;
13787  }
13788 
13789  if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL && !SCIPisInfinity(scip, maxviol) )
13790  {
13791  SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
13792  }
13793 
13794  return SCIP_OKAY;
13795 }
13796 
13797 /** constraint copying method of constraint handler */
13798 static
13799 SCIP_DECL_CONSCOPY(consCopyQuadratic)
13801  SCIP_CONSDATA* consdata;
13802  SCIP_CONSDATA* targetconsdata;
13803  SCIP_VAR** linvars;
13804  SCIP_QUADVARTERM* quadvarterms;
13805  SCIP_BILINTERM* bilinterms;
13806  int i;
13807  int j;
13808  int k;
13809 
13810  assert(scip != NULL);
13811  assert(cons != NULL);
13812  assert(sourcescip != NULL);
13813  assert(sourceconshdlr != NULL);
13814  assert(sourcecons != NULL);
13815  assert(varmap != NULL);
13816  assert(valid != NULL);
13817 
13818  consdata = SCIPconsGetData(sourcecons);
13819  assert(consdata != NULL);
13820 
13821  linvars = NULL;
13822  quadvarterms = NULL;
13823  bilinterms = NULL;
13824 
13825  *valid = TRUE;
13826 
13827  if( consdata->nlinvars != 0 )
13828  {
13829  SCIP_CALL( SCIPallocBufferArray(sourcescip, &linvars, consdata->nlinvars) );
13830  for( i = 0; i < consdata->nlinvars; ++i )
13831  {
13832  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, consdata->linvars[i], &linvars[i], varmap, consmap, global, valid) );
13833  assert(!(*valid) || linvars[i] != NULL);
13834 
13835  /* we do not copy, if a variable is missing */
13836  if( !(*valid) )
13837  goto TERMINATE;
13838  }
13839  }
13840 
13841  if( consdata->nbilinterms != 0 )
13842  {
13843  SCIP_CALL( SCIPallocBufferArray(sourcescip, &bilinterms, consdata->nbilinterms) );
13844  }
13845 
13846  if( consdata->nquadvars != 0 )
13847  {
13848  SCIP_CALL( SCIPallocBufferArray(sourcescip, &quadvarterms, consdata->nquadvars) );
13849  for( i = 0; i < consdata->nquadvars; ++i )
13850  {
13851  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, consdata->quadvarterms[i].var, &quadvarterms[i].var, varmap, consmap, global, valid) );
13852  assert(!(*valid) || quadvarterms[i].var != NULL);
13853 
13854  /* we do not copy, if a variable is missing */
13855  if( !(*valid) )
13856  goto TERMINATE;
13857 
13858  quadvarterms[i].lincoef = consdata->quadvarterms[i].lincoef;
13859  quadvarterms[i].sqrcoef = consdata->quadvarterms[i].sqrcoef;
13860  quadvarterms[i].eventdata = NULL;
13861  quadvarterms[i].nadjbilin = consdata->quadvarterms[i].nadjbilin;
13862  quadvarterms[i].adjbilin = consdata->quadvarterms[i].adjbilin;
13863 
13864  assert(consdata->nbilinterms != 0 || consdata->quadvarterms[i].nadjbilin == 0);
13865 
13866  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
13867  {
13868  assert(bilinterms != NULL);
13869 
13870  k = consdata->quadvarterms[i].adjbilin[j];
13871  assert(consdata->bilinterms[k].var1 != NULL);
13872  assert(consdata->bilinterms[k].var2 != NULL);
13873  if( consdata->bilinterms[k].var1 == consdata->quadvarterms[i].var )
13874  {
13875  assert(consdata->bilinterms[k].var2 != consdata->quadvarterms[i].var);
13876  bilinterms[k].var1 = quadvarterms[i].var;
13877  }
13878  else
13879  {
13880  assert(consdata->bilinterms[k].var2 == consdata->quadvarterms[i].var);
13881  bilinterms[k].var2 = quadvarterms[i].var;
13882  }
13883  bilinterms[k].coef = consdata->bilinterms[k].coef;
13884  }
13885  }
13886  }
13887 
13888  assert(stickingatnode == FALSE);
13889  SCIP_CALL( SCIPcreateConsQuadratic2(scip, cons, name ? name : SCIPconsGetName(sourcecons),
13890  consdata->nlinvars, linvars, consdata->lincoefs,
13891  consdata->nquadvars, quadvarterms,
13892  consdata->nbilinterms, bilinterms,
13893  consdata->lhs, consdata->rhs,
13894  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
13895 
13896  /* copy information on curvature */
13897  targetconsdata = SCIPconsGetData(*cons);
13898  targetconsdata->isconvex = consdata->isconvex;
13899  targetconsdata->isconcave = consdata->isconcave;
13900  targetconsdata->iscurvchecked = consdata->iscurvchecked;
13901 
13902  TERMINATE:
13903  SCIPfreeBufferArrayNull(sourcescip, &quadvarterms);
13904  SCIPfreeBufferArrayNull(sourcescip, &bilinterms);
13905  SCIPfreeBufferArrayNull(sourcescip, &linvars);
13906 
13907  return SCIP_OKAY;
13908 }
13909 
13910 /** constraint parsing method of constraint handler */
13911 static
13912 SCIP_DECL_CONSPARSE(consParseQuadratic)
13913 { /*lint --e{715}*/
13914  SCIP_VAR*** monomialvars;
13915  SCIP_Real** monomialexps;
13916  SCIP_Real* monomialcoefs;
13917  char* endptr;
13918  int* monomialnvars;
13919  int nmonomials;
13920 
13921  SCIP_Real lhs;
13922  SCIP_Real rhs;
13923 
13924  assert(scip != NULL);
13925  assert(success != NULL);
13926  assert(str != NULL);
13927  assert(name != NULL);
13928  assert(cons != NULL);
13929 
13930  /* set left and right hand side to their default values */
13931  lhs = -SCIPinfinity(scip);
13932  rhs = SCIPinfinity(scip);
13933 
13934  (*success) = FALSE;
13935 
13936  /* return of string empty */
13937  if( !*str )
13938  return SCIP_OKAY;
13939 
13940  /* ignore whitespace */
13941  while( isspace((unsigned char)*str) )
13942  ++str;
13943 
13944  /* check for left hand side */
13945  if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
13946  {
13947  /* there is a number coming, maybe it is a left-hand-side */
13948  if( !SCIPstrToRealValue(str, &lhs, &endptr) )
13949  {
13950  SCIPerrorMessage("error parsing number from <%s>\n", str);
13951  return SCIP_OKAY;
13952  }
13953 
13954  /* ignore whitespace */
13955  while( isspace((unsigned char)*endptr) )
13956  ++endptr;
13957 
13958  if( endptr[0] != '<' || endptr[1] != '=' )
13959  {
13960  /* no '<=' coming, so it was the first coefficient, but not a left-hand-side */
13961  lhs = -SCIPinfinity(scip);
13962  }
13963  else
13964  {
13965  /* it was indeed a left-hand-side, so continue parsing after it */
13966  str = endptr + 2;
13967 
13968  /* ignore whitespace */
13969  while( isspace((unsigned char)*str) )
13970  ++str;
13971  }
13972  }
13973 
13974  SCIP_CALL( SCIPparseVarsPolynomial(scip, str, &monomialvars, &monomialexps, &monomialcoefs, &monomialnvars, &nmonomials, &endptr, success) );
13975 
13976  if( *success )
13977  {
13978  /* check for right hand side */
13979  str = endptr;
13980 
13981  /* ignore whitespace */
13982  while( isspace((unsigned char)*str) )
13983  ++str;
13984 
13985  if( *str && str[0] == '<' && str[1] == '=' )
13986  {
13987  /* we seem to get a right-hand-side */
13988  str += 2;
13989 
13990  if( !SCIPstrToRealValue(str, &rhs, &endptr) )
13991  {
13992  SCIPerrorMessage("error parsing right-hand-side from %s\n", str);
13993  *success = FALSE;
13994  }
13995  }
13996  else if( *str && str[0] == '>' && str[1] == '=' )
13997  {
13998  /* we seem to get a left-hand-side */
13999  str += 2;
14000 
14001  /* we should not have a left-hand-side already */
14002  assert(SCIPisInfinity(scip, -lhs));
14003 
14004  if( !SCIPstrToRealValue(str, &lhs, &endptr) )
14005  {
14006  SCIPerrorMessage("error parsing left-hand-side from %s\n", str);
14007  *success = FALSE;
14008  }
14009  }
14010  else if( *str && str[0] == '=' && str[1] == '=' )
14011  {
14012  /* we seem to get a left- and right-hand-side */
14013  str += 2;
14014 
14015  /* we should not have a left-hand-side already */
14016  assert(SCIPisInfinity(scip, -lhs));
14017 
14018  if( !SCIPstrToRealValue(str, &lhs, &endptr) )
14019  {
14020  SCIPerrorMessage("error parsing left-hand-side from %s\n", str);
14021  *success = FALSE;
14022  }
14023  else
14024  {
14025  rhs = lhs;
14026  }
14027  }
14028  }
14029 
14030  if( *success )
14031  {
14032  int i;
14033 
14034  /* setup constraint */
14035  assert(stickingatnode == FALSE);
14036  SCIP_CALL( SCIPcreateConsQuadratic(scip, cons, name, 0, NULL, NULL,
14037  0, NULL, NULL, NULL, lhs, rhs,
14038  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
14039 
14040  for( i = 0; i < nmonomials; ++i )
14041  {
14042  if( monomialnvars[i] == 0 )
14043  {
14044  /* constant monomial */
14045  SCIPaddConstantQuadratic(scip, *cons, monomialcoefs[i]);
14046  }
14047  else if( monomialnvars[i] == 1 && monomialexps[i][0] == 1.0 )
14048  {
14049  /* linear monomial */
14050  SCIP_CALL( SCIPaddLinearVarQuadratic(scip, *cons, monomialvars[i][0], monomialcoefs[i]) );
14051  }
14052  else if( monomialnvars[i] == 1 && monomialexps[i][0] == 2.0 )
14053  {
14054  /* square monomial */
14055  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, monomialvars[i][0], 0.0, monomialcoefs[i]) );
14056  }
14057  else if( monomialnvars[i] == 2 && monomialexps[i][0] == 1.0 && monomialexps[i][1] == 1.0 )
14058  {
14059  /* bilinear term */
14060  SCIP_VAR* var1;
14061  SCIP_VAR* var2;
14062  int pos;
14063 
14064  var1 = monomialvars[i][0];
14065  var2 = monomialvars[i][1];
14066  if( var1 == var2 )
14067  {
14068  /* actually a square term */
14069  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, var1, 0.0, monomialcoefs[i]) );
14070  }
14071  else
14072  {
14073  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, *cons, var1, &pos) );
14074  if( pos == -1 )
14075  {
14076  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, var1, 0.0, 0.0) );
14077  }
14078 
14079  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, *cons, var2, &pos) );
14080  if( pos == -1 )
14081  {
14082  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, var2, 0.0, 0.0) );
14083  }
14084  }
14085 
14086  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, *cons, var1, var2, monomialcoefs[i]) );
14087  }
14088  else
14089  {
14090  SCIPerrorMessage("polynomial in quadratic constraint does not have degree at most 2\n");
14091  *success = FALSE;
14092  SCIP_CALL( SCIPreleaseCons(scip, cons) );
14093  break;
14094  }
14095  }
14096  }
14097 
14098  SCIPfreeParseVarsPolynomialData(scip, &monomialvars, &monomialexps, &monomialcoefs, &monomialnvars, nmonomials);
14099 
14100  return SCIP_OKAY;
14101 }
14102 
14103 /** constraint method of constraint handler which returns the variables (if possible) */
14104 static
14105 SCIP_DECL_CONSGETVARS(consGetVarsQuadratic)
14106 { /*lint --e{715}*/
14107  SCIP_CONSDATA* consdata;
14108 
14109  assert(cons != NULL);
14110  assert(success != NULL);
14111 
14112  consdata = SCIPconsGetData(cons);
14113  assert(consdata != NULL);
14114 
14115  if( varssize < consdata->nlinvars + consdata->nquadvars )
14116  (*success) = FALSE;
14117  else
14118  {
14119  int i;
14120 
14121  assert(vars != NULL);
14122 
14123  BMScopyMemoryArray(vars, consdata->linvars, consdata->nlinvars);
14124 
14125  for( i = 0; i < consdata->nquadvars; ++i )
14126  vars[consdata->nlinvars+i] = consdata->quadvarterms[i].var;
14127 
14128  (*success) = TRUE;
14129  }
14130 
14131  return SCIP_OKAY;
14132 }
14133 
14134 /** constraint method of constraint handler which returns the number of variables (if possible) */
14135 static
14136 SCIP_DECL_CONSGETNVARS(consGetNVarsQuadratic)
14137 { /*lint --e{715}*/
14138  SCIP_CONSDATA* consdata;
14139 
14140  assert(cons != NULL);
14141  assert(success != NULL);
14142 
14143  consdata = SCIPconsGetData(cons);
14144  assert(consdata != NULL);
14145 
14146  (*nvars) = consdata->nlinvars + consdata->nquadvars;
14147  (*success) = TRUE;
14148 
14149  return SCIP_OKAY;
14150 }
14151 
14152 
14153 /*
14154  * constraint specific interface methods
14155  */
14156 
14157 /** creates the handler for quadratic constraints and includes it in SCIP */
14159  SCIP* scip /**< SCIP data structure */
14160  )
14161 {
14162  SCIP_CONSHDLRDATA* conshdlrdata;
14163  SCIP_CONSHDLR* conshdlr;
14164 
14165  /* create quadratic constraint handler data */
14166  SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
14167  BMSclearMemory(conshdlrdata);
14168 
14169  /* include constraint handler */
14172  consEnfolpQuadratic, consEnfopsQuadratic, consCheckQuadratic, consLockQuadratic,
14173  conshdlrdata) );
14174  assert(conshdlr != NULL);
14175 
14176  /* set non-fundamental callbacks via specific setter functions */
14177  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyQuadratic, consCopyQuadratic) );
14178  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteQuadratic) );
14179  SCIP_CALL( SCIPsetConshdlrDisable(scip, conshdlr, consDisableQuadratic) );
14180  SCIP_CALL( SCIPsetConshdlrEnable(scip, conshdlr, consEnableQuadratic) );
14181  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitQuadratic) );
14182  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreQuadratic) );
14183  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolQuadratic) );
14184  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeQuadratic) );
14185  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsQuadratic) );
14186  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsQuadratic) );
14187  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitQuadratic) );
14188  SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolQuadratic) );
14189  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpQuadratic) );
14190  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseQuadratic) );
14191  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolQuadratic, CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
14192  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintQuadratic) );
14193  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropQuadratic, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
14195  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpQuadratic, consSepasolQuadratic, CONSHDLR_SEPAFREQ,
14197  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransQuadratic) );
14198  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxQuadratic) );
14199 
14200  /* add quadratic constraint handler parameters */
14201  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/replacebinaryprod",
14202  "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)",
14203  &conshdlrdata->replacebinaryprodlength, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
14204 
14205  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/empathy4and",
14206  "empathy level for using the AND constraint handler: 0 always avoid using AND; 1 use AND sometimes; 2 use AND as often as possible",
14207  &conshdlrdata->empathy4and, FALSE, 2, 0, 2, NULL, NULL) );
14208 
14209  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/binreforminitial",
14210  "whether to make non-varbound linear constraints added due to replacing products with binary variables initial",
14211  &conshdlrdata->binreforminitial, TRUE, FALSE, NULL, NULL) );
14212 
14213  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/binreformbinaryonly",
14214  "whether to consider only binary variables when replacing products with binary variables",
14215  &conshdlrdata->binreformbinaryonly, FALSE, TRUE, NULL, NULL) );
14216 
14217  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/binreformmaxcoef",
14218  "limit (as factor on 1/feastol) on coefficients and coef. range in linear constraints created when replacing products with binary variables",
14219  &conshdlrdata->binreformmaxcoef, TRUE, 1e-4, 0.0, SCIPinfinity(scip), NULL, NULL) );
14220 
14221  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/cutmaxrange",
14222  "maximal coef range of a cut (maximal coefficient divided by minimal coefficient) in order to be added to LP relaxation",
14223  &conshdlrdata->cutmaxrange, TRUE, 1e+7, 0.0, SCIPinfinity(scip), NULL, NULL) );
14224 
14225  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/mincurvcollectbilinterms",
14226  "minimal curvature of constraints to be considered when returning bilinear terms to other plugins",
14227  &conshdlrdata->mincurvcollectbilinterms, TRUE, 0.8, -SCIPinfinity(scip), SCIPinfinity(scip), NULL, NULL) );
14228 
14229  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/linearizeheursol",
14230  "whether linearizations of convex quadratic constraints should be added to cutpool in a solution found by some heuristic",
14231  &conshdlrdata->linearizeheursol, TRUE, TRUE, NULL, NULL) );
14232 
14233  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/checkcurvature",
14234  "whether multivariate quadratic functions should be checked for convexity/concavity",
14235  &conshdlrdata->checkcurvature, FALSE, TRUE, NULL, NULL) );
14236 
14237  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/checkfactorable",
14238  "whether constraint functions should be checked to be factorable",
14239  &conshdlrdata->checkfactorable, TRUE, TRUE, NULL, NULL) );
14240 
14241  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/checkquadvarlocks",
14242  "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)",
14243  &conshdlrdata->checkquadvarlocks, TRUE, 't', "bdt", NULL, NULL) );
14244 
14245  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/linfeasshift",
14246  "whether to try to make solutions in check function feasible by shifting a linear variable (esp. useful if constraint was actually objective function)",
14247  &conshdlrdata->linfeasshift, TRUE, TRUE, NULL, NULL) );
14248 
14249  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxdisaggrsize",
14250  "maximum number of created constraints when disaggregating a quadratic constraint (<= 1: off)",
14251  &conshdlrdata->maxdisaggrsize, FALSE, 1, 1, INT_MAX, NULL, NULL) );
14252 
14253  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/disaggrmergemethod",
14254  "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)",
14255  &conshdlrdata->disaggrmergemethod, TRUE, 'm', "bms", NULL, NULL) );
14256 
14257  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
14258  "limit on number of propagation rounds for a single constraint within one round of SCIP propagation during solve",
14259  &conshdlrdata->maxproprounds, TRUE, 1, 0, INT_MAX, NULL, NULL) );
14260 
14261  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproproundspresolve",
14262  "limit on number of propagation rounds for a single constraint within one round of SCIP presolve",
14263  &conshdlrdata->maxproproundspresolve, TRUE, 10, 0, INT_MAX, NULL, NULL) );
14264 
14265  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/enfolplimit",
14266  "maximum number of enforcement rounds before declaring the LP relaxation infeasible (-1: no limit); WARNING: changing this parameter might lead to incorrect results!",
14267  &conshdlrdata->enfolplimit, TRUE, -1, -1, INT_MAX, NULL, NULL) );
14268 
14269  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/sepanlpmincont",
14270  "minimal required fraction of continuous variables in problem to use solution of NLP relaxation in root for separation",
14271  &conshdlrdata->sepanlpmincont, FALSE, 1.0, 0.0, 2.0, NULL, NULL) );
14272 
14273  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/enfocutsremovable",
14274  "are cuts added during enforcement removable from the LP in the same node?",
14275  &conshdlrdata->enfocutsremovable, TRUE, FALSE, NULL, NULL) );
14276 
14277  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/gaugecuts",
14278  "should convex quadratics generated strong cuts via gauge function?",
14279  &conshdlrdata->gaugecuts, FALSE, FALSE, NULL, NULL) );
14280 
14281  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/interiorcomputation",
14282  "how the interior point for gauge cuts should be computed: 'a'ny point per constraint, 'm'ost interior per constraint",
14283  &conshdlrdata->interiorcomputation, TRUE, 'a', "am", NULL, NULL) );
14284 
14285  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/projectedcuts",
14286  "should convex quadratics generated strong cuts via projections?",
14287  &conshdlrdata->projectedcuts, FALSE, FALSE, NULL, NULL) );
14288 
14289  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branchscoring",
14290  "which score to give branching candidates: convexification 'g'ap, constraint 'v'iolation, 'c'entrality of variable value in domain",
14291  &conshdlrdata->branchscoring, TRUE, 'g', "cgv", NULL, NULL) );
14292 
14293  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/usebilinineqbranch",
14294  "should linear inequalities be consindered when computing the branching scores for bilinear terms?",
14295  &conshdlrdata->usebilinineqbranch, FALSE, FALSE, NULL, NULL) );
14296 
14297  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/minscorebilinterms",
14298  "minimal required score in order to use linear inequalities for tighter bilinear relaxations",
14299  &conshdlrdata->minscorebilinterms, FALSE, 0.01, 0.0, 1.0, NULL, NULL) );
14300 
14301  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/bilinineqmaxseparounds",
14302  "maximum number of separation rounds to use linear inequalities for the bilinear term relaxation in a local node",
14303  &conshdlrdata->bilinineqmaxseparounds, TRUE, 3, 0, INT_MAX, NULL, NULL) );
14304 
14305  conshdlrdata->eventhdlr = NULL;
14306  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlr),CONSHDLR_NAME"_boundchange", "signals a bound change to a quadratic constraint",
14307  processVarEvent, NULL) );
14308  assert(conshdlrdata->eventhdlr != NULL);
14309 
14310  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME"_newsolution", "handles the event that a new primal solution has been found",
14311  processNewSolutionEvent, NULL) );
14312 
14313  /* include the quadratic constraint upgrade in the nonlinear constraint handler */
14315 
14316  return SCIP_OKAY;
14317 }
14318 
14319 /** includes a quadratic constraint update method into the quadratic constraint handler */
14321  SCIP* scip, /**< SCIP data structure */
14322  SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), /**< method to call for upgrading quadratic constraint */
14323  int priority, /**< priority of upgrading method */
14324  SCIP_Bool active, /**< should the upgrading method be active by default? */
14325  const char* conshdlrname /**< name of the constraint handler */
14326  )
14327 {
14328  SCIP_CONSHDLR* conshdlr;
14329  SCIP_CONSHDLRDATA* conshdlrdata;
14330  SCIP_QUADCONSUPGRADE* quadconsupgrade;
14331  char paramname[SCIP_MAXSTRLEN];
14332  char paramdesc[SCIP_MAXSTRLEN];
14333  int i;
14334 
14335  assert(quadconsupgd != NULL);
14336  assert(conshdlrname != NULL );
14337 
14338  /* find the quadratic constraint handler */
14339  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14340  if( conshdlr == NULL )
14341  {
14342  SCIPerrorMessage("quadratic constraint handler not found\n");
14343  return SCIP_PLUGINNOTFOUND;
14344  }
14345 
14346  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14347  assert(conshdlrdata != NULL);
14348 
14349  if( !conshdlrdataHasUpgrade(scip, conshdlrdata, quadconsupgd, conshdlrname) )
14350  {
14351  /* create a quadratic constraint upgrade data object */
14352  SCIP_CALL( SCIPallocBlockMemory(scip, &quadconsupgrade) );
14353  quadconsupgrade->quadconsupgd = quadconsupgd;
14354  quadconsupgrade->priority = priority;
14355  quadconsupgrade->active = active;
14356 
14357  /* insert quadratic constraint upgrade method into constraint handler data */
14358  assert(conshdlrdata->nquadconsupgrades <= conshdlrdata->quadconsupgradessize);
14359  if( conshdlrdata->nquadconsupgrades+1 > conshdlrdata->quadconsupgradessize )
14360  {
14361  int newsize;
14362 
14363  newsize = SCIPcalcMemGrowSize(scip, conshdlrdata->nquadconsupgrades+1);
14364  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->quadconsupgrades, conshdlrdata->quadconsupgradessize, newsize) );
14365  conshdlrdata->quadconsupgradessize = newsize;
14366  }
14367  assert(conshdlrdata->nquadconsupgrades+1 <= conshdlrdata->quadconsupgradessize);
14368 
14369  for( i = conshdlrdata->nquadconsupgrades; i > 0 && conshdlrdata->quadconsupgrades[i-1]->priority < quadconsupgrade->priority; --i )
14370  conshdlrdata->quadconsupgrades[i] = conshdlrdata->quadconsupgrades[i-1];
14371  assert(0 <= i && i <= conshdlrdata->nquadconsupgrades);
14372  conshdlrdata->quadconsupgrades[i] = quadconsupgrade;
14373  conshdlrdata->nquadconsupgrades++;
14374 
14375  /* adds parameter to turn on and off the upgrading step */
14376  (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
14377  (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable quadratic upgrading for constraint handler <%s>", conshdlrname);
14379  paramname, paramdesc,
14380  &quadconsupgrade->active, FALSE, active, NULL, NULL) );
14381  }
14382 
14383  return SCIP_OKAY;
14384 }
14385 
14386 /** Creates and captures a quadratic constraint.
14387  *
14388  * The constraint should be given in the form
14389  * \f[
14390  * \ell \leq \sum_{i=1}^n b_i x_i + \sum_{j=1}^m a_j y_j z_j \leq u,
14391  * \f]
14392  * where \f$x_i = y_j = z_k\f$ is possible.
14393  *
14394  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
14395  */
14397  SCIP* scip, /**< SCIP data structure */
14398  SCIP_CONS** cons, /**< pointer to hold the created constraint */
14399  const char* name, /**< name of constraint */
14400  int nlinvars, /**< number of linear terms (n) */
14401  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
14402  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
14403  int nquadterms, /**< number of quadratic terms (m) */
14404  SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms (y_j) */
14405  SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms (z_j) */
14406  SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms (a_j) */
14407  SCIP_Real lhs, /**< left hand side of quadratic equation (ell) */
14408  SCIP_Real rhs, /**< right hand side of quadratic equation (u) */
14409  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
14410  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
14411  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
14412  * Usually set to TRUE. */
14413  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
14414  * TRUE for model constraints, FALSE for additional, redundant constraints. */
14415  SCIP_Bool check, /**< should the constraint be checked for feasibility?
14416  * TRUE for model constraints, FALSE for additional, redundant constraints. */
14417  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
14418  * Usually set to TRUE. */
14419  SCIP_Bool local, /**< is constraint only valid locally?
14420  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
14421  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
14422  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
14423  * adds coefficients to this constraint. */
14424  SCIP_Bool dynamic, /**< is constraint subject to aging?
14425  * Usually set to FALSE. Set to TRUE for own cuts which
14426  * are separated as constraints. */
14427  SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
14428  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
14429  )
14430 {
14431  SCIP_CONSHDLR* conshdlr;
14432  SCIP_CONSDATA* consdata;
14433  SCIP_HASHMAP* quadvaridxs;
14434  SCIP_Real sqrcoef;
14435  int i;
14436  int var1pos;
14437  int var2pos;
14438 
14439  int nbilinterms;
14440 
14441  assert(linvars != NULL || nlinvars == 0);
14442  assert(lincoefs != NULL || nlinvars == 0);
14443  assert(quadvars1 != NULL || nquadterms == 0);
14444  assert(quadvars2 != NULL || nquadterms == 0);
14445  assert(quadcoefs != NULL || nquadterms == 0);
14446 
14447  assert(modifiable == FALSE); /* we do not support column generation */
14448 
14449  /* find the quadratic constraint handler */
14450  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14451  if( conshdlr == NULL )
14452  {
14453  SCIPerrorMessage("quadratic constraint handler not found\n");
14454  return SCIP_PLUGINNOTFOUND;
14455  }
14456 
14457  /* create constraint data and constraint */
14458  SCIP_CALL( consdataCreateEmpty(scip, &consdata) );
14459 
14460  consdata->lhs = lhs;
14461  consdata->rhs = rhs;
14462 
14463  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
14464  local, modifiable, dynamic, removable, FALSE) );
14465 
14466  /* add quadratic variables and remember their indices */
14467  SCIP_CALL( SCIPhashmapCreate(&quadvaridxs, SCIPblkmem(scip), nquadterms) );
14468  nbilinterms = 0;
14469  for( i = 0; i < nquadterms; ++i )
14470  {
14471  if( SCIPisZero(scip, quadcoefs[i]) ) /*lint !e613*/
14472  continue;
14473 
14474  /* if it is actually a square term, remember it's coefficient */
14475  /* cppcheck-suppress nullPointer */
14476  if( quadvars1[i] == quadvars2[i] ) /*lint !e613*/
14477  sqrcoef = quadcoefs[i]; /*lint !e613 */
14478  else
14479  sqrcoef = 0.0;
14480 
14481  /* add quadvars1[i], if not in there already */
14482  if( !SCIPhashmapExists(quadvaridxs, quadvars1[i]) ) /*lint !e613*/
14483  {
14484  SCIP_CALL( addQuadVarTerm(scip, *cons, quadvars1[i], 0.0, sqrcoef) ); /*lint !e613*/
14485  assert(consdata->nquadvars >= 0);
14486  assert(consdata->quadvarterms[consdata->nquadvars-1].var == quadvars1[i]); /*lint !e613*/
14487 
14488  SCIP_CALL( SCIPhashmapInsertInt(quadvaridxs, quadvars1[i], consdata->nquadvars-1) ); /*lint !e613*/
14489  }
14490  else if( !SCIPisZero(scip, sqrcoef) )
14491  {
14492  /* if it's there already, but we got a square coefficient, add it to the previous one */
14493  var1pos = SCIPhashmapGetImageInt(quadvaridxs, quadvars1[i]); /*lint !e613*/
14494  assert(consdata->quadvarterms[var1pos].var == quadvars1[i]); /*lint !e613*/
14495  consdata->quadvarterms[var1pos].sqrcoef += sqrcoef;
14496  }
14497 
14498  /* cppcheck-suppress nullPointer */
14499  if( quadvars1[i] == quadvars2[i] ) /*lint !e613*/
14500  continue;
14501 
14502  /* add quadvars2[i], if not in there already */
14503  if( !SCIPhashmapExists(quadvaridxs, quadvars2[i]) ) /*lint !e613*/
14504  {
14505  assert(sqrcoef == 0.0);
14506  SCIP_CALL( addQuadVarTerm(scip, *cons, quadvars2[i], 0.0, 0.0) ); /*lint !e613*/
14507  assert(consdata->nquadvars >= 0);
14508  assert(consdata->quadvarterms[consdata->nquadvars-1].var == quadvars2[i]); /*lint !e613*/
14509 
14510  SCIP_CALL( SCIPhashmapInsertInt(quadvaridxs, quadvars2[i], consdata->nquadvars-1) ); /*lint !e613*/
14511  }
14512 
14513  ++nbilinterms;
14514  }
14515 
14516  /* add bilinear terms, if we saw any */
14517  if( nbilinterms > 0 )
14518  {
14519  SCIP_CALL( consdataEnsureBilinSize(scip, consdata, nbilinterms) );
14520  for( i = 0; i < nquadterms; ++i )
14521  {
14522  if( SCIPisZero(scip, quadcoefs[i]) ) /*lint !e613*/
14523  continue;
14524 
14525  /* square terms have been taken care of already */
14526  if( quadvars1[i] == quadvars2[i] ) /*lint !e613 */
14527  continue;
14528 
14529  assert(SCIPhashmapExists(quadvaridxs, quadvars1[i])); /*lint !e613*/
14530  assert(SCIPhashmapExists(quadvaridxs, quadvars2[i])); /*lint !e613*/
14531 
14532  var1pos = SCIPhashmapGetImageInt(quadvaridxs, quadvars1[i]); /*lint !e613*/
14533  var2pos = SCIPhashmapGetImageInt(quadvaridxs, quadvars2[i]); /*lint !e613*/
14534 
14535  SCIP_CALL( addBilinearTerm(scip, *cons, var1pos, var2pos, quadcoefs[i]) ); /*lint !e613*/
14536  }
14537  }
14538 
14539  /* add linear variables */
14540  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, nlinvars) );
14541  for( i = 0; i < nlinvars; ++i )
14542  {
14543  if( SCIPisZero(scip, lincoefs[i]) ) /*lint !e613*/
14544  continue;
14545 
14546  /* if it's a linear coefficient for a quadratic variable, add it there, otherwise add as linear variable */
14547  if( SCIPhashmapExists(quadvaridxs, linvars[i]) ) /*lint !e613*/
14548  {
14549  var1pos = SCIPhashmapGetImageInt(quadvaridxs, linvars[i]); /*lint !e613*/
14550  assert(consdata->quadvarterms[var1pos].var == linvars[i]); /*lint !e613*/
14551  consdata->quadvarterms[var1pos].lincoef += lincoefs[i]; /*lint !e613*/
14552  }
14553  else
14554  {
14555  SCIP_CALL( addLinearCoef(scip, *cons, linvars[i], lincoefs[i]) ); /*lint !e613*/
14556  }
14557  }
14558 
14559  SCIPhashmapFree(&quadvaridxs);
14560 
14561  SCIPdebugMsg(scip, "created quadratic constraint ");
14562  SCIPdebugPrintCons(scip, *cons, NULL);
14563 
14564  return SCIP_OKAY;
14565 }
14566 
14567 /** creates and captures a quadratic constraint with all its
14568  * flags set to their default values.
14569  *
14570  * The constraint should be given in the form
14571  * \f[
14572  * \ell \leq \sum_{i=1}^n b_i x_i + \sum_{j=1}^m a_j y_j z_j \leq u,
14573  * \f]
14574  * where \f$x_i = y_j = z_k\f$ is possible.
14575  *
14576  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
14577  */
14579  SCIP* scip, /**< SCIP data structure */
14580  SCIP_CONS** cons, /**< pointer to hold the created constraint */
14581  const char* name, /**< name of constraint */
14582  int nlinvars, /**< number of linear terms (n) */
14583  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
14584  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
14585  int nquadterms, /**< number of quadratic terms (m) */
14586  SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms (y_j) */
14587  SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms (z_j) */
14588  SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms (a_j) */
14589  SCIP_Real lhs, /**< left hand side of quadratic equation (ell) */
14590  SCIP_Real rhs /**< right hand side of quadratic equation (u) */
14591  )
14592 {
14593  SCIP_CALL( SCIPcreateConsQuadratic(scip, cons, name, nlinvars, linvars, lincoefs,
14594  nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
14595  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
14596 
14597  return SCIP_OKAY;
14598 }
14599 
14600 /** Creates and captures a quadratic constraint.
14601  *
14602  * The constraint should be given in the form
14603  * \f[
14604  * \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.
14605  * \f]
14606  *
14607  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
14608  */
14610  SCIP* scip, /**< SCIP data structure */
14611  SCIP_CONS** cons, /**< pointer to hold the created constraint */
14612  const char* name, /**< name of constraint */
14613  int nlinvars, /**< number of linear terms (n) */
14614  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
14615  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
14616  int nquadvarterms, /**< number of quadratic terms (m) */
14617  SCIP_QUADVARTERM* quadvarterms, /**< quadratic variable terms */
14618  int nbilinterms, /**< number of bilinear terms (p) */
14619  SCIP_BILINTERM* bilinterms, /**< bilinear terms */
14620  SCIP_Real lhs, /**< constraint left hand side (ell) */
14621  SCIP_Real rhs, /**< constraint right hand side (u) */
14622  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? */
14623  SCIP_Bool separate, /**< should the constraint be separated during LP processing? */
14624  SCIP_Bool enforce, /**< should the constraint be enforced during node processing? */
14625  SCIP_Bool check, /**< should the constraint be checked for feasibility? */
14626  SCIP_Bool propagate, /**< should the constraint be propagated during node processing? */
14627  SCIP_Bool local, /**< is constraint only valid locally? */
14628  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)? */
14629  SCIP_Bool dynamic, /**< is constraint dynamic? */
14630  SCIP_Bool removable /**< should the constraint be removed from the LP due to aging or cleanup? */
14631  )
14632 {
14633  SCIP_CONSHDLR* conshdlr;
14634  SCIP_CONSDATA* consdata;
14635 
14636  assert(modifiable == FALSE); /* we do not support column generation */
14637  assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
14638  assert(nquadvarterms == 0 || quadvarterms != NULL);
14639  assert(nbilinterms == 0 || bilinterms != NULL);
14640 
14641  /* find the quadratic constraint handler */
14642  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14643  if( conshdlr == NULL )
14644  {
14645  SCIPerrorMessage("quadratic constraint handler not found\n");
14646  return SCIP_PLUGINNOTFOUND;
14647  }
14648 
14649  /* create constraint data */
14650  SCIP_CALL( consdataCreate(scip, &consdata, lhs, rhs,
14651  nlinvars, linvars, lincoefs, nquadvarterms, quadvarterms, nbilinterms, bilinterms,
14652  TRUE) );
14653 
14654  /* create constraint */
14655  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
14656  local, modifiable, dynamic, removable, FALSE) );
14657 
14658  return SCIP_OKAY;
14659 }
14660 
14661 /** creates and captures a quadratic constraint in its most basic version, i.e.,
14662  * all constraint flags are set to their default values.
14663  *
14664  * The constraint should be given in the form
14665  * \f[
14666  * \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.
14667  * \f]
14668  *
14669  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
14670  */
14672  SCIP* scip, /**< SCIP data structure */
14673  SCIP_CONS** cons, /**< pointer to hold the created constraint */
14674  const char* name, /**< name of constraint */
14675  int nlinvars, /**< number of linear terms (n) */
14676  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
14677  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
14678  int nquadvarterms, /**< number of quadratic terms (m) */
14679  SCIP_QUADVARTERM* quadvarterms, /**< quadratic variable terms */
14680  int nbilinterms, /**< number of bilinear terms (p) */
14681  SCIP_BILINTERM* bilinterms, /**< bilinear terms */
14682  SCIP_Real lhs, /**< constraint left hand side (ell) */
14683  SCIP_Real rhs /**< constraint right hand side (u) */
14684  )
14685 {
14686  SCIP_CALL( SCIPcreateConsQuadratic2(scip, cons, name, nlinvars, linvars, lincoefs,
14687  nquadvarterms, quadvarterms, nbilinterms, bilinterms, lhs, rhs,
14688  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
14689 
14690  return SCIP_OKAY;
14691 }
14692 
14693 
14694 /** Adds a constant to the constraint function, that is, subtracts a constant from both sides */
14696  SCIP* scip, /**< SCIP data structure */
14697  SCIP_CONS* cons, /**< constraint */
14698  SCIP_Real constant /**< constant to subtract from both sides */
14699  )
14700 {
14701  SCIP_CONSDATA* consdata;
14702 
14703  assert(scip != NULL);
14704  assert(cons != NULL);
14705  assert(!SCIPisInfinity(scip, REALABS(constant)));
14706 
14707  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
14708  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
14709  {
14710  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
14711  SCIPABORT();
14712  }
14713 
14714  consdata = SCIPconsGetData(cons);
14715  assert(consdata != NULL);
14716  assert(consdata->lhs <= consdata->rhs);
14717 
14718  if( !SCIPisInfinity(scip, -consdata->lhs) )
14719  consdata->lhs -= constant;
14720  if( !SCIPisInfinity(scip, consdata->rhs) )
14721  consdata->rhs -= constant;
14722 
14723  if( consdata->lhs > consdata->rhs )
14724  {
14725  assert(SCIPisEQ(scip, consdata->lhs, consdata->rhs));
14726  consdata->lhs = consdata->rhs;
14727  }
14728 }
14729 
14730 /** Adds a linear variable with coefficient to a quadratic constraint. */
14732  SCIP* scip, /**< SCIP data structure */
14733  SCIP_CONS* cons, /**< constraint */
14734  SCIP_VAR* var, /**< variable */
14735  SCIP_Real coef /**< coefficient of variable */
14736  )
14737 {
14738  assert(scip != NULL);
14739  assert(cons != NULL);
14740  assert(var != NULL);
14741  assert(!SCIPisInfinity(scip, REALABS(coef)));
14742 
14743  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
14744  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
14745  {
14746  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
14747  return SCIP_INVALIDCALL;
14748  }
14749 
14750  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
14751 
14752  return SCIP_OKAY;
14753 }
14754 
14755 /** Adds a quadratic variable with linear and square coefficient to a quadratic constraint. */
14757  SCIP* scip, /**< SCIP data structure */
14758  SCIP_CONS* cons, /**< constraint */
14759  SCIP_VAR* var, /**< variable */
14760  SCIP_Real lincoef, /**< linear coefficient of variable */
14761  SCIP_Real sqrcoef /**< square coefficient of variable */
14762  )
14763 {
14764  assert(scip != NULL);
14765  assert(cons != NULL);
14766  assert(var != NULL);
14767  assert(!SCIPisInfinity(scip, REALABS(lincoef)));
14768  assert(!SCIPisInfinity(scip, REALABS(sqrcoef)));
14769 
14770  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
14771  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
14772  {
14773  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
14774  return SCIP_INVALIDCALL;
14775  }
14776 
14777  SCIP_CALL( addQuadVarTerm(scip, cons, var, lincoef, sqrcoef) );
14778 
14779  return SCIP_OKAY;
14780 }
14781 
14782 /** Adds a linear coefficient for a quadratic variable.
14783  *
14784  * Variable will be added with square coefficient 0.0 if not existing yet.
14785  */
14787  SCIP* scip, /**< SCIP data structure */
14788  SCIP_CONS* cons, /**< constraint */
14789  SCIP_VAR* var, /**< variable */
14790  SCIP_Real coef /**< value to add to linear coefficient of variable */
14791  )
14792 {
14793  SCIP_CONSDATA* consdata;
14794  int pos;
14795 
14796  assert(scip != NULL);
14797  assert(cons != NULL);
14798  assert(var != NULL);
14799  assert(!SCIPisInfinity(scip, REALABS(coef)));
14800 
14801  if( SCIPisZero(scip, coef) )
14802  return SCIP_OKAY;
14803 
14804  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
14805  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
14806  {
14807  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
14808  return SCIP_INVALIDCALL;
14809  }
14810 
14811  consdata = SCIPconsGetData(cons);
14812  assert(consdata != NULL);
14813 
14814  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var, &pos) );
14815  if( pos < 0 )
14816  {
14817  SCIP_CALL( addQuadVarTerm(scip, cons, var, coef, 0.0) );
14818  return SCIP_OKAY;
14819  }
14820  assert(pos < consdata->nquadvars);
14821  assert(consdata->quadvarterms[pos].var == var);
14822 
14823  consdata->quadvarterms[pos].lincoef += coef;
14824 
14825  /* update flags and invalid activities */
14826  consdata->ispropagated = FALSE;
14827  consdata->ispresolved = consdata->ispresolved && !SCIPisZero(scip, consdata->quadvarterms[pos].lincoef);
14828 
14829  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
14830  consdata->activity = SCIP_INVALID;
14831 
14832  return SCIP_OKAY;
14833 }
14834 
14835 /** Adds a square coefficient for a quadratic variable.
14836  *
14837  * Variable will be added with linear coefficient 0.0 if not existing yet.
14838  */
14840  SCIP* scip, /**< SCIP data structure */
14841  SCIP_CONS* cons, /**< constraint */
14842  SCIP_VAR* var, /**< variable */
14843  SCIP_Real coef /**< value to add to square coefficient of variable */
14844  )
14845 {
14846  SCIP_CONSDATA* consdata;
14847  int pos;
14848 
14849  assert(scip != NULL);
14850  assert(cons != NULL);
14851  assert(var != NULL);
14852  assert(!SCIPisInfinity(scip, REALABS(coef)));
14853 
14854  if( SCIPisZero(scip, coef) )
14855  return SCIP_OKAY;
14856 
14857  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
14858  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
14859  {
14860  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
14861  return SCIP_INVALIDCALL;
14862  }
14863 
14864  consdata = SCIPconsGetData(cons);
14865  assert(consdata != NULL);
14866 
14867  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var, &pos) );
14868  if( pos < 0 )
14869  {
14870  SCIP_CALL( addQuadVarTerm(scip, cons, var, 0.0, coef) );
14871  return SCIP_OKAY;
14872  }
14873  assert(pos < consdata->nquadvars);
14874  assert(consdata->quadvarterms[pos].var == var);
14875 
14876  consdata->quadvarterms[pos].sqrcoef += coef;
14877 
14878  /* update flags and invalid activities */
14879  consdata->isconvex = FALSE;
14880  consdata->isconcave = FALSE;
14881  consdata->iscurvchecked = FALSE;
14882  consdata->ispropagated = FALSE;
14883  consdata->ispresolved = consdata->ispresolved && !SCIPisZero(scip, consdata->quadvarterms[pos].sqrcoef);
14884 
14885  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
14886  consdata->activity = SCIP_INVALID;
14887 
14888  return SCIP_OKAY;
14889 }
14890 
14891 /** Adds a bilinear term to a quadratic constraint.
14892  *
14893  * Variables will be added with linear and square coefficient 0.0 if not existing yet.
14894  * If variables are equal, only the square coefficient of the variable is updated.
14895  */
14897  SCIP* scip, /**< SCIP data structure */
14898  SCIP_CONS* cons, /**< constraint */
14899  SCIP_VAR* var1, /**< first variable */
14900  SCIP_VAR* var2, /**< second variable */
14901  SCIP_Real coef /**< coefficient of bilinear term */
14902  )
14903 {
14904  SCIP_CONSDATA* consdata;
14905  int var1pos;
14906  int var2pos;
14907 
14908  assert(scip != NULL);
14909  assert(cons != NULL);
14910  assert(var1 != NULL);
14911  assert(var2 != NULL);
14912  assert(!SCIPisInfinity(scip, REALABS(coef)));
14913 
14914  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
14915  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
14916  {
14917  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
14918  return SCIP_INVALIDCALL;
14919  }
14920 
14921  if( var1 == var2 )
14922  {
14923  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, cons, var1, coef) );
14924  return SCIP_OKAY;
14925  }
14926 
14927  consdata = SCIPconsGetData(cons);
14928  assert(consdata != NULL);
14929 
14930  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var1, &var1pos) );
14931  if( var1pos < 0 )
14932  {
14933  SCIP_CALL( addQuadVarTerm(scip, cons, var1, 0.0, 0.0) );
14934  var1pos = consdata->nquadvars-1;
14935  }
14936 
14937  if( !consdata->quadvarssorted )
14938  {
14939  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
14940  /* sorting may change the position of var1 */
14941  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var1, &var1pos) );
14942  assert(var1pos >= 0);
14943  }
14944 
14945  assert(consdata->quadvarssorted);
14946  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var2, &var2pos) );
14947  if( var2pos < 0 )
14948  {
14949  SCIP_CALL( addQuadVarTerm(scip, cons, var2, 0.0, 0.0) );
14950  var2pos = consdata->nquadvars-1;
14951  }
14952 
14953  assert(consdata->quadvarterms[var1pos].var == var1);
14954  assert(consdata->quadvarterms[var2pos].var == var2);
14955 
14956  SCIP_CALL( addBilinearTerm(scip, cons, var1pos, var2pos, coef) );
14957 
14958  return SCIP_OKAY;
14959 }
14960 
14961 /** Gets the quadratic constraint as a nonlinear row representation. */
14963  SCIP* scip, /**< SCIP data structure */
14964  SCIP_CONS* cons, /**< constraint */
14965  SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
14966  )
14967 {
14968  SCIP_CONSDATA* consdata;
14969 
14970  assert(cons != NULL);
14971  assert(nlrow != NULL);
14972 
14973  consdata = SCIPconsGetData(cons);
14974  assert(consdata != NULL);
14975 
14976  if( consdata->nlrow == NULL )
14977  {
14978  SCIP_CALL( createNlRow(scip, cons) );
14979  }
14980  assert(consdata->nlrow != NULL);
14981  *nlrow = consdata->nlrow;
14982 
14983  return SCIP_OKAY;
14984 }
14985 
14986 /** Gets the number of variables in the linear term of a quadratic constraint. */
14988  SCIP* scip, /**< SCIP data structure */
14989  SCIP_CONS* cons /**< constraint */
14990  )
14991 {
14992  assert(scip != NULL);
14993  assert(cons != NULL);
14994  assert(SCIPconsGetData(cons) != NULL);
14995 
14996  return SCIPconsGetData(cons)->nlinvars;
14997 }
14998 
14999 /** Gets the variables in the linear part of a quadratic constraint.
15000  * Length is given by SCIPgetNLinearVarsQuadratic.
15001  */
15003  SCIP* scip, /**< SCIP data structure */
15004  SCIP_CONS* cons /**< constraint */
15005  )
15006 {
15007  assert(scip != NULL);
15008  assert(cons != NULL);
15009  assert(SCIPconsGetData(cons) != NULL);
15010 
15011  return SCIPconsGetData(cons)->linvars;
15012 }
15013 
15014 /** Gets the coefficients in the linear part of a quadratic constraint.
15015  * Length is given by SCIPgetNLinearVarsQuadratic.
15016  */
15018  SCIP* scip, /**< SCIP data structure */
15019  SCIP_CONS* cons /**< constraint */
15020  )
15021 {
15022  assert(scip != NULL);
15023  assert(cons != NULL);
15024  assert(SCIPconsGetData(cons) != NULL);
15025 
15026  return SCIPconsGetData(cons)->lincoefs;
15027 }
15028 
15029 /** Gets the number of quadratic variable terms of a quadratic constraint.
15030  */
15032  SCIP* scip, /**< SCIP data structure */
15033  SCIP_CONS* cons /**< constraint */
15034  )
15035 {
15036  assert(scip != NULL);
15037  assert(cons != NULL);
15038  assert(SCIPconsGetData(cons) != NULL);
15039 
15040  return SCIPconsGetData(cons)->nquadvars;
15041 }
15042 
15043 /** Gets the quadratic variable terms of a quadratic constraint.
15044  * Length is given by SCIPgetNQuadVarTermsQuadratic.
15045  */
15047  SCIP* scip, /**< SCIP data structure */
15048  SCIP_CONS* cons /**< constraint */
15049  )
15050 {
15051  assert(scip != NULL);
15052  assert(cons != NULL);
15053  assert(SCIPconsGetData(cons) != NULL);
15054 
15055  return SCIPconsGetData(cons)->quadvarterms;
15056 }
15057 
15058 /** Ensures that quadratic variable terms are sorted. */
15060  SCIP* scip, /**< SCIP data structure */
15061  SCIP_CONS* cons /**< constraint */
15062  )
15063 {
15064  assert(scip != NULL);
15065  assert(cons != NULL);
15066  assert(SCIPconsGetData(cons) != NULL);
15067 
15069 
15070  return SCIP_OKAY;
15071 }
15072 
15073 /** Finds the position of a quadratic variable term for a given variable.
15074  *
15075  * @note If the quadratic variable terms have not been sorted before, then a search may reorder the current order of the terms.
15076  */
15078  SCIP* scip, /**< SCIP data structure */
15079  SCIP_CONS* cons, /**< constraint */
15080  SCIP_VAR* var, /**< variable to search for */
15081  int* pos /**< buffer to store position of quadvarterm for var, or -1 if not found */
15082  )
15083 {
15084  assert(scip != NULL);
15085  assert(cons != NULL);
15086  assert(SCIPconsGetData(cons) != NULL);
15087  assert(var != NULL);
15088  assert(pos != NULL);
15089 
15090  SCIP_CALL( consdataFindQuadVarTerm(scip, SCIPconsGetData(cons), var, pos) );
15091 
15092  return SCIP_OKAY;
15093 }
15094 
15095 /** Gets the number of bilinear terms of a quadratic constraint. */
15097  SCIP* scip, /**< SCIP data structure */
15098  SCIP_CONS* cons /**< constraint */
15099  )
15100 {
15101  assert(scip != NULL);
15102  assert(cons != NULL);
15103  assert(SCIPconsGetData(cons) != NULL);
15104 
15105  return SCIPconsGetData(cons)->nbilinterms;
15106 }
15107 
15108 /** Gets the bilinear terms of a quadratic constraint.
15109  * Length is given by SCIPgetNBilinTermQuadratic.
15110  */
15112  SCIP* scip, /**< SCIP data structure */
15113  SCIP_CONS* cons /**< constraint */
15114  )
15115 {
15116  assert(scip != NULL);
15117  assert(cons != NULL);
15118  assert(SCIPconsGetData(cons) != NULL);
15119 
15120  return SCIPconsGetData(cons)->bilinterms;
15121 }
15122 
15123 /** Gets the left hand side of a quadratic constraint. */
15125  SCIP* scip, /**< SCIP data structure */
15126  SCIP_CONS* cons /**< constraint */
15127  )
15128 {
15129  assert(scip != NULL);
15130  assert(cons != NULL);
15131  assert(SCIPconsGetData(cons) != NULL);
15132 
15133  return SCIPconsGetData(cons)->lhs;
15134 }
15135 
15136 /** Gets the right hand side of a quadratic constraint. */
15138  SCIP* scip, /**< SCIP data structure */
15139  SCIP_CONS* cons /**< constraint */
15140  )
15141 {
15142  assert(scip != NULL);
15143  assert(cons != NULL);
15144  assert(SCIPconsGetData(cons) != NULL);
15145 
15146  return SCIPconsGetData(cons)->rhs;
15147 }
15148 
15149 /** get index of a variable in linvars that may be decreased without making any other constraint infeasible, or -1 if none */
15151  SCIP* scip, /**< SCIP data structure */
15152  SCIP_CONS* cons /**< constraint */
15153  )
15154 {
15155  SCIP_CONSDATA* consdata;
15156 
15157  assert(scip != NULL);
15158  assert(cons != NULL);
15159 
15160  consdata = SCIPconsGetData(cons);
15161  assert(consdata != NULL);
15162 
15163  /* check for a linear variable that can be increase or decreased without harming feasibility */
15164  consdataFindUnlockedLinearVar(scip, consdata);
15165 
15166  return consdata->linvar_maydecrease;
15167 }
15168 
15169 /** get index of a variable in linvars that may be increased without making any other constraint infeasible, or -1 if none */
15171  SCIP* scip, /**< SCIP data structure */
15172  SCIP_CONS* cons /**< constraint */
15173  )
15174 {
15175  SCIP_CONSDATA* consdata;
15176 
15177  assert(scip != NULL);
15178  assert(cons != NULL);
15179 
15180  consdata = SCIPconsGetData(cons);
15181  assert(consdata != NULL);
15182 
15183  /* check for a linear variable that can be increase or decreased without harming feasibility */
15184  consdataFindUnlockedLinearVar(scip, consdata);
15185 
15186  return consdata->linvar_mayincrease;
15187 }
15188 
15189 /** Check the quadratic function of a quadratic constraint for its semi-definiteness, if not done yet. */
15191  SCIP* scip, /**< SCIP data structure */
15192  SCIP_CONS* cons /**< constraint */
15193  )
15194 {
15195  assert(scip != NULL);
15196  assert(cons != NULL);
15197 
15198  SCIP_CALL( checkCurvature(scip, cons, TRUE) );
15199 
15200  return SCIP_OKAY;
15201 }
15202 
15203 /** Indicates whether the quadratic function of a quadratic constraint is (known to be) convex. */
15205  SCIP* scip, /**< SCIP data structure */
15206  SCIP_CONS* cons /**< constraint */
15207  )
15208 {
15209  SCIP_CONSDATA* consdata;
15210  SCIP_Bool determined;
15211  SCIP_Bool isconvex;
15212  SCIP_Bool isconcave;
15213 
15214  assert(scip != NULL);
15215  assert(cons != NULL);
15216  assert(SCIPconsGetData(cons) != NULL);
15217 
15218  consdata = SCIPconsGetData(cons);
15219  assert(consdata != NULL);
15220 
15221  if( consdata->iscurvchecked )
15222  return consdata->isconvex;
15223 
15224  checkCurvatureEasy(scip, cons, NULL, &determined, TRUE, &isconvex, &isconcave, &consdata->maxnonconvexity);
15225 
15226  if( determined )
15227  {
15228  consdata->isconvex = isconvex;
15229  consdata->isconcave = isconcave;
15230  consdata->iscurvchecked = TRUE;
15231  }
15232 
15233  return isconvex;
15234 }
15235 
15236 /** Indicates whether the quadratic function of a quadratic constraint is (known to be) concave. */
15238  SCIP* scip, /**< SCIP data structure */
15239  SCIP_CONS* cons /**< constraint */
15240  )
15241 {
15242  SCIP_CONSDATA* consdata;
15243  SCIP_Bool determined;
15244  SCIP_Bool isconvex;
15245  SCIP_Bool isconcave;
15246 
15247  assert(scip != NULL);
15248  assert(cons != NULL);
15249  assert(SCIPconsGetData(cons) != NULL);
15250 
15251  consdata = SCIPconsGetData(cons);
15252  assert(consdata != NULL);
15253 
15254  if( consdata->iscurvchecked )
15255  return consdata->isconcave;
15256 
15257  checkCurvatureEasy(scip, cons, NULL, &determined, TRUE, &isconvex, &isconcave, &consdata->maxnonconvexity);
15258 
15259  if( determined )
15260  {
15261  consdata->isconvex = isconvex;
15262  consdata->isconcave = isconcave;
15263  consdata->iscurvchecked = TRUE;
15264  }
15265 
15266  return isconcave;
15267 }
15268 
15269 /** Checks and indicates whether the quadratic constraint is convex. */
15271  SCIP* scip, /**< SCIP data structure */
15272  SCIP_CONS* cons, /**< constraint */
15273  SCIP_HASHMAP* assumevarfixed, /**< hashmap containing variables that should be assumed to be fixed, or NULL */
15274  SCIP_Bool* result /**< buffer where to store whether constraint is convex (under given variable fixing) */
15275  )
15276 {
15277  SCIP_CONSDATA* consdata;
15278  SCIP_Real maxnonconvexity;
15279  SCIP_Bool isconvex;
15280  SCIP_Bool isconcave;
15281  SCIP_Bool determined;
15282 
15283  assert(cons != NULL);
15284  assert(result != NULL);
15285 
15286  consdata = SCIPconsGetData(cons);
15287  assert(consdata != NULL);
15288 
15289  if( consdata->iscurvchecked )
15290  {
15291  /* if already checked and convex (w.r.t. all vars), then will also be convex after fixing some vars */
15292  if( consdata->isconvex && SCIPisInfinity(scip, -consdata->lhs) )
15293  {
15294  *result = TRUE;
15295  return SCIP_OKAY;
15296  }
15297  if( consdata->isconcave && SCIPisInfinity(scip, consdata->rhs) )
15298  {
15299  *result = TRUE;
15300  return SCIP_OKAY;
15301  }
15302 
15303  /* if no variables to be fixed, then previous negative result will hold */
15304  if( assumevarfixed == NULL )
15305  {
15306  *result = FALSE;
15307  return SCIP_OKAY;
15308  }
15309  }
15310 
15311  checkCurvatureEasy(scip, cons, assumevarfixed, &determined, TRUE, &isconvex, &isconcave, &maxnonconvexity);
15312  if( !determined )
15313  {
15314  SCIP_CALL( checkCurvatureExpensive(scip, cons, assumevarfixed, &isconvex, &isconcave, &maxnonconvexity) );
15315  }
15316 
15317  if( assumevarfixed == NULL )
15318  {
15319  consdata->isconvex = isconvex;
15320  consdata->isconcave = isconcave;
15321  consdata->maxnonconvexity = maxnonconvexity;
15322  consdata->iscurvchecked = TRUE;
15323  }
15324 
15325  if( (isconvex && SCIPisInfinity(scip, -consdata->lhs)) || (isconcave && SCIPisInfinity(scip, consdata->rhs)) )
15326  {
15327  *result = TRUE;
15328  return SCIP_OKAY;
15329  }
15330 
15331  *result = FALSE;
15332  return SCIP_OKAY;
15333 }
15334 
15335 /** Computes the violation of a constraint by a solution */
15337  SCIP* scip, /**< SCIP data structure */
15338  SCIP_CONS* cons, /**< constraint */
15339  SCIP_SOL* sol, /**< solution which violation to calculate, or NULL for LP solution */
15340  SCIP_Real* violation /**< pointer to store violation of constraint */
15341  )
15342 {
15343  SCIP_CONSDATA* consdata;
15344  SCIP_Bool solviolbounds;
15345 
15346  assert(scip != NULL);
15347  assert(cons != NULL);
15348  assert(violation != NULL);
15349 
15350  SCIP_CALL( computeViolation(scip, cons, sol, &solviolbounds) );
15351  /* we don't care here whether the solution violated variable bounds */
15352 
15353  consdata = SCIPconsGetData(cons);
15354  assert(consdata != NULL);
15355 
15356  *violation = MAX(consdata->lhsviol, consdata->rhsviol);
15357 
15358  return SCIP_OKAY; /*lint !e438*/
15359 }
15360 
15361 /** Indicates whether the quadratic constraint is local w.r.t. the current local bounds.
15362  *
15363  * That is, checks whether each variable with a square term is fixed and for each bilinear term at least one variable is fixed.
15364  */
15366  SCIP* scip, /**< SCIP data structure */
15367  SCIP_CONS* cons /**< constraint */
15368  )
15369 {
15370  SCIP_CONSDATA* consdata;
15371  SCIP_VAR* var1;
15372  SCIP_VAR* var2;
15373  int i;
15374 
15375  assert(scip != NULL);
15376  assert(cons != NULL);
15377 
15378  consdata = SCIPconsGetData(cons);
15379  assert(consdata != NULL);
15380 
15381  /* check all square terms */
15382  for( i = 0; i < consdata->nquadvars; ++i )
15383  {
15384  if( consdata->quadvarterms[i].sqrcoef == 0.0 )
15385  continue;
15386 
15387  var1 = consdata->quadvarterms[i].var;
15388  assert(var1 != NULL);
15389 
15390  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var1), SCIPvarGetUbLocal(var1)) )
15391  return FALSE;
15392  }
15393 
15394  for( i = 0; i < consdata->nbilinterms; ++i )
15395  {
15396  var1 = consdata->bilinterms[i].var1;
15397  var2 = consdata->bilinterms[i].var2;
15398 
15399  assert(var1 != NULL);
15400  assert(var2 != NULL);
15401 
15402  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var1), SCIPvarGetUbLocal(var1)) &&
15403  ! SCIPisRelEQ(scip, SCIPvarGetLbLocal(var2), SCIPvarGetUbLocal(var2)) )
15404  return FALSE;
15405  }
15406 
15407  return TRUE;
15408 }
15409 
15410 /** Adds the constraint to an NLPI problem. */
15412  SCIP* scip, /**< SCIP data structure */
15413  SCIP_CONS* cons, /**< constraint */
15414  SCIP_NLPI* nlpi, /**< interface to NLP solver */
15415  SCIP_NLPIPROBLEM* nlpiprob, /**< NLPI problem where to add constraint */
15416  SCIP_HASHMAP* scipvar2nlpivar, /**< mapping from SCIP variables to variable indices in NLPI */
15417  SCIP_Bool names /**< whether to pass constraint names to NLPI */
15418  )
15419 {
15420  SCIP_CONSDATA* consdata;
15421  int nlininds;
15422  int* lininds;
15423  SCIP_Real* linvals;
15424  int nquadelems;
15425  SCIP_QUADELEM* quadelems;
15426  SCIP_VAR* othervar;
15427  const char* name;
15428  int j;
15429  int l;
15430  int lincnt;
15431  int quadcnt;
15432  int idx1;
15433  int idx2;
15434 
15435  assert(scip != NULL);
15436  assert(cons != NULL);
15437  assert(nlpi != NULL);
15438  assert(nlpiprob != NULL);
15439  assert(scipvar2nlpivar != NULL);
15440 
15441  consdata = SCIPconsGetData(cons);
15442  assert(consdata != NULL);
15443 
15444  /* count nonzeros in quadratic part */
15445  nlininds = consdata->nlinvars;
15446  nquadelems = consdata->nbilinterms;
15447  for( j = 0; j < consdata->nquadvars; ++j )
15448  {
15449  if( consdata->quadvarterms[j].sqrcoef != 0.0 )
15450  ++nquadelems;
15451  if( consdata->quadvarterms[j].lincoef != 0.0 )
15452  ++nlininds;
15453  }
15454 
15455  /* setup linear part */
15456  lininds = NULL;
15457  linvals = NULL;
15458  lincnt = 0;
15459  if( nlininds > 0 )
15460  {
15461  SCIP_CALL( SCIPallocBufferArray(scip, &lininds, nlininds) );
15462  SCIP_CALL( SCIPallocBufferArray(scip, &linvals, nlininds) );
15463 
15464  for( j = 0; j < consdata->nlinvars; ++j )
15465  {
15466  linvals[j] = consdata->lincoefs[j];
15467  assert(SCIPhashmapExists(scipvar2nlpivar, consdata->linvars[j]));
15468  lininds[j] = SCIPhashmapGetImageInt(scipvar2nlpivar, consdata->linvars[j]);
15469  }
15470 
15471  lincnt = consdata->nlinvars;
15472  }
15473 
15474  /* setup quadratic part */
15475  quadelems = NULL;
15476  if( nquadelems > 0 )
15477  {
15478  SCIP_CALL( SCIPallocBufferArray(scip, &quadelems, nquadelems) );
15479  }
15480  quadcnt = 0;
15481 
15482  for( j = 0; j < consdata->nquadvars; ++j )
15483  {
15484  assert(SCIPhashmapExists(scipvar2nlpivar, consdata->quadvarterms[j].var));
15485  idx1 = SCIPhashmapGetImageInt(scipvar2nlpivar, consdata->quadvarterms[j].var);
15486  if( consdata->quadvarterms[j].lincoef != 0.0 )
15487  {
15488  assert(lininds != NULL);
15489  assert(linvals != NULL);
15490  /* coverity[var_deref_op] */
15491  lininds[lincnt] = idx1;
15492  linvals[lincnt] = consdata->quadvarterms[j].lincoef;
15493  ++lincnt;
15494  }
15495 
15496  if( consdata->quadvarterms[j].sqrcoef != 0.0 )
15497  {
15498  assert(quadcnt < nquadelems);
15499  assert(quadelems != NULL);
15500  /* coverity[var_deref_op] */
15501  quadelems[quadcnt].idx1 = idx1;
15502  quadelems[quadcnt].idx2 = idx1;
15503  quadelems[quadcnt].coef = consdata->quadvarterms[j].sqrcoef;
15504  ++quadcnt;
15505  }
15506 
15507  for( l = 0; l < consdata->quadvarterms[j].nadjbilin; ++l )
15508  {
15509  othervar = consdata->bilinterms[consdata->quadvarterms[j].adjbilin[l]].var2;
15510  /* if othervar is on position 2, then we process this bilinear term later (or it was processed already) */
15511  if( othervar == consdata->quadvarterms[j].var )
15512  continue;
15513 
15514  assert(quadcnt < nquadelems);
15515  assert(quadelems != NULL);
15516  assert(SCIPhashmapExists(scipvar2nlpivar, othervar));
15517  idx2 = SCIPhashmapGetImageInt(scipvar2nlpivar, othervar);
15518  /* coverity[var_deref_op] */
15519  quadelems[quadcnt].idx1 = MIN(idx1, idx2);
15520  quadelems[quadcnt].idx2 = MAX(idx1, idx2);
15521  quadelems[quadcnt].coef = consdata->bilinterms[consdata->quadvarterms[j].adjbilin[l]].coef;
15522  ++quadcnt;
15523  }
15524  }
15525 
15526  assert(quadcnt == nquadelems);
15527  assert(lincnt == nlininds);
15528 
15529  name = names ? SCIPconsGetName(cons) : NULL;
15530 
15531  SCIP_CALL( SCIPnlpiAddConstraints(nlpi, nlpiprob, 1,
15532  &consdata->lhs, &consdata->rhs,
15533  &nlininds, &lininds, &linvals ,
15534  &nquadelems, &quadelems,
15535  NULL, NULL, &name) );
15536 
15537  SCIPfreeBufferArrayNull(scip, &quadelems);
15538  SCIPfreeBufferArrayNull(scip, &lininds);
15539  SCIPfreeBufferArrayNull(scip, &linvals);
15540 
15541  return SCIP_OKAY;
15542 }
15543 
15544 
15545 /** sets the left hand side of a quadratic constraint
15546  *
15547  * @note This method may only be called during problem creation stage for an original constraint.
15548  */
15550  SCIP* scip, /**< SCIP data structure */
15551  SCIP_CONS* cons, /**< constraint data */
15552  SCIP_Real lhs /**< new left hand side */
15553  )
15554 {
15555  SCIP_CONSDATA* consdata;
15556 
15557  assert(scip != NULL);
15558  assert(cons != NULL);
15559  assert(!SCIPisInfinity(scip, lhs));
15560 
15561  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
15562  {
15563  SCIPerrorMessage("constraint is not quadratic\n");
15564  return SCIP_INVALIDDATA;
15565  }
15566 
15567  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) )
15568  {
15569  SCIPerrorMessage("method may only be called during problem creation stage for original constraints\n");
15570  return SCIP_INVALIDDATA;
15571  }
15572 
15573  consdata = SCIPconsGetData(cons);
15574  assert(consdata != NULL);
15575  assert(!SCIPisInfinity(scip, consdata->lhs));
15576 
15577  /* adjust value to not be smaller than -inf */
15578  if( SCIPisInfinity(scip, -lhs) )
15579  lhs = -SCIPinfinity(scip);
15580 
15581  /* check for lhs <= rhs */
15582  if( !SCIPisLE(scip, lhs, consdata->rhs) )
15583  return SCIP_INVALIDDATA;
15584 
15585  consdata->lhs = lhs;
15586 
15587  return SCIP_OKAY;
15588 }
15589 
15590 /** sets the right hand side of a quadratic constraint
15591  *
15592  * @note This method may only be called during problem creation stage for an original constraint.
15593  */
15595  SCIP* scip, /**< SCIP data structure */
15596  SCIP_CONS* cons, /**< constraint data */
15597  SCIP_Real rhs /**< new right hand side */
15598  )
15599 {
15600  SCIP_CONSDATA* consdata;
15601 
15602  assert(scip != NULL);
15603  assert(cons != NULL);
15604  assert(!SCIPisInfinity(scip, -rhs));
15605 
15606  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
15607  {
15608  SCIPerrorMessage("constraint is not quadratic\n");
15609  return SCIP_INVALIDDATA;
15610  }
15611 
15612  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) )
15613  {
15614  SCIPerrorMessage("method may only be called during problem creation stage for original constraints\n");
15615  return SCIP_INVALIDDATA;
15616  }
15617 
15618  consdata = SCIPconsGetData(cons);
15619  assert(consdata != NULL);
15620  assert(!SCIPisInfinity(scip, -consdata->rhs));
15621 
15622  /* adjust value to not be greater than inf */
15623  if( SCIPisInfinity(scip, rhs) )
15624  rhs = SCIPinfinity(scip);
15625 
15626  /* check for lhs <= rhs */
15627  if( !SCIPisLE(scip, consdata->lhs, rhs) )
15628  return SCIP_INVALIDDATA;
15629 
15630  consdata->rhs = rhs;
15631 
15632  return SCIP_OKAY;
15633 }
15634 
15635 /** gets the feasibility of the quadratic constraint in the given solution */
15637  SCIP* scip, /**< SCIP data structure */
15638  SCIP_CONS* cons, /**< constraint data */
15639  SCIP_SOL* sol, /**< solution, or NULL to use current node's solution */
15640  SCIP_Real* feasibility /**< pointer to store the feasibility */
15641  )
15642 {
15643  SCIP_CONSDATA* consdata;
15644  SCIP_Bool solviolbounds;
15645 
15646  assert(scip != NULL);
15647  assert(cons != NULL);
15648  assert(feasibility != NULL);
15649 
15650  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
15651  {
15652  SCIPerrorMessage("constraint is not quadratic\n");
15653  SCIPABORT();
15654  }
15655 
15656  SCIP_CALL( computeViolation(scip, cons, sol, &solviolbounds) );
15657 
15658  consdata = SCIPconsGetData(cons);
15659  assert(consdata != NULL);
15660 
15661  if( SCIPisInfinity(scip, consdata->rhs) && SCIPisInfinity(scip, -consdata->lhs) )
15662  *feasibility = SCIPinfinity(scip);
15663  else if( SCIPisInfinity(scip, -consdata->lhs) )
15664  *feasibility = (consdata->rhs - consdata->activity);
15665  else if( SCIPisInfinity(scip, consdata->rhs) )
15666  *feasibility = (consdata->activity - consdata->lhs);
15667  else
15668  {
15669  assert(!SCIPisInfinity(scip, -consdata->rhs));
15670  assert(!SCIPisInfinity(scip, consdata->lhs));
15671  *feasibility = MIN( consdata->rhs - consdata->activity, consdata->activity - consdata->lhs );
15672  }
15673 
15674  return SCIP_OKAY; /*lint !e438*/
15675 }
15676 
15677 /** gets the activity of the quadratic constraint in the given solution */
15679  SCIP* scip, /**< SCIP data structure */
15680  SCIP_CONS* cons, /**< constraint data */
15681  SCIP_SOL* sol, /**< solution, or NULL to use current node's solution */
15682  SCIP_Real* activity /**< pointer to store the activity */
15683  )
15684 {
15685  SCIP_CONSDATA* consdata;
15686  SCIP_Bool solviolbounds;
15687 
15688  assert(scip != NULL);
15689  assert(cons != NULL);
15690  assert(activity != NULL);
15691 
15692  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
15693  {
15694  SCIPerrorMessage("constraint is not quadratic\n");
15695  SCIPABORT();
15696  }
15697 
15698  SCIP_CALL( computeViolation(scip, cons, sol, &solviolbounds) );
15699 
15700  consdata = SCIPconsGetData(cons);
15701  assert(consdata != NULL);
15702 
15703  *activity = consdata->activity;
15704 
15705  return SCIP_OKAY; /*lint !e438*/
15706 }
15707 
15708 /** changes the linear coefficient value for a given quadratic variable in a quadratic constraint data; if not
15709  * available, it adds it
15710  *
15711  * @note this is only allowed for original constraints and variables in problem creation stage
15712  */
15714  SCIP* scip, /**< SCIP data structure */
15715  SCIP_CONS* cons, /**< constraint data */
15716  SCIP_VAR* var, /**< quadratic variable */
15717  SCIP_Real coef /**< new coefficient */
15718  )
15719 {
15720  SCIP_CONSDATA* consdata;
15721  SCIP_Bool found;
15722  int i;
15723 
15724  assert(scip != NULL);
15725  assert(cons != NULL);
15726  assert(var != NULL);
15727 
15728  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
15729  {
15730  SCIPerrorMessage("constraint is not quadratic\n");
15731  return SCIP_INVALIDDATA;
15732  }
15733 
15734  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) || !SCIPvarIsOriginal(var) )
15735  {
15736  SCIPerrorMessage("method may only be called during problem creation stage for original constraints and variables\n");
15737  return SCIP_INVALIDDATA;
15738  }
15739 
15740  consdata = SCIPconsGetData(cons);
15741  assert(consdata != NULL);
15742 
15743  /* check all quadratic variables */
15744  found = FALSE;
15745  for( i = 0; i < consdata->nquadvars; ++i )
15746  {
15747  if( var == consdata->quadvarterms[i].var )
15748  {
15749  if( found || SCIPisZero(scip, coef) )
15750  {
15751  consdata->quadvarterms[i].lincoef = 0.0;
15752 
15753  /* remember to merge quadratic variable terms */
15754  consdata->quadvarsmerged = FALSE;
15755  }
15756  else
15757  consdata->quadvarterms[i].lincoef = coef;
15758 
15759  found = TRUE;
15760  }
15761  }
15762 
15763  /* check all linear variables */
15764  i = 0;
15765  while( i < consdata->nlinvars )
15766  {
15767  if( var == consdata->linvars[i] )
15768  {
15769  if( found || SCIPisZero(scip, coef) )
15770  {
15771  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
15772 
15773  /* decrease i by one since otherwise we would skip the coefficient which has been switched to position i */
15774  i--;
15775  }
15776  else
15777  {
15778  SCIP_CALL( chgLinearCoefPos(scip, cons, i, coef) );
15779  }
15780 
15781  found = TRUE;
15782  }
15783  i++;
15784  }
15785 
15786  /* add linear term if necessary */
15787  if( !found && !SCIPisZero(scip, coef) )
15788  {
15789  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
15790  }
15791 
15792  consdata->ispropagated = FALSE;
15793  consdata->ispresolved = FALSE;
15794 
15795  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
15796  consdata->activity = SCIP_INVALID;
15797 
15798  return SCIP_OKAY;
15799 }
15800 
15801 /** changes the square coefficient value for a given quadratic variable in a quadratic constraint data; if not
15802  * available, it adds it
15803  *
15804  * @note this is only allowed for original constraints and variables in problem creation stage
15805  */
15807  SCIP* scip, /**< SCIP data structure */
15808  SCIP_CONS* cons, /**< constraint data */
15809  SCIP_VAR* var, /**< quadratic variable */
15810  SCIP_Real coef /**< new coefficient */
15811  )
15812 {
15813  SCIP_CONSDATA* consdata;
15814  SCIP_Bool found;
15815  int i;
15816 
15817  assert(scip != NULL);
15818  assert(cons != NULL);
15819  assert(var != NULL);
15820  assert(!SCIPisInfinity(scip, REALABS(coef)));
15821 
15822  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
15823  {
15824  SCIPerrorMessage("constraint is not quadratic\n");
15825  return SCIP_INVALIDDATA;
15826  }
15827 
15828  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) || !SCIPvarIsOriginal(var) )
15829  {
15830  SCIPerrorMessage("method may only be called during problem creation stage for original constraints and variables\n");
15831  return SCIP_INVALIDDATA;
15832  }
15833 
15834  consdata = SCIPconsGetData(cons);
15835  assert(consdata != NULL);
15836 
15837  /* find the quadratic variable and change its quadratic coefficient */
15838  found = FALSE;
15839  for( i = 0; i < consdata->nquadvars; ++i )
15840  {
15841  if( var == consdata->quadvarterms[i].var )
15842  {
15843  consdata->quadvarterms[i].sqrcoef = (found || SCIPisZero(scip, coef)) ? 0.0 : coef;
15844  found = TRUE;
15845  }
15846  }
15847 
15848  /* add bilinear term if necessary */
15849  if( !found && !SCIPisZero(scip, coef) )
15850  {
15851  SCIP_CALL( addQuadVarTerm(scip, cons, var, 0.0, coef) );
15852  }
15853 
15854  /* update flags and invalidate activities */
15855  consdata->isconvex = FALSE;
15856  consdata->isconcave = FALSE;
15857  consdata->iscurvchecked = FALSE;
15858  consdata->ispropagated = FALSE;
15859  consdata->ispresolved = FALSE;
15860 
15861  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
15862  consdata->activity = SCIP_INVALID;
15863 
15864  /* remember to merge quadratic variable terms */
15865  consdata->quadvarsmerged = FALSE;
15866 
15867  return SCIP_OKAY;
15868 }
15869 
15870 /** changes the bilinear coefficient value for a given quadratic variable in a quadratic constraint data; if not
15871  * available, it adds it
15872  *
15873  * @note this is only allowed for original constraints and variables in problem creation stage
15874  */
15876  SCIP* scip, /**< SCIP data structure */
15877  SCIP_CONS* cons, /**< constraint */
15878  SCIP_VAR* var1, /**< first variable */
15879  SCIP_VAR* var2, /**< second variable */
15880  SCIP_Real coef /**< coefficient of bilinear term */
15881  )
15882 {
15883  SCIP_CONSDATA* consdata;
15884  SCIP_Bool found;
15885  int i;
15886 
15887  assert(scip != NULL);
15888  assert(cons != NULL);
15889  assert(var1 != NULL);
15890  assert(var2 != NULL);
15891  assert(!SCIPisInfinity(scip, REALABS(coef)));
15892 
15893  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
15894  {
15895  SCIPerrorMessage("constraint is not quadratic\n");
15896  return SCIP_INVALIDDATA;
15897  }
15898 
15899  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) || !SCIPvarIsOriginal(var1) || !SCIPvarIsOriginal(var2) )
15900  {
15901  SCIPerrorMessage("method may only be called during problem creation stage for original constraints and variables\n");
15902  return SCIP_INVALIDDATA;
15903  }
15904 
15905  if( var1 == var2 )
15906  {
15907  SCIP_CALL( SCIPchgSquareCoefQuadratic(scip, cons, var1, coef) );
15908  return SCIP_OKAY;
15909  }
15910 
15911  consdata = SCIPconsGetData(cons);
15912  assert(consdata != NULL);
15913 
15914  /* search array of bilinear terms */
15915  found = FALSE;
15916  for( i = 0; i < consdata->nbilinterms; ++i )
15917  {
15918  if( (consdata->bilinterms[i].var1 == var1 && consdata->bilinterms[i].var2 == var2) ||
15919  (consdata->bilinterms[i].var1 == var2 && consdata->bilinterms[i].var2 == var1) )
15920  {
15921  if( found || SCIPisZero(scip, coef) )
15922  {
15923  consdata->bilinterms[i].coef = 0.0;
15924 
15925  /* remember to merge bilinear terms */
15926  consdata->bilinmerged = FALSE;
15927  }
15928  else
15929  consdata->bilinterms[i].coef = coef;
15930  found = TRUE;
15931  }
15932  }
15933 
15934  /* add bilinear term if necessary */
15935  if( !found )
15936  {
15937  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, cons, var1, var2, coef) );
15938  }
15939 
15940  /* update flags and invalidate activities */
15941  consdata->isconvex = FALSE;
15942  consdata->isconcave = FALSE;
15943  consdata->iscurvchecked = FALSE;
15944  consdata->ispropagated = FALSE;
15945  consdata->ispresolved = FALSE;
15946 
15947  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
15948  consdata->activity = SCIP_INVALID;
15949 
15950  return SCIP_OKAY;
15951 }
15952 
15953 /** returns the total number of bilinear terms that are contained in all quadratic constraints */
15955  SCIP* scip /**< SCIP data structure */
15956  )
15957 {
15958  SCIP_CONSHDLRDATA* conshdlrdata;
15959  SCIP_CONSHDLR* conshdlr;
15960 
15961  assert(scip != NULL);
15962 
15963  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
15964 
15965  if( conshdlr == NULL )
15966  return 0;
15967 
15968  conshdlrdata = SCIPconshdlrGetData(conshdlr);
15969  assert(conshdlrdata != NULL);
15970 
15971  return conshdlrdata->nbilinterms;
15972 }
15973 
15974 /** returns all bilinear terms that are contained in all quadratic constraints */
15976  SCIP* scip, /**< SCIP data structure */
15977  SCIP_VAR** RESTRICT x, /**< array to store first variable of each bilinear term */
15978  SCIP_VAR** RESTRICT y, /**< array to second variable of each bilinear term */
15979  int* RESTRICT nbilinterms, /**< buffer to store the total number of bilinear terms */
15980  int* RESTRICT nunderests, /**< array to store the total number of constraints that require to underestimate a bilinear term */
15981  int* RESTRICT noverests, /**< array to store the total number of constraints that require to overestimate a bilinear term */
15982  SCIP_Real* maxnonconvexity /**< largest absolute value of nonconvex eigenvalues of all quadratic constraints containing a bilinear term */
15983  )
15984 {
15985  SCIP_CONSHDLRDATA* conshdlrdata;
15986  SCIP_CONSHDLR* conshdlr;
15987  int i;
15988 
15989  assert(scip != NULL);
15990  assert(x != NULL);
15991  assert(y != NULL);
15992  assert(nbilinterms != NULL);
15993  assert(nunderests != NULL);
15994  assert(noverests!= NULL);
15995  assert(maxnonconvexity != NULL);
15996 
15997  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
15998 
15999  if( conshdlr == NULL )
16000  {
16001  *nbilinterms = 0;
16002  return SCIP_OKAY;
16003  }
16004 
16005  conshdlrdata = SCIPconshdlrGetData(conshdlr);
16006  assert(conshdlrdata != NULL);
16007 
16008  for( i = 0; i < conshdlrdata->nbilinterms; ++i )
16009  {
16010  x[i] = conshdlrdata->bilinestimators[i].x;
16011  y[i] = conshdlrdata->bilinestimators[i].y;
16012  nunderests[i] = conshdlrdata->bilinestimators[i].nunderest;
16013  noverests[i] = conshdlrdata->bilinestimators[i].noverest;
16014  maxnonconvexity[i] = conshdlrdata->bilinestimators[i].maxnonconvexity;
16015  }
16016 
16017  *nbilinterms = conshdlrdata->nbilinterms;
16018 
16019  return SCIP_OKAY;
16020 }
16021 
16022 /** helper function to compute the violation of an inequality of the form xcoef * x <= ycoef * y + constant for two
16023  * corner points of the domain [lbx,ubx]x[lby,uby]
16024  */
16025 static
16026 void getIneqViol(
16027  SCIP_VAR* x, /**< first variable */
16028  SCIP_VAR* y, /**< second variable */
16029  SCIP_Real xcoef, /**< x-coefficient */
16030  SCIP_Real ycoef, /**< y-coefficient */
16031  SCIP_Real constant, /**< constant */
16032  SCIP_Real* viol1, /**< buffer to store the violation of the first corner point */
16033  SCIP_Real* viol2 /**< buffer to store the violation of the second corner point */
16034  )
16035 {
16036  SCIP_Real norm;
16037 
16038  assert(viol1 != NULL);
16039  assert(viol2 != NULL);
16040 
16041  norm = SQRT(SQR(xcoef) + SQR(ycoef));
16042 
16043  /* inequality can be used for underestimating xy if and only if xcoef * ycoef > 0 */
16044  if( xcoef * ycoef >= 0 )
16045  {
16046  /* violation for top-left and bottom-right corner */
16047  *viol1 = MAX(0, (xcoef * SCIPvarGetLbLocal(x) - ycoef * SCIPvarGetUbLocal(y) - constant) / norm); /*lint !e666*/
16048  *viol2 = MAX(0, (xcoef * SCIPvarGetUbLocal(x) - ycoef * SCIPvarGetLbLocal(y) - constant) / norm); /*lint !e666*/
16049  }
16050  else
16051  {
16052  /* violation for top-right and bottom-left corner */
16053  *viol1 = MAX(0, (xcoef * SCIPvarGetUbLocal(x) - ycoef * SCIPvarGetUbLocal(y) - constant) / norm); /*lint !e666*/
16054  *viol2 = MAX(0, (xcoef * SCIPvarGetLbLocal(x) - ycoef * SCIPvarGetLbLocal(y) - constant) / norm); /*lint !e666*/
16055  }
16056 
16057  return;
16058 }
16059 
16060 /** adds a globally valid inequality of the form xcoef x <= ycoef y + constant for a bilinear term (x,y)
16061  *
16062  * @note the indices of bilinear terms match with the entries of bilinear terms returned by SCIPgetAllBilinearTermsQuadratic
16063  */
16065  SCIP* scip, /**< SCIP data structure */
16066  SCIP_VAR* x, /**< first variable */
16067  SCIP_VAR* y, /**< second variable */
16068  int idx, /**< index of the bilinear term */
16069  SCIP_Real xcoef, /**< x coefficient */
16070  SCIP_Real ycoef, /**< y coefficient */
16071  SCIP_Real constant, /**< constant part */
16072  SCIP_Bool* success /**< buffer to store whether inequality has been accepted */
16073  )
16074 {
16075  SCIP_CONSHDLRDATA* conshdlrdata;
16076  SCIP_CONSHDLR* conshdlr;
16077  BILINESTIMATOR* bilinest;
16078  SCIP_Real* ineqs;
16079  SCIP_Real viol1 = 0.0;
16080  SCIP_Real viol2 = 0.0;
16081  int* nineqs;
16082  int i;
16083 
16084  assert(scip != NULL);
16085  assert(x != NULL);
16086  assert(y != NULL);
16087  assert(idx >= 0);
16088  assert(xcoef != SCIP_INVALID); /*lint !e777 */
16089  assert(ycoef != SCIP_INVALID); /*lint !e777 */
16090  assert(constant != SCIP_INVALID); /*lint !e777 */
16091  assert(success != NULL);
16092 
16093  *success = FALSE;
16094 
16095  /* ignore inequalities that only yield to a (possible) bound tightening */
16096  if( SCIPisFeasZero(scip, xcoef) || SCIPisFeasZero(scip, ycoef) )
16097  return SCIP_OKAY;
16098 
16099  /* get constraint handler and its data */
16100  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
16101  if( conshdlr == NULL )
16102  return SCIP_OKAY;
16103 
16104  conshdlrdata = SCIPconshdlrGetData(conshdlr);
16105  assert(conshdlrdata != NULL);
16106  assert(idx < conshdlrdata->nbilinterms);
16107 
16108  bilinest = &conshdlrdata->bilinestimators[idx];
16109  assert(bilinest != NULL);
16110  assert(bilinest->x == x);
16111  assert(bilinest->y == y);
16112 
16113  SCIPdebugMsg(scip, "add bilinear term inequality: %g %s <= %g %s + %g\n", xcoef, SCIPvarGetName(bilinest->x),
16114  ycoef, SCIPvarGetName(bilinest->y), constant);
16115 
16116  if( xcoef * ycoef > 0.0 )
16117  {
16118  ineqs = bilinest->inequnderest;
16119  nineqs = &bilinest->ninequnderest;
16120  }
16121  else
16122  {
16123  ineqs = bilinest->ineqoverest;
16124  nineqs = &bilinest->nineqoverest;
16125  }
16126 
16127  /* compute violation of the inequality of the important corner points */
16128  getIneqViol(x, y, xcoef, ycoef, constant, &viol1, &viol2);
16129  SCIPdebugMsg(scip, "violations of inequality = (%g,%g)\n", viol1, viol2);
16130 
16131  /* inequality does not cut off one of the important corner points */
16132  if( SCIPisFeasLE(scip, MAX(viol1, viol2), 0.0) )
16133  return SCIP_OKAY;
16134 
16135  /* check whether inequality exists already */
16136  for( i = 0; i < *nineqs; ++i )
16137  {
16138  if( SCIPisFeasEQ(scip, xcoef, ineqs[3*i]) && SCIPisFeasEQ(scip, ycoef, ineqs[3*i+1])
16139  && SCIPisFeasEQ(scip, constant, ineqs[3*i+2]) )
16140  {
16141  SCIPdebugMsg(scip, "inequality already found -> skip\n");
16142  return SCIP_OKAY;
16143  }
16144  }
16145 
16146  /* add inequality if we found less than two so far; otherwise compare the violations to decide which which
16147  * inequality might be replaced
16148  */
16149  if( *nineqs < 2 )
16150  {
16151  ineqs[3*(*nineqs)] = xcoef;
16152  ineqs[3*(*nineqs) + 1] = ycoef;
16153  ineqs[3*(*nineqs) + 2] = constant;
16154  ++(*nineqs);
16155  *success = TRUE;
16156  }
16157  else
16158  {
16159  SCIP_Real viols1[2] = {0.0, 0.0};
16160  SCIP_Real viols2[2] = {0.0, 0.0};
16161  SCIP_Real bestviol;
16162  int pos = -1;
16163 
16164  assert(*nineqs == 2);
16165 
16166  /* compute resulting violations of both corner points when replacing an existing inequality
16167  *
16168  * given the violations (v1,w1), (v2,w2), (v3,w3) we select two inequalities i and j that
16169  * maximize max{vi,vj} + max{wi,wj} this measurement guarantees that select inequalities that
16170  * separate both important corner points
16171  */
16172  getIneqViol(x, y, ineqs[0], ineqs[1], ineqs[2], &viols1[0], &viols2[0]);
16173  getIneqViol(x, y, ineqs[3], ineqs[4], ineqs[5], &viols1[1], &viols2[1]);
16174  bestviol = MAX(viols1[0], viols1[1]) + MAX(viols2[0], viols2[1]);
16175 
16176  for( i = 0; i < 2; ++i )
16177  {
16178  SCIP_Real viol = MAX(viol1, viols1[i]) + MAX(viol2, viols2[i]);
16179  if( SCIPisGT(scip, viol, bestviol) )
16180  {
16181  bestviol = viol;
16182  /* remember inequality that should be replaced */
16183  pos = 1 - i;
16184  }
16185  }
16186 
16187  /* replace inequality at pos when replacing an existing inequality improved the total violation */
16188  if( pos != -1 )
16189  {
16190  assert(pos >= 0 && pos < 2);
16191  ineqs[3*pos] = xcoef;
16192  ineqs[3*pos+1] = ycoef;
16193  ineqs[3*pos+2] = constant;
16194  *success = TRUE;
16195  }
16196  }
16197  SCIPdebugMsg(scip, "accepted inequality? %u\n", *success);
16198 
16199  return SCIP_OKAY;
16200 }
16201 
16202 
16203 /** creates a SCIP_ROWPREP datastructure
16204  *
16205  * Initial cut represents 0 <= 0.
16206  */
16208  SCIP* scip, /**< SCIP data structure */
16209  SCIP_ROWPREP** rowprep, /**< buffer to store pointer to rowprep */
16210  SCIP_SIDETYPE sidetype, /**< whether cut will be or lower-equal or larger-equal type */
16211  SCIP_Bool local /**< whether cut will be valid only locally */
16212  )
16213 {
16214  assert(scip != NULL);
16215  assert(rowprep != NULL);
16216 
16217  SCIP_CALL( SCIPallocBlockMemory(scip, rowprep) );
16218  BMSclearMemory(*rowprep);
16219 
16220  (*rowprep)->sidetype = sidetype;
16221  (*rowprep)->local = local;
16222 
16223  return SCIP_OKAY;
16224 }
16225 
16226 /** frees a SCIP_ROWPREP datastructure */
16227 void SCIPfreeRowprep(
16228  SCIP* scip, /**< SCIP data structure */
16229  SCIP_ROWPREP** rowprep /**< pointer that stores pointer to rowprep */
16230  )
16231 {
16232  assert(scip != NULL);
16233  assert(rowprep != NULL);
16234  assert(*rowprep != NULL);
16235 
16236  SCIPfreeBlockMemoryArrayNull(scip, &(*rowprep)->vars, (*rowprep)->varssize);
16237  SCIPfreeBlockMemoryArrayNull(scip, &(*rowprep)->coefs, (*rowprep)->varssize);
16238  SCIPfreeBlockMemory(scip, rowprep);
16239 }
16240 
16241 /** creates a copy of a SCIP_ROWPREP datastructure */
16243  SCIP* scip, /**< SCIP data structure */
16244  SCIP_ROWPREP** target, /**< buffer to store pointer of rowprep copy */
16245  SCIP_ROWPREP* source /**< rowprep to copy */
16246  )
16247 {
16248  assert(scip != NULL);
16249  assert(target != NULL);
16250  assert(source != NULL);
16251 
16252  SCIP_CALL( SCIPduplicateBlockMemory(scip, target, source) );
16253  if( source->coefs != NULL )
16254  {
16255  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*target)->coefs, source->coefs, source->varssize) );
16256  }
16257  if( source->vars != NULL )
16258  {
16259  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*target)->vars, source->vars, source->varssize) );
16260  }
16261 
16262  return SCIP_OKAY;
16263 }
16264 
16265 /** ensures that rowprep has space for at least given number of additional terms
16266  *
16267  * Useful when knowing in advance how many terms will be added.
16268  */
16270  SCIP* scip, /**< SCIP data structure */
16271  SCIP_ROWPREP* rowprep, /**< rowprep */
16272  int size /**< number of additional terms for which to alloc space in rowprep */
16273  )
16274 {
16275  int oldsize;
16276 
16277  assert(scip != NULL);
16278  assert(rowprep != NULL);
16279  assert(size >= 0);
16280 
16281  if( rowprep->varssize >= rowprep->nvars + size )
16282  return SCIP_OKAY; /* already enough space left */
16283 
16284  /* realloc vars and coefs array */
16285  oldsize = rowprep->varssize;
16286  rowprep->varssize = SCIPcalcMemGrowSize(scip, rowprep->nvars + size);
16287 
16288  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &rowprep->vars, oldsize, rowprep->varssize) );
16289  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &rowprep->coefs, oldsize, rowprep->varssize) );
16290 
16291  return SCIP_OKAY;
16292 }
16293 
16294 /** prints a rowprep */
16295 void SCIPprintRowprep(
16296  SCIP* scip, /**< SCIP data structure */
16297  SCIP_ROWPREP* rowprep, /**< rowprep to be printed */
16298  FILE* file /**< file to print to, or NULL for stdout */
16299  )
16300 {
16301  int i;
16302 
16303  assert(scip != NULL);
16304  assert(rowprep != NULL);
16305 
16306  if( *rowprep->name != '\0' )
16307  {
16308  SCIPinfoMessage(scip, file, "[%s](%c) ", rowprep->name, rowprep->local ? 'l' : 'g');
16309  }
16310 
16311  for( i = 0; i < rowprep->nvars; ++i )
16312  {
16313  SCIPinfoMessage(scip, file, "%+.15g*<%s> ", rowprep->coefs[i], SCIPvarGetName(rowprep->vars[i]));
16314  }
16315 
16316  SCIPinfoMessage(scip, file, rowprep->sidetype == SCIP_SIDETYPE_LEFT ? ">= %.15g\n" : "<= %.15g\n", rowprep->side);
16317 }
16318 
16319 /** adds a term coef*var to a rowprep */
16321  SCIP* scip, /**< SCIP data structure */
16322  SCIP_ROWPREP* rowprep, /**< rowprep */
16323  SCIP_VAR* var, /**< variable to add */
16324  SCIP_Real coef /**< coefficient to add */
16325  )
16326 {
16327  assert(scip != NULL);
16328  assert(rowprep != NULL);
16329  assert(var != NULL);
16330 
16331  if( coef == 0.0 )
16332  return SCIP_OKAY;
16333 
16334  SCIP_CALL( SCIPensureRowprepSize(scip, rowprep, 1) );
16335  assert(rowprep->varssize > rowprep->nvars);
16336 
16337  rowprep->vars[rowprep->nvars] = var;
16338  rowprep->coefs[rowprep->nvars] = coef;
16339  ++rowprep->nvars;
16340 
16341  return SCIP_OKAY;
16342 }
16343 
16344 /** adds several terms coef*var to a rowprep */
16346  SCIP* scip, /**< SCIP data structure */
16347  SCIP_ROWPREP* rowprep, /**< rowprep */
16348  int nvars, /**< number of terms to add */
16349  SCIP_VAR** vars, /**< variables to add */
16350  SCIP_Real* coefs /**< coefficients to add */
16351  )
16352 {
16353  assert(scip != NULL);
16354  assert(rowprep != NULL);
16355  assert(vars != NULL || nvars == 0);
16356  assert(coefs != NULL || nvars == 0);
16357 
16358  if( nvars == 0 )
16359  return SCIP_OKAY;
16360 
16361  SCIP_CALL( SCIPensureRowprepSize(scip, rowprep, nvars) );
16362  assert(rowprep->varssize >= rowprep->nvars + nvars);
16363 
16364  /*lint --e{866} */
16365  BMScopyMemoryArray(rowprep->vars + rowprep->nvars, vars, nvars);
16366  BMScopyMemoryArray(rowprep->coefs + rowprep->nvars, coefs, nvars);
16367  rowprep->nvars += nvars;
16368 
16369  return SCIP_OKAY;
16370 }
16371 
16372 #ifdef NDEBUG
16373 #undef SCIPaddRowprepSide
16374 #undef SCIPaddRowprepConstant
16375 #endif
16376 
16377 /** adds constant value to side of rowprep */
16378 void SCIPaddRowprepSide(
16379  SCIP_ROWPREP* rowprep, /**< rowprep */
16380  SCIP_Real side /**< constant value to be added to side */
16381  )
16382 {
16383  assert(rowprep != NULL);
16384 
16385  rowprep->side += side;
16386 }
16387 
16388 /** adds constant term to rowprep
16389  *
16390  * Substracts constant from side.
16391  */
16393  SCIP_ROWPREP* rowprep, /**< rowprep */
16394  SCIP_Real constant /**< constant value to be added */
16395  )
16396 {
16397  assert(rowprep != NULL);
16398 
16399  SCIPaddRowprepSide(rowprep, -constant);
16400 }
16401 
16402 /** computes violation of cut in a given solution */
16404  SCIP* scip, /**< SCIP data structure */
16405  SCIP_ROWPREP* rowprep, /**< rowprep to be turned into a row */
16406  SCIP_SOL* sol /**< solution or NULL for LP solution */
16407  )
16408 {
16409  SCIP_Real activity;
16410  int i;
16411 
16412  activity = 0.0;
16413  for( i = 0; i < rowprep->nvars; ++i )
16414  {
16415  /* Loose variable have the best bound as LP solution value.
16416  * HOWEVER, they become column variables when they are added to a row (via SCIPaddVarsToRow below).
16417  * When this happens, their LP solution value changes to 0.0!
16418  * So when calculating the row activity for an LP solution, we treat loose variable as if they were already column variables.
16419  */
16420  if( sol != NULL || SCIPvarGetStatus(rowprep->vars[i]) != SCIP_VARSTATUS_LOOSE )
16421  activity += rowprep->coefs[i] * SCIPgetSolVal(scip, sol, rowprep->vars[i]);
16422  }
16423 
16424  if( rowprep->sidetype == SCIP_SIDETYPE_RIGHT )
16425  /* cut is activity <= side -> violation is activity - side, if positive */
16426  return MAX(activity - rowprep->side, 0.0);
16427  else
16428  /* cut is activity >= side -> violation is side - activity, if positive */
16429  return MAX(rowprep->side - activity, 0.0);
16430 }
16431 
16432 /** Merge terms that use same variable and eliminate zero coefficients.
16433  *
16434  * Terms are sorted by variable (@see SCIPvarComp) after return.
16435  */
16437  SCIP* scip, /**< SCIP data structure */
16438  SCIP_ROWPREP* rowprep /**< rowprep to be cleaned up */
16439  )
16440 {
16441  int i;
16442  int j;
16443 
16444  assert(scip != NULL);
16445  assert(rowprep != NULL);
16446 
16447  if( rowprep->nvars <= 1 )
16448  return;
16449 
16450  /* sort terms by variable index */
16451  SCIPsortPtrReal((void**)rowprep->vars, rowprep->coefs, SCIPvarComp, rowprep->nvars);
16452 
16453  /* merge terms with same variable, drop 0 coefficients */
16454  i = 0;
16455  j = 1;
16456  while( j < rowprep->nvars )
16457  {
16458  if( rowprep->vars[i] == rowprep->vars[j] )
16459  {
16460  /* merge term j into term i */
16461  rowprep->coefs[i] += rowprep->coefs[j];
16462  ++j;
16463  continue;
16464  }
16465 
16466  if( rowprep->coefs[i] == 0.0 )
16467  {
16468  /* move term j to position i */
16469  rowprep->coefs[i] = rowprep->coefs[j];
16470  rowprep->vars[i] = rowprep->vars[j];
16471  ++j;
16472  continue;
16473  }
16474 
16475  /* move term j to position i+1 and move on */
16476  if( j != i+1 )
16477  {
16478  rowprep->vars[i+1] = rowprep->vars[j];
16479  rowprep->coefs[i+1] = rowprep->coefs[j];
16480  }
16481  ++i;
16482  ++j;
16483  }
16484 
16485  /* remaining term can have coef zero -> forget about it */
16486  if( rowprep->coefs[i] == 0.0 )
16487  --i;
16488 
16489  /* i points to last term */
16490  rowprep->nvars = i+1;
16491 }
16492 
16493 /** sort cut terms by absolute value of coefficients, from largest to smallest */
16494 static
16496  SCIP* scip, /**< SCIP data structure */
16497  SCIP_ROWPREP* rowprep /**< rowprep to be sorted */
16498  )
16499 {
16500  int i;
16501 
16502  assert(scip != NULL);
16503  assert(rowprep != NULL);
16504 
16505  /* special treatment for cuts with few variables */
16506  switch( rowprep->nvars )
16507  {
16508  case 0:
16509  case 1:
16510  break;
16511 
16512  case 2:
16513  {
16514  if( REALABS(rowprep->coefs[0]) < REALABS(rowprep->coefs[1]) )
16515  {
16516  SCIP_Real tmp1;
16517  SCIP_VAR* tmp2;
16518 
16519  tmp1 = rowprep->coefs[0];
16520  rowprep->coefs[0] = rowprep->coefs[1];
16521  rowprep->coefs[1] = tmp1;
16522 
16523  tmp2 = rowprep->vars[0];
16524  rowprep->vars[0] = rowprep->vars[1];
16525  rowprep->vars[1] = tmp2;
16526  }
16527  break;
16528  }
16529 
16530  default :
16531  {
16532  SCIP_Real* abscoefs;
16533 
16534  SCIP_CALL( SCIPallocBufferArray(scip, &abscoefs, rowprep->nvars) );
16535  for( i = 0; i < rowprep->nvars; ++i )
16536  abscoefs[i] = REALABS(rowprep->coefs[i]);
16537  SCIPsortDownRealRealPtr(abscoefs, rowprep->coefs, (void**)rowprep->vars, rowprep->nvars);
16538  SCIPfreeBufferArray(scip, &abscoefs);
16539  }
16540  }
16541 
16542  /* forget about coefs that are exactly zero (unlikely to have some) */
16543  while( rowprep->nvars > 0 && rowprep->coefs[rowprep->nvars-1] == 0.0 )
16544  --rowprep->nvars;
16545 
16546  return SCIP_OKAY;
16547 }
16548 
16549 /** try to improve coef range by aggregating cut with variable bounds
16550  *
16551  * Assumes terms have been sorted by rowprepCleanupSortTerms().
16552  */
16553 static
16555  SCIP* scip, /**< SCIP data structure */
16556  SCIP_ROWPREP* rowprep, /**< rowprep to be improve */
16557  SCIP_SOL* sol, /**< solution that we try to cut off, or NULL for LP solution */
16558  SCIP_Real maxcoefrange /**< maximal allowed coefficients range */
16559  )
16560 {
16561  SCIP_VAR* var;
16562  SCIP_Real lb;
16563  SCIP_Real ub;
16564  SCIP_Real ref;
16565  SCIP_Real coef;
16566  SCIP_Real mincoef;
16567  SCIP_Real maxcoef;
16568  SCIP_Real loss[2];
16569  int maxcoefidx;
16570  int pos;
16571 
16572  maxcoefidx = 0;
16573  if( rowprep->nvars > 0 )
16574  {
16575  maxcoef = REALABS(rowprep->coefs[0]);
16576  mincoef = REALABS(rowprep->coefs[rowprep->nvars-1]);
16577  }
16578  else
16579  mincoef = maxcoef = 1.0;
16580 
16581  /* eliminate minimal or maximal coefs as long as coef range is too large
16582  * this is likely going to eliminate coefs that are within eps of 0.0
16583  * if not, then we do so after scaling (or should we enforce this here?)
16584  */
16585  while( maxcoef / mincoef > maxcoefrange )
16586  {
16587  SCIPdebugMsg(scip, "cut coefficients have very large range: mincoef = %g maxcoef = %g\n", mincoef, maxcoef);
16588 
16589  /* max/min can only be > 1 if there is more than one var
16590  * we need this below for updating the max/min coef after eliminating a term
16591  */
16592  assert(rowprep->nvars > 1);
16593 
16594  /* try to reduce coef range by aggregating with variable bounds
16595  * that is, eliminate a term like a*x from a*x + ... <= side by adding -a*x <= -a*lb(x)
16596  * with ref(x) the reference point we try to eliminate, this would weaken the cut by a*(lb(x)-ref(x))
16597  *
16598  * we consider eliminating either the term with maximal or the one with minimal coefficient,
16599  * taking the one that leads to the least weakening of the cut
16600  *
16601  * TODO (suggested by @bzfserra, see !496):
16602  * - Also one could think of not completely removing the coefficient but do an aggregation that makes the coefficient look better. For instance:
16603  * say you have $`a x + 0.1 y \leq r`$ and $`y`$ has only an upper bound, $`y \leq b`$,
16604  * then you can't really remove $`y`$. However, you could aggregate it with $`0.9 \cdot (y \leq b)`$ to get
16605  * $`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)
16606  */
16607 
16608  for( pos = 0; pos < 2; ++pos )
16609  {
16610  var = rowprep->vars[pos ? rowprep->nvars-1 : maxcoefidx];
16611  coef = rowprep->coefs[pos ? rowprep->nvars-1 : maxcoefidx];
16612  lb = SCIPvarGetLbLocal(var);
16613  ub = SCIPvarGetUbLocal(var);
16614  ref = SCIPgetSolVal(scip, sol, var);
16615  assert(coef != 0.0);
16616 
16617  /* make sure reference point is something reasonable within the bounds, preferable the value from the solution */
16618  if( SCIPisInfinity(scip, REALABS(ref)) )
16619  ref = 0.0;
16620  ref = MAX(lb, MIN(ub, ref));
16621 
16622  /* check whether we can eliminate coef*var from rowprep and how much we would loose w.r.t. ref(x) */
16623  if( ((coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT)) )
16624  {
16625  /* we would need to aggregate with -coef*var <= -coef*lb(x) */
16626  if( SCIPisInfinity(scip, -lb) )
16627  loss[pos] = SCIP_INVALID;
16628  else
16629  loss[pos] = REALABS(coef) * (ref - lb);
16630  }
16631  else
16632  {
16633  assert((coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT));
16634  /* we would need to aggregate with -coef*var >= -coef*ub(x) */
16635  if( SCIPisInfinity(scip, ub) )
16636  loss[pos] = SCIP_INVALID;
16637  else
16638  loss[pos] = REALABS(coef) * (ub - ref);
16639  }
16640  assert(loss[pos] >= 0.0); /* assuming SCIP_INVALID >= 0 */
16641 
16642  SCIPdebugMsg(scip, "aggregating %g*<%s> %c= ... with <%s>[%g] %c= %g looses %g\n",
16643  coef, SCIPvarGetName(var), rowprep->sidetype == SCIP_SIDETYPE_RIGHT ? '<' : '>',
16644  SCIPvarGetName(var), ref,
16645  ((coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT)) ? '>' : '<',
16646  ((coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT)) ? lb : ub, loss[pos]);
16647  }
16648 
16649  /*lint --e{777} */
16650  if( loss[0] == SCIP_INVALID && loss[1] == SCIP_INVALID )
16651  break; /* cannot eliminate coefficient */
16652 
16653  /* select position with smaller loss */
16654  pos = (loss[1] == SCIP_INVALID || loss[1] > loss[0]) ? 0 : 1;
16655 
16656  /* now do the actual elimination */
16657  var = rowprep->vars[pos ? rowprep->nvars-1 : maxcoefidx];
16658  coef = rowprep->coefs[pos ? rowprep->nvars-1 : maxcoefidx];
16659 
16660  /* eliminate coef*var from rowprep: increase side */
16661  if( ((coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT)) )
16662  {
16663  /* we aggregate with -coef*var <= -coef*lb(x) */
16664  assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
16665  SCIPaddRowprepConstant(rowprep, coef * SCIPvarGetLbLocal(var));
16666  rowprep->local |= SCIPisGT(scip, SCIPvarGetLbLocal(var), SCIPvarGetLbGlobal(var));
16667  }
16668  else
16669  {
16670  assert((coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT));
16671  /* we aggregate with -coef*var >= -coef*ub(x) */
16672  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
16673  SCIPaddRowprepConstant(rowprep, coef * SCIPvarGetUbLocal(var));
16674  rowprep->local |= SCIPisLT(scip, SCIPvarGetUbLocal(var), SCIPvarGetUbGlobal(var));
16675  }
16676 
16677  /* eliminate coef*var from rowprep: remove coef */
16678  if( pos == 0 )
16679  {
16680  /* set first term to zero */
16681  rowprep->coefs[maxcoefidx] = 0.0;
16682 
16683  /* update index */
16684  ++maxcoefidx;
16685 
16686  /* update maxcoef */
16687  maxcoef = REALABS(rowprep->coefs[maxcoefidx]);
16688  }
16689  else
16690  {
16691  /* forget last term */
16692  --rowprep->nvars;
16693 
16694  /* update mincoef */
16695  mincoef = REALABS(rowprep->coefs[rowprep->nvars-1]);
16696  }
16697  }
16698 
16699  /* if maximal coefs were removed, then there are now 0's in the beginning of the coefs array
16700  * -> move all remaining coefs and vars up front
16701  */
16702  if( maxcoefidx > 0 )
16703  {
16704  int i;
16705  for( i = maxcoefidx; i < rowprep->nvars; ++i )
16706  {
16707  rowprep->vars[i-maxcoefidx] = rowprep->vars[i];
16708  rowprep->coefs[i-maxcoefidx] = rowprep->coefs[i];
16709  }
16710  rowprep->nvars -= maxcoefidx;
16711  }
16712 }
16713 
16714 
16715 /** scales up rowprep if it seems useful */
16716 static
16718  SCIP* scip, /**< SCIP data structure */
16719  SCIP_ROWPREP* rowprep, /**< rowprep to be improve */
16720  SCIP_Real* viol, /**< violation of cut in sol (input and output) */
16721  SCIP_Real minviol /**< minimal violation we try to achieve */
16722  )
16723 {
16724  SCIP_Real scalefactor;
16725  SCIP_Real mincoef;
16726  SCIP_Real maxcoef;
16727 
16728  assert(scip != NULL);
16729  assert(rowprep != NULL);
16730  assert(viol != NULL);
16731 
16732  /* if violation is very small than better don't scale up */
16733  if( *viol < ROWPREP_SCALEUP_VIOLNONZERO )
16734  return;
16735 
16736  /* if violation is already above minviol, then nothing to do */
16737  if( *viol >= minviol )
16738  return;
16739 
16740  /* if violation is sufficiently positive (>10*eps), but has not reached minviol,
16741  * then consider scaling up to reach approx MINVIOLFACTOR*minviol
16742  */
16743  scalefactor = ROWPREP_SCALEUP_MINVIOLFACTOR * minviol / *viol;
16744 
16745  /* 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) */
16746  mincoef = rowprep->nvars > 0 ? REALABS(rowprep->coefs[rowprep->nvars-1]) : 1.0;
16747  maxcoef = rowprep->nvars > 0 ? REALABS(rowprep->coefs[0]) : 1.0;
16748  if( mincoef < ROWPREP_SCALEUP_MAXMINCOEF && scalefactor * maxcoef < ROWPREP_SCALEUP_MAXMAXCOEF && scalefactor * REALABS(rowprep->side) < ROWPREP_SCALEUP_MAXSIDE )
16749  {
16750  int scaleexp;
16751 
16752  /* SCIPinfoMessage(scip, NULL, "scale up by ~%g, viol=%g: ", scalefactor, myviol);
16753  SCIPprintRowprep(scip, rowprep, NULL); */
16754 
16755  /* SCIPscaleRowprep returns the actually applied scale factor */
16756  scaleexp = SCIPscaleRowprep(rowprep, scalefactor);
16757  *viol = ldexp(*viol, scaleexp);
16758 
16759  /* SCIPinfoMessage(scip, NULL, "scaled up by %g, viol=%g: ", ldexp(1.0, scaleexp), myviol);
16760  SCIPprintRowprep(scip, rowprep, NULL); */
16761  }
16762 }
16763 
16764 /** scales down rowprep if it improves coefs and keeps rowprep violated */
16765 static
16767  SCIP* scip, /**< SCIP data structure */
16768  SCIP_ROWPREP* rowprep, /**< rowprep to be improve */
16769  SCIP_Real* viol, /**< violation of cut in sol (input and output) */
16770  SCIP_Real minviol /**< minimal violation we try to keep */
16771  )
16772 {
16773  SCIP_Real scalefactor;
16774 
16775  /* if maxcoef < ROWPREP_SCALEDOWN_MINMAXCOEF (or no terms), then don't consider scaling down */
16776  if( rowprep->nvars == 0 || REALABS(rowprep->coefs[0]) < ROWPREP_SCALEDOWN_MINMAXCOEF )
16777  return;
16778 
16779  /* consider scaling down so that maxcoef ~ 10 */
16780  scalefactor = 10.0 / REALABS(rowprep->coefs[0]);
16781 
16782  /* if minimal violation would be lost by scaling down, then increase scalefactor such that minviol is still reached */
16783  if( *viol > minviol && scalefactor * *viol < minviol )
16784  {
16785  assert(minviol > 0.0); /* since viol >= 0, the if-condition should ensure that minviol > 0 */
16786  assert(*viol > 0.0); /* since minviol > 0, the if-condition ensures viol > 0 */
16787  scalefactor = ROWPREP_SCALEUP_MINVIOLFACTOR * minviol / *viol;
16788  }
16789 
16790  /* scale by approx. scalefactor if scaling down and minimal coef does not get too small
16791  * myviol < minviol (-> scalefactor > 1) or mincoef < feastol before scaling is possible, in which case we also don't scale down
16792  */
16793  if( scalefactor < 1.0 && scalefactor * REALABS(rowprep->coefs[rowprep->nvars-1]) > ROWPREP_SCALEDOWN_MINCOEF )
16794  {
16795  int scaleexp;
16796 
16797  /* SCIPinfoMessage(scip, NULL, "scale down by ~%g, viol=%g: ", scalefactor, myviol);
16798  SCIPprintRowprep(scip, rowprep, NULL); */
16799 
16800  scaleexp = SCIPscaleRowprep(rowprep, scalefactor);
16801  *viol = ldexp(*viol, scaleexp);
16802 
16803  /* SCIPinfoMessage(scip, NULL, "scaled down by %g, viol=%g: ", ldexp(1.0, scaleexp), myviol);
16804  SCIPprintRowprep(scip, rowprep, NULL); */
16805  }
16806 }
16807 
16808 /** rounds almost integral coefs to integrals, thereby trying to relax the cut */
16809 static
16811  SCIP* scip, /**< SCIP data structure */
16812  SCIP_ROWPREP* rowprep, /**< rowprep to be improve */
16813  SCIP_Real* viol /**< violation of cut in sol (input), set to SCIP_INVALID if some coef changed */
16814  )
16815 {
16816  SCIP_Real coef;
16817  SCIP_Real roundcoef;
16818  int i;
16819 
16820  assert(scip != NULL);
16821  assert(rowprep != NULL);
16822  assert(viol != NULL);
16823 
16824  /* Coefficients smaller than epsilon are rounded to 0.0 when added to row and
16825  * coefficients very close to integral values are rounded to integers when added to LP.
16826  * Both cases can be problematic if variable value is very large (bad numerics).
16827  * Thus, we anticipate by rounding coef here, but also modify constant so that cut is still valid (if possible),
16828  * i.e., bound coef[i]*x by round(coef[i])*x + (coef[i]-round(coef[i])) * bound(x).
16829  * Or in other words, we aggregate with the variable bound.
16830  *
16831  * If the required bound of x is not finite, then only round coef (introduces an error).
16832  * @TODO If only the opposite bound is available, then one could move the coefficient
16833  * away from the closest integer so that the SCIP_ROW won't try to round it.
16834  */
16835  for( i = 0; i < rowprep->nvars; ++i )
16836  {
16837  coef = rowprep->coefs[i];
16838  roundcoef = SCIPround(scip, coef);
16839  if( coef != roundcoef && SCIPisEQ(scip, coef, roundcoef) ) /*lint !e777*/
16840  {
16841  SCIP_Real xbnd;
16842  SCIP_VAR* var;
16843 
16844  var = rowprep->vars[i];
16845  if( rowprep->sidetype == SCIP_SIDETYPE_RIGHT )
16846  if( rowprep->local )
16847  xbnd = coef > roundcoef ? SCIPvarGetLbLocal(var) : SCIPvarGetUbLocal(var);
16848  else
16849  xbnd = coef > roundcoef ? SCIPvarGetLbGlobal(var) : SCIPvarGetUbGlobal(var);
16850  else
16851  if( rowprep->local )
16852  xbnd = coef > roundcoef ? SCIPvarGetUbLocal(var) : SCIPvarGetLbLocal(var);
16853  else
16854  xbnd = coef > roundcoef ? SCIPvarGetUbGlobal(var) : SCIPvarGetLbGlobal(var);
16855 
16856  if( !SCIPisInfinity(scip, REALABS(xbnd)) )
16857  {
16858  /* if there is a bound, then relax row side so rounding coef will not introduce an error */
16859  SCIPdebugMsg(scip, "var <%s> [%g,%g] has almost integral coef %.15g, round coefficient to %g and add constant %g\n",
16860  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), coef, roundcoef, (coef-roundcoef) * xbnd);
16861  SCIPaddRowprepConstant(rowprep, (coef-roundcoef) * xbnd);
16862  }
16863  else
16864  {
16865  /* if there is no bound, then we make the coef integral, too, even though this will introduce an error
16866  * however, SCIP_ROW would do this anyway, but doing this here might eliminate some epsilon coefs (so they don't determine mincoef below)
16867  * and helps to get a more accurate row violation value
16868  */
16869  SCIPdebugMsg(scip, "var <%s> [%g,%g] has almost integral coef %.15g, round coefficient to %g without relaxing side (!)\n",
16870  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), coef, roundcoef);
16871  }
16872  rowprep->coefs[i] = roundcoef;
16873  *viol = SCIP_INVALID;
16874  }
16875  }
16876 
16877  /* forget about coefs that became exactly zero by the above step */
16878  while( rowprep->nvars > 0 && rowprep->coefs[rowprep->nvars-1] == 0.0 )
16879  --rowprep->nvars;
16880 }
16881 
16882 /** relaxes almost zero side */
16883 static
16884 void rowprepCleanupSide(
16885  SCIP* scip, /**< SCIP data structure */
16886  SCIP_ROWPREP* rowprep, /**< rowprep to be improve */
16887  SCIP_Real* viol /**< violation of cut in sol (input), set to SCIP_INVALID if some coef changed */
16888  )
16889 {
16890  /* SCIP_ROW handling will replace a side close to 0 by 0.0, even if that makes the row more restrictive
16891  * we thus relax the side here so that it will either be 0 now or will not be rounded to 0 later
16892  */
16893  if( !SCIPisZero(scip, rowprep->side) )
16894  return;
16895 
16896  if( rowprep->side > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT )
16897  rowprep->side = 1.1*SCIPepsilon(scip);
16898  else if( rowprep->side < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT )
16899  rowprep->side = -1.1*SCIPepsilon(scip);
16900  else
16901  rowprep->side = 0.0;
16902 
16903  *viol = SCIP_INVALID;
16904 }
16905 
16906 /* Cleans up and attempts to improve rowprep
16907  *
16908  * Drops small or large coefficients if coefrange is too large, if this can be done by relaxing the cut.
16909  * Scales coefficients and side up to reach minimal violation, if possible.
16910  * Scaling is omitted if violation is very small (ROWPREP_SCALEUP_VIOLNONZERO) or
16911  * maximal coefficient would become huge (ROWPREP_SCALEUP_MAXMAXCOEF).
16912  * Scales coefficients and side down if they are large and if the minimal violation is still reached.
16913  * Rounds coefficients close to integral values to integrals, if this can be done by relaxing the cut.
16914  * Rounds side within epsilon of 0 to 0.0 or +/-1.1*epsilon, whichever relaxes the cut least.
16915  *
16916  * After return, the terms in the rowprep will be sorted by absolute value of coefficient, in decreasing order.
16917  */
16919  SCIP* scip, /**< SCIP data structure */
16920  SCIP_ROWPREP* rowprep, /**< rowprep to be cleaned */
16921  SCIP_SOL* sol, /**< solution that we try to cut off, or NULL for LP solution */
16922  SCIP_Real maxcoefrange, /**< maximal allowed coefficients range */
16923  SCIP_Real minviol, /**< minimal absolute violation the row should achieve (w.r.t. sol) */
16924  SCIP_Real* coefrange, /**< buffer to store coefrange of cleaned up cut, or NULL if not of interest */
16925  SCIP_Real* viol /**< buffer to store absolute violation of cleaned up cut in sol, or NULL if not of interest */
16926  )
16927 {
16928  SCIP_Real myviol;
16929 #ifdef SCIP_DEBUG
16930  SCIP_Real mincoef = 1.0;
16931  SCIP_Real maxcoef = 1.0;
16932 #endif
16933 
16934  assert(maxcoefrange > 1.0); /* not much interesting otherwise */
16935 
16936  /* sort term by absolute value of coef. */
16937  SCIP_CALL( rowprepCleanupSortTerms(scip, rowprep) );
16938 
16939 #ifdef SCIP_DEBUG
16940  if( rowprep->nvars > 0 )
16941  {
16942  maxcoef = REALABS(rowprep->coefs[0]);
16943  mincoef = REALABS(rowprep->coefs[rowprep->nvars-1]);
16944  }
16945 
16946  SCIPinfoMessage(scip, NULL, "starting cleanup, coefrange %g: ", maxcoef/mincoef);
16947  SCIPprintRowprep(scip, rowprep, NULL);
16948 #endif
16949 
16950  /* improve coefficient range by aggregating out variables */
16951  rowprepCleanupImproveCoefrange(scip, rowprep, sol, maxcoefrange);
16952 
16953  /* get current violation in sol */
16954  myviol = SCIPgetRowprepViolation(scip, rowprep, sol);
16955  assert(myviol >= 0.0);
16956 
16957 #ifdef SCIP_DEBUG
16958  if( rowprep->nvars > 0 )
16959  {
16960  maxcoef = REALABS(rowprep->coefs[0]);
16961  mincoef = REALABS(rowprep->coefs[rowprep->nvars-1]);
16962  }
16963 
16964  SCIPinfoMessage(scip, NULL, "improved coefrange to %g, viol %g: ", maxcoef / mincoef, myviol);
16965  SCIPprintRowprep(scip, rowprep, NULL);
16966 #endif
16967 
16968  /* if there is interest in achieving some minimal violation, then possibly scale up to increase violation, updates myviol */
16969  if( minviol > 0.0 )
16970  {
16971  /* first, try to achieve scip's minefficacy (typically 1e-4) */
16972  if( SCIPgetSepaMinEfficacy(scip) > minviol )
16973  rowprepCleanupScaleup(scip, rowprep, &myviol, SCIPgetSepaMinEfficacy(scip));
16974  /* in case scip minefficacy could not be reached or was smaller than minviol, try with the given minviol */
16975  rowprepCleanupScaleup(scip, rowprep, &myviol, minviol);
16976  }
16977 
16978  /* scale down to improve numerics, updates myviol */
16979  rowprepCleanupScaledown(scip, rowprep, &myviol, MAX(SCIPgetSepaMinEfficacy(scip), minviol)); /*lint !e666*/
16980 
16981 #ifdef SCIP_DEBUG
16982  SCIPinfoMessage(scip, NULL, "applied scaling, viol %g: ", myviol);
16983  SCIPprintRowprep(scip, rowprep, NULL);
16984 #endif
16985 
16986  /* turn almost-integral coefs to integral values, may set myviol to SCIP_INVALID */
16987  rowprepCleanupIntegralCoefs(scip, rowprep, &myviol);
16988 
16989  /* relax almost-zero side, may set myviol to SCIP_INVALID */
16990  rowprepCleanupSide(scip, rowprep, &myviol);
16991 
16992 #ifdef SCIP_DEBUG
16993  SCIPinfoMessage(scip, NULL, "adjusted almost-integral coefs and sides, viol %g: ", myviol);
16994  SCIPprintRowprep(scip, rowprep, NULL);
16995 #endif
16996 
16997  /* compute final coefrange, if requested by caller */
16998  if( coefrange != NULL )
16999  {
17000  if( rowprep->nvars > 0 )
17001  *coefrange = REALABS(rowprep->coefs[0]) / REALABS(rowprep->coefs[rowprep->nvars-1]);
17002  else
17003  *coefrange = 1.0;
17004  }
17005 
17006  /* If we updated myviol correctly, then it should coincide with freshly computed violation.
17007  * I leave this assert off for now, since getting the tolerance in the EQ correctly is not trivial. We recompute viol below anyway.
17008  */
17009  /* assert(myviol == SCIP_INVALID || SCIPisEQ(scip, myviol, SCIPgetRowprepViolation(scip, rowprep, sol))); */
17010 
17011  /* compute final violation, if requested by caller */
17012  if( viol != NULL ) /*lint --e{777} */
17013  *viol = myviol == SCIP_INVALID ? SCIPgetRowprepViolation(scip, rowprep, sol) : myviol;
17014 
17015  return SCIP_OKAY;
17016 }
17017 
17018 /** scales a rowprep
17019  *
17020  * @return Exponent of actually applied scaling factor, if written as 2^x.
17021  */
17022 int SCIPscaleRowprep(
17023  SCIP_ROWPREP* rowprep, /**< rowprep to be scaled */
17024  SCIP_Real factor /**< suggested scale factor */
17025  )
17026 {
17027  double v;
17028  int expon;
17029  int i;
17030 
17031  assert(rowprep != NULL);
17032  assert(factor > 0.0);
17033 
17034  /* write factor as v*2^expon with v in [0.5,1) */
17035  v = frexp(factor, &expon);
17036  /* adjust to v'*2^expon with v' in (0.5,1] by v'=v if v > 0.5, v'=1 if v=0.5 */
17037  if( v == 0.5 )
17038  --expon;
17039 
17040  /* multiply each coefficient by 2^expon */
17041  for( i = 0; i < rowprep->nvars; ++i )
17042  rowprep->coefs[i] = ldexp(rowprep->coefs[i], expon);
17043 
17044  /* multiply side by 2^expon */
17045  rowprep->side = ldexp(rowprep->side, expon);
17046 
17047  return expon;
17048 }
17049 
17050 /** generates a SCIP_ROW from a rowprep */
17052  SCIP* scip, /**< SCIP data structure */
17053  SCIP_ROW** row, /**< buffer to store pointer to new row */
17054  SCIP_ROWPREP* rowprep, /**< rowprep to be turned into a row */
17055  SCIP_CONSHDLR* conshdlr /**< constraint handler */
17056  )
17057 {
17058  assert(scip != NULL);
17059  assert(row != NULL);
17060  assert(rowprep != NULL);
17061  assert(conshdlr != NULL);
17062 
17063  SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, row, conshdlr, rowprep->name,
17064  rowprep->sidetype == SCIP_SIDETYPE_LEFT ? rowprep->side : -SCIPinfinity(scip),
17065  rowprep->sidetype == SCIP_SIDETYPE_RIGHT ? rowprep->side : SCIPinfinity(scip),
17066  rowprep->local && (SCIPgetDepth(scip) > 0), FALSE, TRUE) );
17067 
17068  SCIP_CALL( SCIPaddVarsToRow(scip, *row, rowprep->nvars, rowprep->vars, rowprep->coefs) );
17069 
17070  return SCIP_OKAY;
17071 }
17072 
17073 /** generates a SCIP_ROW from a rowprep */
17075  SCIP* scip, /**< SCIP data structure */
17076  SCIP_ROW** row, /**< buffer to store pointer to new row */
17077  SCIP_ROWPREP* rowprep, /**< rowprep to be turned into a row */
17078  SCIP_CONS* cons /**< constraint */
17079  )
17080 {
17081  assert(scip != NULL);
17082  assert(row != NULL);
17083  assert(rowprep != NULL);
17084  assert(cons != NULL);
17085 
17086  SCIP_CALL( SCIPcreateEmptyRowCons(scip, row, cons, rowprep->name,
17087  rowprep->sidetype == SCIP_SIDETYPE_LEFT ? rowprep->side : -SCIPinfinity(scip),
17088  rowprep->sidetype == SCIP_SIDETYPE_RIGHT ? rowprep->side : SCIPinfinity(scip),
17089  rowprep->local && (SCIPgetDepth(scip) > 0), FALSE, TRUE) );
17090 
17091  SCIP_CALL( SCIPaddVarsToRow(scip, *row, rowprep->nvars, rowprep->vars, rowprep->coefs) );
17092 
17093  return SCIP_OKAY;
17094 }
17095 
17096 /** generates a SCIP_ROW from a rowprep */
17098  SCIP* scip, /**< SCIP data structure */
17099  SCIP_ROW** row, /**< buffer to store pointer to new row */
17100  SCIP_ROWPREP* rowprep, /**< rowprep to be turned into a row */
17101  SCIP_SEPA* sepa /**< separator */
17102  )
17103 {
17104  assert(scip != NULL);
17105  assert(row != NULL);
17106  assert(rowprep != NULL);
17107 
17108  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, row, sepa, rowprep->name,
17109  rowprep->sidetype == SCIP_SIDETYPE_LEFT ? rowprep->side : -SCIPinfinity(scip),
17110  rowprep->sidetype == SCIP_SIDETYPE_RIGHT ? rowprep->side : SCIPinfinity(scip),
17111  rowprep->local && (SCIPgetDepth(scip) > 0), FALSE, TRUE) );
17112 
17113  SCIP_CALL( SCIPaddVarsToRow(scip, *row, rowprep->nvars, rowprep->vars, rowprep->coefs) );
17114 
17115  return SCIP_OKAY;
17116 }
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:52
SCIP_RETCODE SCIPupdateStartpointHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *solcand, SCIP_Real violation)
Definition: heur_subnlp.c:2502
static void rowprepCleanupImproveCoefrange(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Real maxcoefrange)
SCIP_Real SCIPgetPrimalRayVal(SCIP *scip, SCIP_VAR *var)
Definition: scip_sol.c:3553
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPround(SCIP *scip, SCIP_Real val)
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:97
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
void SCIPintervalDivScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
static SCIP_Bool conshdlrdataHasUpgrade(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), const char *conshdlrname)
SCIP_Real SCIPfeastol(SCIP *scip)
SCIP_EXPORT SCIP_Real SCIPvarGetBestBoundLocal(SCIP_VAR *var)
Definition: var.c:17748
#define ROWPREP_SCALEUP_VIOLNONZERO
SCIP_Bool SCIPisRelEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:86
static SCIP_RETCODE mergeAndCleanLinearVars(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcreateConsLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
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)
void SCIPintervalMulSup(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
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:5007
int SCIPgetNContVars(SCIP *scip)
Definition: scip_prob.c:2166
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)
static volatile int nterms
Definition: interrupt.c:38
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip_sol.c:977
SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
Definition: lp.c:17250
SCIP_Real SCIPdualfeastol(SCIP *scip)
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)
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_EXPORT SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:17154
static SCIP_RETCODE freeAllBilinearTerms(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **conss, int nconss)
SCIP_Real SCIPepsilon(SCIP *scip)
static SCIP_DECL_CONSENFOPS(consEnfopsQuadratic)
SCIP_RETCODE SCIPcreateChild(SCIP *scip, SCIP_NODE **node, SCIP_Real nodeselprio, SCIP_Real estimate)
Definition: scip_branch.c:1008
SCIP_Bool SCIPconsIsLockedType(SCIP_CONS *cons, SCIP_LOCKTYPE locktype)
Definition: cons.c:8482
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:251
#define ROWPREP_SCALEDOWN_MINCOEF
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:687
static void consdataMoveLinearVar(SCIP_CONSDATA *consdata, int oldpos, int newpos)
SCIP_RETCODE SCIPheurPassSolTrySol(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *sol)
Definition: heur_trysol.c:243
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)
SCIP_Bool SCIPconsIsEnabled(SCIP_CONS *cons)
Definition: cons.c:8186
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip_cons.c:586
SCIP_Bool SCIPintervalIsEmpty(SCIP_Real infinity, SCIP_INTERVAL operand)
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:80
static SCIP_RETCODE consdataSortBilinTerms(SCIP *scip, SCIP_CONSDATA *consdata)
primal heuristic that tries a given solution
SCIP_Bool SCIPhaveVarsCommonClique(SCIP *scip, SCIP_VAR *var1, SCIP_Bool value1, SCIP_VAR *var2, SCIP_Bool value2, SCIP_Bool regardimplics)
Definition: scip_var.c:7640
SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
Definition: scip_branch.c:656
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:877
SCIP_VAR * var2
const char * SCIPheurGetName(SCIP_HEUR *heur)
Definition: heur.c:1429
static void rowprepCleanupScaleup(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_Real *viol, SCIP_Real minviol)
public methods for SCIP parameter handling
SCIP_Real SCIPgetSepaMinEfficacy(SCIP *scip)
Definition: scip_sepa.c:298
#define MAXDNOM
SCIP_RETCODE SCIPgetViolationQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *violation)
#define SCIP_EVENTTYPE_VARFIXED
Definition: type_event.h:63
#define GAUGESCALE
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)
public methods for branch and bound tree
#define CONSHDLR_PRESOLTIMING
static SCIP_DECL_CONSSEPASOL(consSepasolQuadratic)
SCIP_RETCODE SCIPaddLinearCoefsToNlRow(SCIP *scip, SCIP_NLROW *nlrow, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip_nlp.c:1417
static SCIP_RETCODE consdataEnsureQuadVarTermsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num)
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip_cons.c:453
static SCIP_DECL_CONSINITSOL(consInitsolQuadratic)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
void SCIPfreeParseVarsPolynomialData(SCIP *scip, SCIP_VAR ****monomialvars, SCIP_Real ***monomialexps, SCIP_Real **monomialcoefs, int **monomialnvars, int nmonomials)
Definition: scip_var.c:1162
Constraint handler for variable bound constraints .
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_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5184
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_cons.c:934
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8328
SCIP_BILINTERM * SCIPgetBilinTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
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)
SCIP_EXPORT int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3250
public methods for memory management
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip_cons.c:308
#define ROWPREP_SCALEDOWN_MINMAXCOEF
SCIP_NLPI ** SCIPgetNlpis(SCIP *scip)
Definition: scip_nlp.c:119
int SCIPexprgraphGetNodeNChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12991
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition: scip_mem.h:113
SCIP_Real SCIPintervalNegateReal(SCIP_Real x)
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8288
SCIP_EXPORT SCIP_Bool SCIPsortedvecFindPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void *val, int len, int *pos)
SCIP_RETCODE SCIPmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1951
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_cons.c:166
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition: scip_var.c:4263
static SCIP_DECL_SORTINDCOMP(quadVarTermComp)
#define SCIP_MAXSTRLEN
Definition: def.h:273
static SCIP_RETCODE replaceQuadVarTermPos(SCIP *scip, SCIP_CONS *cons, int pos, SCIP_VAR *var, SCIP_Real coef, SCIP_Real offset)
#define CONSHDLR_DELAYPROP
SCIP_VAR * var1
SCIP_EVENTHDLR * SCIPfindEventhdlr(SCIP *scip, const char *name)
Definition: scip_event.c:225
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_nlp.c:1194
SCIP_RETCODE SCIPaddRowprepTerms(SCIP *scip, SCIP_ROWPREP *rowprep, int nvars, SCIP_VAR **vars, SCIP_Real *coefs)
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip_message.c:123
#define SCIPallocClearBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:84
static SCIP_RETCODE getImpliedBounds(SCIP *scip, SCIP_VAR *x, SCIP_Bool xval, SCIP_VAR *y, SCIP_INTERVAL *resultant)
SCIP_Bool SCIPisRelGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip_cons.c:816
SCIP_RETCODE SCIPaddSquareCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_EXPORT void SCIPsortDownIntInt(int *intarray1, int *intarray2, int len)
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]
#define INTERIOR_EPS
int SCIProwGetNNonz(SCIP_ROW *row)
Definition: lp.c:17062
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1218
static SCIP_DECL_CONSSEPALP(consSepalpQuadratic)
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1353
internal methods for NLPI solver interfaces
SCIP_RETCODE SCIPaddRowprepTerm(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_VAR *var, SCIP_Real coef)
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5301
SCIP_RETCODE SCIPcheckCurvatureQuadratic(SCIP *scip, SCIP_CONS *cons)
public solving methods
static SCIP_RETCODE lockLinearVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2152
SCIP_Bool local
static SCIP_RETCODE catchVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons)
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition: misc.c:9008
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip_cons.c:770
static void consdataUpdateLinearActivityUbChange(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real coef, SCIP_Real oldbnd, SCIP_Real newbnd)
static void checkCurvatureEasy(SCIP *scip, SCIP_CONS *cons, SCIP_HASHMAP *assumevarfixed, SCIP_Bool *determined, SCIP_Bool checkmultivariate, SCIP_Bool *isconvex, SCIP_Bool *isconcave, SCIP_Real *maxnonconvexity)
SCIP_Bool SCIPconsIsAdded(SCIP_CONS *cons)
Definition: cons.c:8518
static SCIP_RETCODE dropLinearVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons, int linvarpos)
static SCIP_RETCODE checkCurvatureExpensive(SCIP *scip, SCIP_CONS *cons, SCIP_HASHMAP *assumevarfixed, SCIP_Bool *isconvex, SCIP_Bool *isconcave, SCIP_Real *maxnonconvexity)
int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4594
static SCIP_RETCODE chgSideQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_EVENTHDLR *eventhdlr, SCIP_SIDETYPE side, SCIP_Real sideval)
static SCIP_RETCODE addQuadVarTerm(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real lincoef, SCIP_Real sqrcoef)
SCIP_RETCODE SCIPnlpiCreateProblem(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM **problem, const char *name)
Definition: nlpi.c:212
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3131
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_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition: scip_tree.c:81
SCIP_EXPORT SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:17192
static SCIP_DECL_NONLINCONSUPGD(nonlinconsUpgdQuadratic)
SCIP_EXPORT SCIP_VAR ** SCIPvarGetImplVars(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17957
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:1986
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8150
#define CONSHDLR_MAXPREROUNDS
void SCIPintervalSetRoundingMode(SCIP_ROUNDMODE roundmode)
SCIP_SIDETYPE sidetype
static SCIP_DECL_CONSEXITPRE(consExitpreQuadratic)
void SCIPaddConstantQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_Real constant)
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip_message.c:216
SCIP_RETCODE SCIPchgBilinCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Real coef)
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONS *cons, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1368
#define FALSE
Definition: def.h:73
#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)
SCIP_Real SCIPgetLhsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisRelGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE presolveSolve(SCIP *scip, SCIP_CONS *cons, SCIP_RESULT *result, SCIP_Bool *redundant, int *naggrvars)
SCIP_EXPORT SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17510
SCIP_QUADVARTERM * SCIPgetQuadVarTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisIpoptAvailableIpopt(void)
SCIP_EXPORT SCIP_HEUR * SCIPsolGetHeur(SCIP_SOL *sol)
Definition: sol.c:2604
void * SCIPhashmapEntryGetImage(SCIP_HASHMAPENTRY *entry)
Definition: misc.c:3509
#define CONSHDLR_SEPAPRIORITY
SCIP_EXPORT SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:17177
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
#define TRUE
Definition: def.h:72
#define SCIPdebug(x)
Definition: pub_message.h:84
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:54
static SCIP_RETCODE generateCutConvex(SCIP *scip, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_Real *ref, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
SCIP_Bool SCIPisRelLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition: type_timing.h:45
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3468
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8258
SCIP_Real SCIPgetRhsNonlinear(SCIP *scip, SCIP_CONS *cons)
static void consdataFindUnlockedLinearVar(SCIP *scip, SCIP_CONSDATA *consdata)
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip_cons.c:563
void SCIPintervalSetBounds(SCIP_INTERVAL *resultant, SCIP_Real inf, SCIP_Real sup)
SCIP_RETCODE SCIPgetRowprepRowConshdlr(SCIP *scip, SCIP_ROW **row, SCIP_ROWPREP *rowprep, SCIP_CONSHDLR *conshdlr)
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_EXPORT SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:17335
public methods for problem variables
static GRAPHNODE ** active
SCIP_Real SCIPadjustedVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real ub)
Definition: scip_var.c:4646
void SCIPswapReals(SCIP_Real *value1, SCIP_Real *value2)
Definition: misc.c:10205
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:48
static SCIP_RETCODE removeBilinearTermsPos(SCIP *scip, SCIP_CONS *cons, int nterms, int *termposs)
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:95
SCIP_EXPORT SCIP_Real * SCIPvarGetImplBounds(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17986
SCIP_EXPORT void SCIPsortPtrReal(void **ptrarray, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIPdebugMessage
Definition: pub_message.h:87
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)
static SCIP_RETCODE presolveTryAddAND(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *naddconss)
SCIP_EXPORT SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:17131
SCIP_RETCODE SCIPaddToNlpiProblemQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *nlpiprob, SCIP_HASHMAP *scipvar2nlpivar, SCIP_Bool names)
Constraint handler for AND constraints, .
static SCIP_RETCODE mergeAndCleanBilinearTerms(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPgetUpperbound(SCIP *scip)
SCIP_RETCODE SCIPchgSquareCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip_cons.c:525
SCIP_RETCODE SCIPnlpiSetRealPar(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem, SCIP_NLPPARAM type, SCIP_Real dval)
Definition: nlpi.c:672
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)
static SCIP_DECL_CONSENFOLP(consEnfolpQuadratic)
void SCIPaddSquareLinearization(SCIP *scip, SCIP_Real sqrcoef, SCIP_Real refpoint, SCIP_Bool isint, SCIP_Real *lincoef, SCIP_Real *linconstant, SCIP_Bool *success)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:123
SCIP_RETCODE SCIPsetConshdlrInit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINIT((*consinit)))
Definition: scip_cons.c:381
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip_cons.c:839
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:78
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:93
public methods for SCIP variables
static SCIP_RETCODE dropQuadVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons, int quadvarpos)
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip_cons.c:501
SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1182
#define SCIP_EVENTTYPE_BOUNDCHANGED
Definition: type_event.h:116
SCIP_RETCODE SCIPfindQuadVarTermQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, int *pos)
static SCIP_RETCODE registerBranchingCandidatesViolation(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, int *nnotify)
#define SCIPdebugMsgPrint
Definition: scip_message.h:70
#define ROWPREP_SCALEUP_MAXMAXCOEF
#define SCIPdebugMsg
Definition: scip_message.h:69
SCIP_RETCODE SCIPchgLinearCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_RETCODE SCIPcreateNLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip_sol.c:390
static void consdataUpdateLinearActivity(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real intervalinfty)
public methods for separator plugins
SCIP_RETCODE SCIPgetActivityQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *activity)
SCIP_VAR ** x
Definition: circlepacking.c:54
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4354
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip_lp.c:159
SCIP_EXPORT void SCIPsortInt(int *intarray, int len)
int SCIPgetNQuadVarTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE lockQuadraticVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
#define SCIP_PRESOLTIMING_FAST
Definition: type_timing.h:43
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip_cons.c:357
SCIP_RETCODE SCIPgetRowprepRowCons(SCIP *scip, SCIP_ROW **row, SCIP_ROWPREP *rowprep, SCIP_CONS *cons)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPgetNLPFracVars(SCIP *scip, SCIP_VAR ***fracvars, SCIP_Real **fracvarssol, SCIP_Real **fracvarsfrac, int *nfracvars, int *npriofracvars)
Definition: scip_nlp.c:739
int SCIPgetNIntVars(SCIP *scip)
Definition: scip_prob.c:2076
SCIP_RETCODE SCIPsortQuadVarTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPsolveNLP(SCIP *scip)
Definition: scip_nlp.c:596
public methods for numerical tolerances
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:301
SCIP_RETCODE SCIPaddQuadVarQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real lincoef, SCIP_Real sqrcoef)
static SCIP_RETCODE unlockQuadraticVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
Definition: scip_heur.c:249
SCIP_EXPORT SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition: var.c:17454
void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition: scip_sol.c:265
SCIP_Longint SCIPgetNLPs(SCIP *scip)
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)
public methods for expressions, expression trees, expression graphs, and related stuff ...
#define SCIP_EVENTTYPE_LBCHANGED
Definition: type_event.h:112
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2837
SCIP_RETCODE SCIPchgLhsQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_Real lhs)
public methods for querying solving statistics
SCIP_Bool SCIPconsIsLocked(SCIP_CONS *cons)
Definition: cons.c:8428
static SCIP_RETCODE generateCutNonConvex(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_Real *ref, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE registerBranchingCandidatesGap(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, int *nnotify)
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3220
public methods for the branch-and-bound tree
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_copy.c:697
SCIP_RETCODE SCIPaddQuadVarLinearCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_EXPROP SCIPexprgraphGetNodeOperator(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13051
static SCIP_RETCODE consdataSortQuadVarTerms(SCIP *scip, SCIP_CONSDATA *consdata)
SCIP_EXPORT SCIP_Bool SCIPvarIsInitial(SCIP_VAR *var)
Definition: var.c:17213
#define CONSHDLR_EAGERFREQ
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3362
SCIP_RETCODE SCIPcreateSolCopy(SCIP *scip, SCIP_SOL **sol, SCIP_SOL *sourcesol)
Definition: scip_sol.c:610
SCIP_RETCODE SCIPreleaseNlRow(SCIP *scip, SCIP_NLROW **nlrow)
Definition: scip_nlp.c:1302
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip_mem.h:92
SCIP_Real coef
Definition: type_expr.h:104
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)
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:269
public methods for managing constraints
#define SCIP_EVENTTYPE_SOLFOUND
Definition: type_event.h:135
void SCIPfreeRowprep(SCIP *scip, SCIP_ROWPREP **rowprep)
SCIP_Real inf
Definition: intervalarith.h:39
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_cons.c:2072
SCIP_HASHMAPENTRY * SCIPhashmapGetEntry(SCIP_HASHMAP *hashmap, int entryidx)
Definition: misc.c:3488
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:10898
static SCIP_RETCODE checkCurvature(SCIP *scip, SCIP_CONS *cons, SCIP_Bool checkmultivariate)
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)
SCIP_RETCODE SCIPsetConshdlrExit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXIT((*consexit)))
Definition: scip_cons.c:405
SCIP_EXPORT const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17012
SCIP_RETCODE SCIPcreateEmptyRowConshdlr(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_lp.c:1337
static SCIP_DECL_CONSEXIT(consExitQuadratic)
SCIP_RETCODE SCIPincludeConshdlrQuadratic(SCIP *scip)
struct SCIP_QuadVarEventData SCIP_QUADVAREVENTDATA
SCIP_Bool SCIPintervalIsEntire(SCIP_Real infinity, SCIP_INTERVAL operand)
static void getIneqViol(SCIP_VAR *x, SCIP_VAR *y, SCIP_Real xcoef, SCIP_Real ycoef, SCIP_Real constant, SCIP_Real *viol1, SCIP_Real *viol2)
SCIP_RETCODE LapackDsyev(SCIP_Bool computeeigenvectors, int N, SCIP_Real *a, SCIP_Real *w)
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)
SCIP_EXPORT SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:17203
SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
Definition: lp.c:17087
static SCIP_RETCODE addLinearizationCuts(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *ref, SCIP_Bool *separatedlpsol, SCIP_Real minefficacy)
#define SCIPerrorMessage
Definition: pub_message.h:55
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:10691
interval arithmetics for provable bounds
SCIP_Bool SCIPisConvexQuadratic(SCIP *scip, SCIP_CONS *cons)
void SCIPintervalSetEmpty(SCIP_INTERVAL *resultant)
SCIP_Real SCIPgetRowprepViolation(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol)
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:538
SCIP_RETCODE SCIPincSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real incval)
Definition: scip_sol.c:1310
SCIP_EXPORT int SCIPvarGetNImpls(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17940
SCIP_VAR ** vars
enum SCIP_NlpSolStat SCIP_NLPSOLSTAT
Definition: type_nlpi.h:69
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1508
public methods for event handler plugins and event handlers
SCIP_Real SCIPintervalGetInf(SCIP_INTERVAL interval)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPcatchEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:277
public methods for nonlinear functions
SCIP_Bool SCIPisInRestart(SCIP *scip)
Definition: scip_solve.c:3539
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)
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
Definition: scip_general.c:596
static SCIP_RETCODE computeViolation(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *solviolbounds)
SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITSOL((*consinitsol)))
Definition: scip_cons.c:429
static SCIP_DECL_CONSDELETE(consDeleteQuadratic)
SCIP_RETCODE SCIPsetConshdlrDisable(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDISABLE((*consdisable)))
Definition: scip_cons.c:724
static SCIP_DECL_CONSPARSE(consParseQuadratic)
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)
static SCIP_RETCODE catchQuadVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons, int quadvarpos)
SCIPInterval sqrt(const SCIPInterval &x)
SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
Definition: scip_var.c:1443
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip_mem.h:124
int SCIPhashmapGetNEntries(SCIP_HASHMAP *hashmap)
Definition: misc.c:3480
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:48
static SCIP_DECL_CONSCHECK(consCheckQuadratic)
SCIP_Real * SCIProwGetVals(SCIP_ROW *row)
Definition: lp.c:17097
SCIP_Bool SCIPnlrowIsInNLP(SCIP_NLROW *nlrow)
Definition: nlp.c:3439
#define SCIP_EVENTTYPE_IMPLADDED
Definition: type_event.h:76
static SCIP_DECL_CONSPRESOL(consPresolQuadratic)
void SCIPaddRowprepSide(SCIP_ROWPREP *rowprep, SCIP_Real side)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:164
SCIP_NLPSOLSTAT SCIPnlpiGetSolstat(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem)
Definition: nlpi.c:512
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:88
int SCIPnlrowGetNQuadElems(SCIP_NLROW *nlrow)
Definition: nlp.c:3329
static SCIP_DECL_CONSTRANS(consTransQuadratic)
constraint handler for quadratic constraints
SCIP_RETCODE SCIPcreateRowprep(SCIP *scip, SCIP_ROWPREP **rowprep, SCIP_SIDETYPE sidetype, SCIP_Bool local)
#define CONSHDLR_CHECKPRIORITY
#define NULL
Definition: lpi_spx1.cpp:155
static SCIP_RETCODE registerBranchingCandidates(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, int *nnotify)
#define REALABS(x)
Definition: def.h:187
public methods for problem copies
SCIP_Bool SCIPisRelLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
public methods for primal CIP solutions
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8119
#define SCIP_CALL(x)
Definition: def.h:364
SCIP_RETCODE SCIPaddBilinTermQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Real coef)
unsigned int SCIP_PRESOLTIMING
Definition: type_timing.h:52
#define CONSHDLR_ENFOPRIORITY
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:1021
SCIP_VAR * h
Definition: circlepacking.c:59
SCIP_Real SCIPeventGetNewbound(SCIP_EVENT *event)
Definition: event.c:1233
SCIP_Real sup
Definition: intervalarith.h:40
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)
SCIP_RETCODE SCIPchgRhsQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_Real rhs)
SCIP_RETCODE SCIPincludeQuadconsUpgrade(SCIP *scip, SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), int priority, SCIP_Bool active, const char *conshdlrname)
void SCIPintervalSet(SCIP_INTERVAL *resultant, SCIP_Real value)
SCIP_QUADELEM * SCIPnlrowGetQuadElems(SCIP_NLROW *nlrow)
Definition: nlp.c:3339
int SCIPgetLinvarMayIncreaseQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_VAR ** SCIPgetLinearVarsQuadratic(SCIP *scip, SCIP_CONS *cons)
static void rowprepCleanupScaledown(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_Real *viol, SCIP_Real minviol)
#define SCIPdebugGetSolVal(scip, var, val)
Definition: debug.h:257
static SCIP_RETCODE rowprepCleanupSortTerms(SCIP *scip, SCIP_ROWPREP *rowprep)
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:56
#define SCIP_EVENTTYPE_BOUNDTIGHTENED
Definition: type_event.h:114
public methods for primal heuristic plugins and divesets
#define SCIP_EVENTTYPE_UBCHANGED
Definition: type_event.h:113
public methods for constraint handler plugins and constraints
public methods for NLP management
static SCIP_RETCODE consdataEnsureAdjBilinSize(SCIP *scip, SCIP_QUADVARTERM *quadvarterm, int num)
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1749
static SCIP_RETCODE proposeFeasibleSolution(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool *success)
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8358
SCIP_Real SCIPexprgraphGetNodeQuadraticConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13154
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
int SCIPgetNLinearVarsNonlinear(SCIP *scip, SCIP_CONS *cons)
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_mem.h:111
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:130
SCIP_Real SCIPinfinity(SCIP *scip)
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_cons.c:220
public data structures and miscellaneous methods
#define CONSHDLR_NEEDSCONS
SCIP_Real SCIPeventGetOldbound(SCIP_EVENT *event)
Definition: event.c:1209
static unsigned int nextPowerOf2(unsigned int v)
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4439
SCIP_Real SCIPgetLPFeastol(SCIP *scip)
Definition: scip_lp.c:419
static SCIP_DECL_CONSINITLP(consInitlpQuadratic)
SCIP_Real side
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:638
#define SCIP_Bool
Definition: def.h:70
static SCIP_DECL_CONSFREE(consFreeQuadratic)
SCIP_RETCODE SCIPgetFeasibilityQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *feasibility)
static SCIP_RETCODE presolveDisaggregate(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *naddconss)
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:391
SCIP_Bool SCIPexprgraphAreAllNodeChildrenVars(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14655
static void rowprepCleanupIntegralCoefs(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_Real *viol)
void SCIPintervalSolveUnivariateQuadExpression(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL rhs, SCIP_INTERVAL xbnds)
#define CONSHDLR_DELAYSEPA
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyQuadratic)
SCIP_EXPORT SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
Definition: var.c:17466
static SCIP_RETCODE registerBranchingCandidatesCentrality(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, int *nnotify)
SCIP_Bool SCIPisSumLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
const char * SCIPgetProbName(SCIP *scip)
Definition: scip_prob.c:1065
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3013
SCIP_EXPORT void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
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 SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip_cons.c:332
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition: scip_nlp.c:210
static const char * paramname[]
Definition: lpi_msk.c:4958
int SCIPgetNNlpis(SCIP *scip)
Definition: scip_nlp.c:132
SCIP_EXPORT SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17672
#define NONLINCONSUPGD_PRIORITY
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip_cons.c:2473
constraint handler for nonlinear constraints
SCIP_EXPORT SCIP_BOUNDTYPE SCIPvarGetBestBoundType(SCIP_VAR *var)
Definition: var.c:17774
SCIP_NLPSOLSTAT SCIPgetNLPSolstat(SCIP *scip)
Definition: scip_nlp.c:619
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)
void SCIPmergeRowprepTerms(SCIP *scip, SCIP_ROWPREP *rowprep)
SCIP_RETCODE SCIPnlpiSetIntPar(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem, SCIP_NLPPARAM type, int ival)
Definition: nlpi.c:637
SCIP_EXPORT SCIP_Real SCIPvarGetWorstBoundLocal(SCIP_VAR *var)
Definition: var.c:17761
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4199
#define MAX(x, y)
Definition: tclique_def.h:83
SCIP_RETCODE SCIPcreateLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip_sol.c:362
SCIP_Bool SCIPisCutApplicable(SCIP *scip, SCIP_ROW *cut)
Definition: scip_cut.c:178
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 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_var.c:105
SCIP_EXPORT SCIP_Bool SCIPvarIsOriginal(SCIP_VAR *var)
Definition: var.c:17141
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:17141
methods for debugging
public methods for LP management
static SCIP_RETCODE generateCutLTI(SCIP *scip, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_Real *ref, SCIP_SOL *sol, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
static void consdataSortLinearVars(SCIP_CONSDATA *consdata)
void SCIPsort(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
Definition: misc.c:5439
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8398
public methods for cuts and aggregation rows
void SCIPintervalAdd(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_RETCODE SCIPnlpiSolve(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem)
Definition: nlpi.c:498
SCIP_Real SCIPgetLhsNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_EXPORT SCIP_Real SCIPnodeGetEstimate(SCIP_NODE *node)
Definition: tree.c:7450
SCIP_Real SCIPintervalGetSup(SCIP_INTERVAL interval)
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:126
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8268
#define ROWPREP_SCALEUP_MAXSIDE
static SCIP_Real getInteriority(SCIP *scip, SCIP_Real lbx, SCIP_Real ubx, SCIP_Real refx, SCIP_Real lby, SCIP_Real uby, SCIP_Real refy)
#define infty2infty(infty1, infty2, val)
int SCIPgetNSepaRounds(SCIP *scip)
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_Real * SCIPgetLinearCoefsNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_prob.c:1666
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define CONSHDLR_NAME
#define BMSclearMemory(ptr)
Definition: memory.h:121
#define SCIP_EVENTTYPE_GBDCHANGED
Definition: type_event.h:111
static SCIP_Bool consdataCheckBilinTermsSort(SCIP_CONSDATA *consdata)
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8348
char name[SCIP_MAXSTRLEN]
SCIP_EXPORT SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17718
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip_event.c:95
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:130
SCIP_RETCODE SCIPunmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1979
void * SCIPexprgraphGetNodeVar(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13083
SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
Definition: lp.c:16901
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)
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)
public methods for the LP relaxation, rows and columns
SCIP_Real * SCIPexprgraphGetNodeQuadraticLinearCoefs(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13166
#define ROWPREP_SCALEUP_MINVIOLFACTOR
SCIP_Bool SCIPisConcaveQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPaddLinearConsToNlpHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_Bool addcombconss, SCIP_Bool addcontconss)
Definition: heur_subnlp.c:2468
SCIP_EXPORT int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3193
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_var.c:810
public methods for nonlinear relaxations
SCIP_EXPORT void SCIPsortDownRealRealPtr(SCIP_Real *realarray1, SCIP_Real *realarray2, void **ptrarray, int len)
SCIP_Bool SCIPinDive(SCIP *scip)
Definition: scip_lp.c:2715
SCIP_RETCODE SCIPaddLinearVarQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
static SCIP_RETCODE registerLargeRelaxValueVariableForBranching(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_VAR **brvar)
SCIP_EXPORT SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17728
methods for sorting joint arrays of various types
SCIP_QUADVAREVENTDATA * eventdata
enum SCIP_ExprCurv SCIP_EXPRCURV
Definition: type_expr.h:95
int SCIPgetNAllBilinearTermsQuadratic(SCIP *scip)
public methods for branching rule plugins and branching
SCIP_VAR ** b
Definition: circlepacking.c:56
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:221
public methods for managing events
static SCIP_RETCODE addBilinearTerm(SCIP *scip, SCIP_CONS *cons, int var1pos, int var2pos, SCIP_Real coef)
general public methods
static void consdataMoveQuadVarTerm(SCIP_CONSDATA *consdata, int oldpos, int newpos)
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_RETCODE SCIPincludeNonlinconsUpgrade(SCIP *scip, SCIP_DECL_NONLINCONSUPGD((*nonlinconsupgd)), SCIP_DECL_EXPRGRAPHNODEREFORM((*nodereform)), int priority, SCIP_Bool active, const char *conshdlrname)
public methods for solutions
#define CONSHDLR_DESC
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8278
SCIP_Real SCIPintervalQuadUpperBound(SCIP_Real infinity, SCIP_Real a, SCIP_INTERVAL b_, SCIP_INTERVAL x)
SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
static SCIP_RETCODE dropVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons)
SCIP_RETCODE SCIPdropEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:311
static SCIP_DECL_CONSGETVARS(consGetVarsQuadratic)
#define SCIP_EVENTTYPE_FORMAT
Definition: type_event.h:143
SCIP_Bool SCIPisLinearLocalQuadratic(SCIP *scip, SCIP_CONS *cons)
int SCIPgetNLinearVarsQuadratic(SCIP *scip, SCIP_CONS *cons)
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_EXPORT SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17662
public methods for the probing mode
SCIP_EXPRGRAPH * SCIPgetExprgraphNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr)
static void rowprepCleanupSide(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_Real *viol)
static SCIP_DECL_CONSCOPY(consCopyQuadratic)
static SCIP_DECL_CONSINIT(consInitQuadratic)
void SCIPenableNLP(SCIP *scip)
Definition: scip_nlp.c:195
static SCIP_RETCODE unlockLinearVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_EXPORT int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition: var.c:17430
void SCIPintervalSetRoundingModeUpwards(void)
SCIP_RETCODE SCIPnlpiFreeProblem(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM **problem)
Definition: nlpi.c:225
type definitions for expressions and expression trees
static SCIP_RETCODE computeReferencePointProjection(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *refsol, SCIP_Real *ref)
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4551
int SCIPgetNBilinTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPisConvexConsQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_HASHMAP *assumevarfixed, SCIP_Bool *result)
public methods for message output
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)
SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1483
SCIP_VAR * a
Definition: circlepacking.c:57
int SCIPscaleRowprep(SCIP_ROWPREP *rowprep, SCIP_Real factor)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10590
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:74
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:3047
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8089
SCIP_RETCODE SCIPaddBilinearIneqQuadratic(SCIP *scip, SCIP_VAR *x, SCIP_VAR *y, int idx, SCIP_Real xcoef, SCIP_Real ycoef, SCIP_Real constant, SCIP_Bool *success)
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1252
SCIP_Real SCIPselectSimpleValue(SCIP_Real lb, SCIP_Real ub, SCIP_Longint maxdnom)
Definition: misc.c:9705
#define SCIP_Real
Definition: def.h:163
void SCIPintervalMulScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
SCIP_VAR ** y
Definition: circlepacking.c:55
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8109
static SCIP_RETCODE computeReferencePointGauge(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *refsol, SCIP_Real *ref, SCIP_Bool *success)
const char * SCIProwGetName(SCIP_ROW *row)
Definition: lp.c:17200
SCIP_Real SCIPgetRhsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
public methods for message handling
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE checkFactorable(SCIP *scip, SCIP_CONS *cons)
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13001
#define SCIP_INVALID
Definition: def.h:183
SCIP_Real SCIPgetRowLPFeasibility(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1950
SCIP_EXPRGRAPHNODE * SCIPgetExprgraphNodeNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPaddNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition: scip_nlp.c:461
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_var.c:395
SCIP_Bool SCIPhasPrimalRay(SCIP *scip)
Definition: scip_sol.c:3535
static SCIP_RETCODE propagateBoundsTightenVarLb(SCIP *scip, SCIP_CONS *cons, SCIP_Real intervalinfty, SCIP_VAR *var, SCIP_Real bnd, SCIP_RESULT *result, int *nchgbds)
SCIP_EXPORT SCIP_BOUNDTYPE * SCIPvarGetImplTypes(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17972
SCIP_VAR ** SCIPnlrowGetQuadVars(SCIP_NLROW *nlrow)
Definition: nlp.c:3292
static SCIP_RETCODE delLinearCoefPos(SCIP *scip, SCIP_CONS *cons, int pos)
#define SCIP_Longint
Definition: def.h:148
static SCIP_RETCODE consdataEnsureBilinSize(SCIP *scip, SCIP_CONSDATA *consdata, int num)
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8368
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4179
SCIP_NLPTERMSTAT SCIPnlpiGetTermstat(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem)
Definition: nlpi.c:524
#define SCIPdebugAddSolVal(scip, var, val)
Definition: debug.h:256
static SCIP_RETCODE removeFixedVariables(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons)
int SCIPgetNBinVars(SCIP *scip)
Definition: scip_prob.c:2031
SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: scip_var.c:1798
static SCIP_DECL_CONSLOCK(consLockQuadratic)
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:345
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)
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_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:1044
SCIP_Real ineqoverest[6]
SCIP_Bool SCIPconsIsOriginal(SCIP_CONS *cons)
Definition: cons.c:8388
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2764
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition: scip_cut.c:332
SCIP_Real * SCIPgetCoefsLinearVarsQuadratic(SCIP *scip, SCIP_CONS *cons)
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:55
static SCIP_DECL_EVENTEXEC(processVarEvent)
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:98
SCIP_EXPORT void SCIPsortPtrPtrReal(void **ptrarray1, void **ptrarray2, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
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)
#define CONSHDLR_PROP_TIMING
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:17151
#define SCIP_DECL_QUADCONSUPGD(x)
static SCIP_DECL_CONSPROP(consPropQuadratic)
SCIP_Real * coefs
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 delQuadVarTermPos(SCIP *scip, SCIP_CONS *cons, int pos)
SCIP_RETCODE SCIPaddConsLocal(SCIP *scip, SCIP_CONS *cons, SCIP_NODE *validnode)
Definition: scip_prob.c:3387
static SCIP_DECL_CONSPRINT(consPrintQuadratic)
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:122
SCIP_Bool SCIPconsIsMarkedPropagate(SCIP_CONS *cons)
Definition: cons.c:8298
public methods for primal heuristics
#define ROWPREP_SCALEUP_MAXMINCOEF
SCIP_RETCODE SCIPaddVarsToRow(SCIP *scip, SCIP_ROW *row, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip_lp.c:1667
#define CONSHDLR_SEPAFREQ
static SCIP_RETCODE computeED(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons)
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:199
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:13190
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1110
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_var.c:8380
SCIP_RETCODE SCIPchgVarType(SCIP *scip, SCIP_VAR *var, SCIP_VARTYPE vartype, SCIP_Bool *infeasible)
Definition: scip_var.c:8155
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:356
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 SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip_cons.c:793
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)
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip_cons.c:266
SCIP_EXPORT SCIP_Bool SCIPvarIsRemovable(SCIP_VAR *var)
Definition: var.c:17223
#define SCIPABORT()
Definition: def.h:336
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)
public methods for global and local (sub)problems
void SCIPmarkRowNotRemovableLocal(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1808
SCIP_Real SCIPadjustedVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real lb)
Definition: scip_var.c:4614
int SCIPgetLinvarMayDecreaseQuadratic(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE consdataFindQuadVarTerm(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR *var, int *pos)
SCIP_ROUNDMODE SCIPintervalGetRoundingMode(void)
SCIP_RETCODE SCIPsetConshdlrEnable(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENABLE((*consenable)))
Definition: scip_cons.c:701
SCIP_RETCODE SCIPgetRowprepRowSepa(SCIP *scip, SCIP_ROW **row, SCIP_ROWPREP *rowprep, SCIP_SEPA *sepa)
static SCIP_RETCODE mergeAndCleanQuadVarTerms(SCIP *scip, SCIP_CONS *cons)
SCIP_VAR ** SCIPgetLinearVarsNonlinear(SCIP *scip, SCIP_CONS *cons)
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_param.c:158
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8308
int SCIPgetSubscipDepth(SCIP *scip)
Definition: scip_copy.c:2548
void SCIPhashmapEntrySetImage(SCIP_HASHMAPENTRY *entry, void *image)
Definition: misc.c:3539
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)
#define SCIPduplicateBlockMemory(scip, ptr, source)
Definition: scip_mem.h:90
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)
static SCIP_RETCODE computeViolations(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool *solviolbounds, SCIP_CONS **maxviolcon)
SCIP_RETCODE SCIPsetNLPInitialGuessSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip_nlp.c:564
SCIP_EXPORT SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
Definition: var.c:17442
SCIP_SOL * SCIPeventGetSol(SCIP_EVENT *event)
Definition: event.c:1328
static SCIP_DECL_CONSDISABLE(consDisableQuadratic)
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip_cons.c:609
static SCIP_Bool hasQuadvarHpProperty(SCIP *scip, SCIP_CONSDATA *consdata, int idx)
SCIP_Bool SCIPintervalIsSubsetEQ(SCIP_Real infinity, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
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)
static SCIP_RETCODE catchLinearVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons, int linvarpos)
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_lp.c:1399
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8338
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
SCIP_EXPORT int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11708
SCIP_RETCODE SCIPgetNlRowQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_NLROW **nlrow)
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:115
uint64_t SCIP_EVENTTYPE
Definition: type_event.h:142
void SCIPaddRowprepConstant(SCIP_ROWPREP *rowprep, SCIP_Real constant)
static SCIP_RETCODE generateCutUnboundedLP(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_ROW **row, SCIP_Real *rowrayprod, SCIP_Bool checkcurvmultivar)
SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1436
void SCIPintervalQuad(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_Real sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL xrng)
memory allocation routines
enum SCIP_SideType SCIP_SIDETYPE
Definition: type_lp.h:58
SCIP_QUADELEM * SCIPexprgraphGetNodeQuadraticQuadElements(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13178