Scippy

SCIP

Solving Constraint Integer Programs

cons_quadratic.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2018 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not visit scip.zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file cons_quadratic.c
17  * @brief constraint handler for quadratic constraints \f$\textrm{lhs} \leq \sum_{i,j=1}^n a_{i,j} x_i x_j + \sum_{i=1}^n b_i x_i \leq \textrm{rhs}\f$
18  * @author Stefan Vigerske
19  * @author Benjamin Mueller
20  * @author Felipe Serrano
21  *
22  * @todo SCIP might fix linear variables on +/- infinity; remove them in presolve and take care later
23  * @todo round constraint sides to integers if all coefficients and variables are (impl.) integer
24  * @todo constraints in one variable should be replaced by linear or bounddisjunction constraint
25  * @todo check if some quadratic terms appear in several constraints and try to simplify (e.g., nous1)
26  * @todo skip separation in enfolp if for current LP (check LP id) was already separated
27  * @todo watch unbounded variables to enable/disable propagation
28  * @todo sort order in bilinvar1/bilinvar2 such that the var which is involved in more terms is in bilinvar1, and use this info propagate and AddLinearReform
29  * @todo underestimate for multivariate concave quadratic terms as in cons_nonlinear
30  */
31 
32 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
33 
34 #define SCIP_PRIVATE_ROWPREP
35 
36 #include "blockmemshell/memory.h"
37 #include <ctype.h>
38 #include "nlpi/nlpi.h"
39 #include "nlpi/nlpi_ipopt.h"
40 #include "nlpi/pub_expr.h"
41 #include "nlpi/type_expr.h"
42 #include "scip/cons_and.h"
44 #include "scip/cons_linear.h"
45 #include "scip/cons_nonlinear.h"
46 #include "scip/cons_quadratic.h"
47 #include "scip/cons_varbound.h"
48 #include "scip/debug.h"
49 #include "scip/heur_subnlp.h"
50 #include "scip/heur_trysol.h"
51 #include "scip/intervalarith.h"
52 #include "scip/pub_cons.h"
53 #include "scip/pub_event.h"
54 #include "scip/pub_heur.h"
55 #include "scip/pub_lp.h"
56 #include "scip/pub_message.h"
57 #include "scip/pub_misc.h"
58 #include "scip/pub_misc_sort.h"
59 #include "scip/pub_nlp.h"
60 #include "scip/pub_sol.h"
61 #include "scip/pub_tree.h"
62 #include "scip/pub_var.h"
63 #include "scip/scip_branch.h"
64 #include "scip/scip_cons.h"
65 #include "scip/scip_copy.h"
66 #include "scip/scip_cut.h"
67 #include "scip/scip_event.h"
68 #include "scip/scip_general.h"
69 #include "scip/scip_heur.h"
70 #include "scip/scip_lp.h"
71 #include "scip/scip_mem.h"
72 #include "scip/scip_message.h"
73 #include "scip/scip_nlp.h"
74 #include "scip/scip_nonlinear.h"
75 #include "scip/scip_numerics.h"
76 #include "scip/scip_param.h"
77 #include "scip/scip_prob.h"
78 #include "scip/scip_probing.h"
79 #include "scip/scip_sepa.h"
80 #include "scip/scip_sol.h"
81 #include "scip/scip_solve.h"
82 #include "scip/scip_solvingstats.h"
83 #include "scip/scip_tree.h"
84 #include "scip/scip_var.h"
85 #include <string.h>
86 
87 /* constraint handler properties */
88 #define CONSHDLR_NAME "quadratic"
89 #define CONSHDLR_DESC "quadratic constraints of the form lhs <= b' x + x' A x <= rhs"
90 #define CONSHDLR_SEPAPRIORITY 10 /**< priority of the constraint handler for separation */
91 #define CONSHDLR_ENFOPRIORITY -50 /**< priority of the constraint handler for constraint enforcing */
92 #define CONSHDLR_CHECKPRIORITY -4000000 /**< priority of the constraint handler for checking feasibility */
93 #define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
94 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
95 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
96  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
97 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
98 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
99 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
100 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
102 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP /**< propagation timing mask of the constraint handler */
103 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS /**< presolving timing of the constraint handler (fast, medium, or exhaustive) */
105 #define MAXDNOM 10000LL /**< maximal denominator for simple rational fixed values */
106 #define NONLINCONSUPGD_PRIORITY 40000 /**< priority of upgrading nonlinear constraints */
107 #define INITLPMAXVARVAL 1000.0 /**< maximal absolute value of variable for still generating a linearization cut at that point in initlp */
109 /* Activating this define enables reformulation of bilinear terms x*y with implications from x to y into linear terms.
110  * 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,
111  * then the implication may not be enforced in a solution.
112  * This issue need to be fixed before this feature can be enabled.
113  */
114 /* #define CHECKIMPLINBILINEAR */
115 
116 /* enable new propagation for bivariate quadratic terms */
117 #define PROPBILINNEW
119 /* epsilon for differentiating between a boundary and interior point */
120 #define INTERIOR_EPS 1e-1
122 /* scaling factor for gauge function */
123 #define GAUGESCALE 0.99999
125 #define ROWPREP_SCALEUP_VIOLNONZERO (10.0*SCIPepsilon(scip)) /**< minimal violation for considering up-scaling of rowprep (we want to avoid upscaling very small violations) */
126 #define ROWPREP_SCALEUP_MINVIOLFACTOR 2.0 /**< scale up will target a violation of ~MINVIOLFACTOR*minviol, where minviol is given by caller */
127 #define ROWPREP_SCALEUP_MAXMINCOEF (1.0 / SCIPfeastol(scip)) /**< scale up only if min. coef is below this number (before scaling) */
128 #define ROWPREP_SCALEUP_MAXMAXCOEF SCIPgetHugeValue(scip) /**< scale up only if max. coef will not exceed this number by scaling */
129 #define ROWPREP_SCALEUP_MAXSIDE SCIPgetHugeValue(scip) /**< scale up only if side will not exceed this number by scaling */
130 #define ROWPREP_SCALEDOWN_MINMAXCOEF (1.0 / SCIPfeastol(scip)) /**< scale down if max. coef is at least this number (before scaling) */
131 #define ROWPREP_SCALEDOWN_MINCOEF SCIPfeastol(scip) /**< scale down only if min. coef does not drop below this number by scaling */
133 /*
134  * Data structures
135  */
136 
137 /** eventdata for variable bound change events in quadratic constraints */
138 struct SCIP_QuadVarEventData
139 {
140  SCIP_CONS* cons; /**< the constraint */
141  int varidx; /**< the index of the variable which bound change is caught, positive for linear variables, negative for quadratic variables */
142  int filterpos; /**< position of eventdata in SCIP's event filter */
143 };
144 
145 /** Data of a quadratic constraint. */
146 struct SCIP_ConsData
147 {
148  SCIP_Real lhs; /**< left hand side of constraint */
149  SCIP_Real rhs; /**< right hand side of constraint */
150 
151  int nlinvars; /**< number of linear variables */
152  int linvarssize; /**< length of linear variable arrays */
153  SCIP_VAR** linvars; /**< linear variables */
154  SCIP_Real* lincoefs; /**< coefficients of linear variables */
155  SCIP_QUADVAREVENTDATA** lineventdata; /**< eventdata for bound change of linear variable */
156 
157  int nquadvars; /**< number of variables in quadratic terms */
158  int quadvarssize; /**< length of quadratic variable terms arrays */
159  SCIP_QUADVARTERM* quadvarterms; /**< array with quadratic variable terms */
160 
161  int nbilinterms; /**< number of bilinear terms */
162  int bilintermssize; /**< length of bilinear term arrays */
163  SCIP_BILINTERM* bilinterms; /**< bilinear terms array */
164  int* bilintermsidx; /**< unique index of each bilinear term xy in the bilinestimators array of the constraint handler data */
165 
166  SCIP_NLROW* nlrow; /**< a nonlinear row representation of this constraint */
167 
168  unsigned int linvarssorted:1; /**< are the linear variables already sorted? */
169  unsigned int linvarsmerged:1; /**< are equal linear variables already merged? */
170  unsigned int quadvarssorted:1; /**< are the quadratic variables already sorted? */
171  unsigned int quadvarsmerged:1; /**< are equal quadratic variables already merged? */
172  unsigned int bilinsorted:1; /**< are the bilinear terms already sorted? */
173  unsigned int bilinmerged:1; /**< are equal bilinear terms (and bilinear terms with zero coefficient) already merged? */
174 
175  unsigned int isconvex:1; /**< is quadratic function is convex ? */
176  unsigned int isconcave:1; /**< is quadratic function is concave ? */
177  unsigned int iscurvchecked:1; /**< is quadratic function checked on convexity or concavity ? */
178  unsigned int isremovedfixings:1; /**< did we removed fixed/aggr/multiaggr variables ? */
179  unsigned int ispropagated:1; /**< was the constraint propagated with respect to the current bounds ? */
180  unsigned int ispresolved:1; /**< did we checked for possibilities of upgrading or implicit integer variables ? */
181  unsigned int initialmerge:1; /**< did we perform an initial merge and clean in presolving yet ? */
182 #ifdef CHECKIMPLINBILINEAR
183  unsigned int isimpladded:1; /**< has there been an implication added for a binary variable in a bilinear term? */
184 #endif
185  unsigned int isgaugeavailable:1; /**< is the gauge function computed? */
186  unsigned int isedavailable:1; /**< is the eigen decomposition of A available? */
187 
188  SCIP_Real minlinactivity; /**< sum of minimal activities of all linear terms with finite minimal activity */
189  SCIP_Real maxlinactivity; /**< sum of maximal activities of all linear terms with finite maximal activity */
190  int minlinactivityinf; /**< number of linear terms with infinite minimal activity */
191  int maxlinactivityinf; /**< number of linear terms with infinity maximal activity */
192  SCIP_INTERVAL quadactivitybounds; /**< bounds on the activity of the quadratic term, if up to date, otherwise empty interval */
193  SCIP_Real activity; /**< activity of quadratic function w.r.t. current solution */
194  SCIP_Real lhsviol; /**< violation of lower bound by current solution (used temporarily inside constraint handler) */
195  SCIP_Real rhsviol; /**< violation of lower bound by current solution (used temporarily inside constraint handler) */
196 
197  int linvar_maydecrease; /**< index of a variable in linvars that may be decreased without making any other constraint infeasible, or -1 if none */
198  int linvar_mayincrease; /**< index of a variable in linvars that may be increased without making any other constraint infeasible, or -1 if none */
199 
200  SCIP_VAR** sepaquadvars; /**< variables corresponding to quadvarterms to use in separation, only available in solving stage */
201  int* sepabilinvar2pos; /**< position of second variable in bilinear terms to use in separation, only available in solving stage */
202  SCIP_Real lincoefsmin; /**< minimal absolute value of coefficients in linear part, only available in solving stage */
203  SCIP_Real lincoefsmax; /**< maximal absolute value of coefficients in linear part, only available in solving stage */
204 
205  SCIP_Real* factorleft; /**< coefficients of left factor if constraint function is factorable */
206  SCIP_Real* factorright; /**< coefficients of right factor if constraint function is factorable */
207 
208  SCIP_Real* gaugecoefs; /**< coefficients of the gauge function */
209  SCIP_Real gaugeconst; /**< constant of the gauge function */
210  SCIP_Real* interiorpoint; /**< interior point of the region defined by the convex function */
211  SCIP_Real interiorpointval; /**< function value at interior point */
212 
213  SCIP_Real* eigenvalues; /**< eigenvalues of A */
214  SCIP_Real* eigenvectors; /**< orthonormal eigenvectors of A; if A = P D P^T, then eigenvectors is P^T */
215  SCIP_Real* bp; /**< stores b * P where b are the linear coefficients of the quadratic vars */
216  SCIP_Real maxnonconvexity; /**< nonconvexity measure: estimate on largest absolute value of nonconvex eigenvalues */
217 
218  SCIP_Bool isdisaggregated; /**< has the constraint already been disaggregated? if might happen that more disaggreation would be potentially
219  possible, but we reached the maximum number of sparsity components during presolveDisaggregate() */
220 };
221 
222 /** quadratic constraint update method */
224 {
225  SCIP_DECL_QUADCONSUPGD((*quadconsupgd)); /**< method to call for upgrading quadratic constraint */
226  int priority; /**< priority of upgrading method */
227  SCIP_Bool active; /**< is upgrading enabled */
228 };
229 typedef struct SCIP_QuadConsUpgrade SCIP_QUADCONSUPGRADE; /**< quadratic constraint update method */
231 /** structure to store everything needed for using linear inequalities to improve upon the McCormick relaxation */
232 struct BilinearEstimator
233 {
234  SCIP_VAR* x; /**< first variable */
235  SCIP_VAR* y; /**< second variable */
236  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 */
237  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 */
238  SCIP_Real maxnonconvexity; /**< estimate on largest absolute value of nonconvex eigenvalues of all quadratic constraint containing xy */
239  int ninequnderest; /**< total number of inequalities for underestimating xy */
240  int nineqoverest; /**< total number of inequalities for overestimating xy */
241  int nunderest; /**< number of constraints that require to underestimate xy */
242  int noverest; /**< number of constraints that require to overestimate xy */
244  SCIP_Real lastimprfac; /**< last achieved improvement factor */
245 };
246 typedef struct BilinearEstimator BILINESTIMATOR;
248 /** constraint handler data */
249 struct SCIP_ConshdlrData
250 {
251  int replacebinaryprodlength; /**< length of linear term which when multiplied with a binary variable is replaced by an auxiliary variable and an equivalent linear formulation */
252  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 */
253  SCIP_Bool binreforminitial; /**< whether to make constraints added due to replacing products with binary variables initial */
254  SCIP_Bool binreformbinaryonly;/**< whether to consider only binary variables when reformulating products with binary variables */
255  SCIP_Real binreformmaxcoef; /**< factor on 1/feastol to limit coefficients and coef range in linear constraints created by binary reformulation */
256  SCIP_Real cutmaxrange; /**< maximal range (maximal coef / minimal coef) of a cut in order to be added to LP */
257  SCIP_Bool linearizeheursol; /**< whether linearizations of convex quadratic constraints should be added to cutpool when some heuristics finds a new solution */
258  SCIP_Bool checkcurvature; /**< whether functions should be checked for convexity/concavity */
259  SCIP_Bool checkfactorable; /**< whether functions should be checked to be factorable */
260  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) */
261  SCIP_Bool linfeasshift; /**< whether to make solutions in check feasible if possible */
262  int maxdisaggrsize; /**< maximum number of components when disaggregating a quadratic constraint (<= 1: off) */
263  char disaggrmergemethod; /**< method on merging blocks in disaggregation */
264  int maxproprounds; /**< limit on number of propagation rounds for a single constraint within one round of SCIP propagation during solve */
265  int maxproproundspresolve; /**< limit on number of propagation rounds for a single constraint within one presolving round */
266  SCIP_Real sepanlpmincont; /**< minimal required fraction of continuous variables in problem to use solution of NLP relaxation in root for separation */
267  SCIP_Bool enfocutsremovable; /**< are cuts added during enforcement removable from the LP in the same node? */
268  SCIP_Bool gaugecuts; /**< should convex quadratics generated strong cuts via gauge function? */
269  SCIP_Bool projectedcuts; /**< should convex quadratics generated strong cuts via projections? */
270  char interiorcomputation;/**< how the interior point should be computed: 'a'ny point per constraint, 'm'ost interior per constraint */
271  char branchscoring; /**< method to use to compute score of branching candidates */
272  int enfolplimit; /**< maximum number of enforcement round before declaring the LP relaxation
273  * infeasible (-1: no limit); WARNING: if this parameter is not set to -1,
274  * SCIP might declare sub-optimal solutions optimal or feasible instances
275  * infeasible; thus, the result returned by SCIP might be incorrect!
276  */
277  SCIP_HEUR* subnlpheur; /**< a pointer to the subnlp heuristic, if available */
278  SCIP_HEUR* trysolheur; /**< a pointer to the trysol heuristic, if available */
279  SCIP_EVENTHDLR* eventhdlr; /**< our handler for variable bound change events */
280  int newsoleventfilterpos; /**< filter position of new solution event handler, if caught */
281  SCIP_Bool sepanlp; /**< where linearization of the NLP relaxation solution added? */
282  SCIP_NODE* lastenfonode; /**< the node for which enforcement was called the last time (and some constraint was violated) */
283  int nenforounds; /**< counter on number of enforcement rounds for the current node */
284  SCIP_QUADCONSUPGRADE** quadconsupgrades; /**< quadratic constraint upgrade methods for specializing quadratic constraints */
285  int quadconsupgradessize; /**< size of quadconsupgrade array */
286  int nquadconsupgrades; /**< number of quadratic constraint upgrade methods */
287 
288  BILINESTIMATOR* bilinestimators; /**< array containing all required information for using stronger estimators for each bilinear term in all quadratic constraints */
289  int nbilinterms; /**< number of bilinear terms in all quadratic constraints */
290 
291  SCIP_Bool usebilinineqbranch; /**< should linear inequalities be considered when computing the branching scores for bilinear terms? */
292  SCIP_Bool storedbilinearterms; /**< did we already try to store all bilinear terms? */
293 
294  SCIP_Real minscorebilinterms; /**< minimal required score in order to use linear inequalities for tighter bilinear relaxations */
295  SCIP_Real mincurvcollectbilinterms;/**< minimal curvature of constraints to be considered when returning bilinear terms to other plugins */
296  int bilinineqmaxseparounds; /**< maximum number of separation rounds to use linear inequalities for the bilinear term relaxation in a local node */
297 };
298 
299 
300 /*
301  * local methods for managing quadratic constraint update methods
302  */
303 
304 
305 /** checks whether a quadratic constraint upgrade method has already be registered */
306 static
308  SCIP* scip, /**< SCIP data structure */
309  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
310  SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), /**< method to call for upgrading quadratic constraint */
311  const char* conshdlrname /**< name of the constraint handler */
312  )
313 {
314  int i;
315 
316  assert(scip != NULL);
317  assert(conshdlrdata != NULL);
318  assert(quadconsupgd != NULL);
319  assert(conshdlrname != NULL);
320 
321  for( i = conshdlrdata->nquadconsupgrades - 1; i >= 0; --i )
322  {
323  if( conshdlrdata->quadconsupgrades[i]->quadconsupgd == quadconsupgd )
324  {
325  SCIPwarningMessage(scip, "Try to add already known upgrade message for constraint handler <%s>.\n", conshdlrname);
326  return TRUE;
327  }
328  }
329 
330  return FALSE;
331 }
332 
333 /*
334  * Local methods
335  */
336 
337 /** translate from one value of infinity to another
338  *
339  * if val is >= infty1, then give infty2, else give val
340  */
341 #define infty2infty(infty1, infty2, val) ((val) >= (infty1) ? (infty2) : (val))
343 /** catches variable bound change events on a linear variable in a quadratic constraint */
344 static
346  SCIP* scip, /**< SCIP data structure */
347  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
348  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
349  int linvarpos /**< position of variable in linear variables array */
350  )
351 {
352  SCIP_CONSDATA* consdata;
353  SCIP_QUADVAREVENTDATA* eventdata;
354  SCIP_EVENTTYPE eventtype;
355 
356  assert(scip != NULL);
357  assert(eventhdlr != NULL);
358  assert(cons != NULL);
359 
360  consdata = SCIPconsGetData(cons);
361  assert(consdata != NULL);
362 
363  assert(linvarpos >= 0);
364  assert(linvarpos < consdata->nlinvars);
365  assert(consdata->lineventdata != NULL);
366 
367  SCIP_CALL( SCIPallocBlockMemory(scip, &eventdata) );
368 
369  eventdata->cons = cons;
370  eventdata->varidx = linvarpos;
371 
373  if( !SCIPisInfinity(scip, consdata->rhs) )
374  {
375  /* if right hand side is finite, then a tightening in the lower bound of coef*linvar is of interest
376  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
377  if( consdata->lincoefs[linvarpos] > 0.0 )
378  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
379  else
380  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
381  }
382  if( !SCIPisInfinity(scip, -consdata->lhs) )
383  {
384  /* if left hand side is finite, then a tightening in the upper bound of coef*linvar is of interest
385  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
386  if( consdata->lincoefs[linvarpos] > 0.0 )
387  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
388  else
389  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
390  }
391 
392  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->linvars[linvarpos], eventtype, eventhdlr, (SCIP_EVENTDATA*)eventdata, &eventdata->filterpos) );
393 
394  consdata->lineventdata[linvarpos] = eventdata;
395 
396  /* invalidate activity information
397  * NOTE: It could happen that a constraint gets temporary deactivated and some variable bounds change. In this case
398  * we do not recognize those bound changes with the variable events and thus we have to recompute the activities.
399  */
400  consdata->minlinactivity = SCIP_INVALID;
401  consdata->maxlinactivity = SCIP_INVALID;
402  consdata->minlinactivityinf = -1;
403  consdata->maxlinactivityinf = -1;
404 
405  return SCIP_OKAY;
406 }
407 
408 /** drops variable bound change events on a linear variable in a quadratic constraint */
409 static
411  SCIP* scip, /**< SCIP data structure */
412  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
413  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
414  int linvarpos /**< position of variable in linear variables array */
415  )
416 {
417  SCIP_CONSDATA* consdata;
418  SCIP_EVENTTYPE eventtype;
419 
420  assert(scip != NULL);
421  assert(eventhdlr != NULL);
422  assert(cons != NULL);
423 
424  consdata = SCIPconsGetData(cons);
425  assert(consdata != NULL);
426 
427  assert(linvarpos >= 0);
428  assert(linvarpos < consdata->nlinvars);
429  assert(consdata->lineventdata != NULL);
430  assert(consdata->lineventdata[linvarpos] != NULL);
431  assert(consdata->lineventdata[linvarpos]->cons == cons);
432  assert(consdata->lineventdata[linvarpos]->varidx == linvarpos);
433  assert(consdata->lineventdata[linvarpos]->filterpos >= 0);
434 
436  if( !SCIPisInfinity(scip, consdata->rhs) )
437  {
438  /* if right hand side is finite, then a tightening in the lower bound of coef*linvar is of interest
439  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
440  if( consdata->lincoefs[linvarpos] > 0.0 )
441  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
442  else
443  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
444  }
445  if( !SCIPisInfinity(scip, -consdata->lhs) )
446  {
447  /* if left hand side is finite, then a tightening in the upper bound of coef*linvar is of interest
448  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
449  if( consdata->lincoefs[linvarpos] > 0.0 )
450  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
451  else
452  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
453  }
454 
455  SCIP_CALL( SCIPdropVarEvent(scip, consdata->linvars[linvarpos], eventtype, eventhdlr, (SCIP_EVENTDATA*)consdata->lineventdata[linvarpos], consdata->lineventdata[linvarpos]->filterpos) );
456 
457  SCIPfreeBlockMemory(scip, &consdata->lineventdata[linvarpos]); /*lint !e866 */
458 
459  return SCIP_OKAY;
460 }
461 
462 /** catches variable bound change events on a quadratic variable in a quadratic constraint */
463 static
465  SCIP* scip, /**< SCIP data structure */
466  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
467  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
468  int quadvarpos /**< position of variable in quadratic variables array */
469  )
470 {
471  SCIP_CONSDATA* consdata;
472  SCIP_QUADVAREVENTDATA* eventdata;
473  SCIP_EVENTTYPE eventtype;
474 
475  assert(scip != NULL);
476  assert(eventhdlr != NULL);
477  assert(cons != NULL);
478 
479  consdata = SCIPconsGetData(cons);
480  assert(consdata != NULL);
481 
482  assert(quadvarpos >= 0);
483  assert(quadvarpos < consdata->nquadvars);
484  assert(consdata->quadvarterms[quadvarpos].eventdata == NULL);
485 
486  SCIP_CALL( SCIPallocBlockMemory(scip, &eventdata) );
487 
489 #ifdef CHECKIMPLINBILINEAR
490  eventtype |= SCIP_EVENTTYPE_IMPLADDED;
491 #endif
492  eventdata->cons = cons;
493  eventdata->varidx = -quadvarpos-1;
494  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->quadvarterms[quadvarpos].var, eventtype, eventhdlr, (SCIP_EVENTDATA*)eventdata, &eventdata->filterpos) );
495 
496  consdata->quadvarterms[quadvarpos].eventdata = eventdata;
497 
498  /* invalidate activity information
499  * NOTE: It could happen that a constraint gets temporary deactivated and some variable bounds change. In this case
500  * we do not recognize those bound changes with the variable events and thus we have to recompute the activities.
501  */
502  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
503 
504  return SCIP_OKAY;
505 }
506 
507 /** catches variable bound change events on a quadratic variable in a quadratic constraint */
508 static
510  SCIP* scip, /**< SCIP data structure */
511  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
512  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
513  int quadvarpos /**< position of variable in quadratic variables array */
514  )
515 {
516  SCIP_CONSDATA* consdata;
517  SCIP_EVENTTYPE eventtype;
518 
519  assert(scip != NULL);
520  assert(eventhdlr != NULL);
521  assert(cons != NULL);
522 
523  consdata = SCIPconsGetData(cons);
524  assert(consdata != NULL);
525 
526  assert(quadvarpos >= 0);
527  assert(quadvarpos < consdata->nquadvars);
528  assert(consdata->quadvarterms[quadvarpos].eventdata != NULL);
529  assert(consdata->quadvarterms[quadvarpos].eventdata->cons == cons);
530  assert(consdata->quadvarterms[quadvarpos].eventdata->varidx == -quadvarpos-1);
531  assert(consdata->quadvarterms[quadvarpos].eventdata->filterpos >= 0);
532 
534 #ifdef CHECKIMPLINBILINEAR
535  eventtype |= SCIP_EVENTTYPE_IMPLADDED;
536 #endif
537 
538  SCIP_CALL( SCIPdropVarEvent(scip, consdata->quadvarterms[quadvarpos].var, eventtype, eventhdlr, (SCIP_EVENTDATA*)consdata->quadvarterms[quadvarpos].eventdata, consdata->quadvarterms[quadvarpos].eventdata->filterpos) );
539 
540  SCIPfreeBlockMemory(scip, &consdata->quadvarterms[quadvarpos].eventdata);
541 
542  return SCIP_OKAY;
543 }
544 
545 /** catch variable events */
546 static
548  SCIP* scip, /**< SCIP data structure */
549  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
550  SCIP_CONS* cons /**< constraint for which to catch bound change events */
551  )
552 {
553  SCIP_CONSDATA* consdata;
554  SCIP_VAR* var;
555  int i;
556 
557  assert(scip != NULL);
558  assert(cons != NULL);
559  assert(eventhdlr != NULL);
560 
561  consdata = SCIPconsGetData(cons);
562  assert(consdata != NULL);
563  assert(consdata->lineventdata == NULL);
564 
565  /* we will update isremovedfixings, so reset it to TRUE first */
566  consdata->isremovedfixings = TRUE;
567 
568  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize) );
569  for( i = 0; i < consdata->nlinvars; ++i )
570  {
571  SCIP_CALL( catchLinearVarEvents(scip, eventhdlr, cons, i) );
572 
573  var = consdata->linvars[i];
574  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var)
575  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
576  }
577 
578  for( i = 0; i < consdata->nquadvars; ++i )
579  {
580  assert(consdata->quadvarterms[i].eventdata == NULL);
581 
582  SCIP_CALL( catchQuadVarEvents(scip, eventhdlr, cons, i) );
583 
584  var = consdata->quadvarterms[i].var;
585  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var)
586  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
587  }
588 
589  consdata->ispropagated = FALSE;
590 
591  return SCIP_OKAY;
592 }
593 
594 /** drop variable events */
595 static
597  SCIP* scip, /**< SCIP data structure */
598  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
599  SCIP_CONS* cons /**< constraint for which to drop bound change events */
600  )
601 {
602  SCIP_CONSDATA* consdata;
603  int i;
604 
605  assert(scip != NULL);
606  assert(eventhdlr != NULL);
607  assert(cons != NULL);
608 
609  consdata = SCIPconsGetData(cons);
610  assert(consdata != NULL);
611 
612  if( consdata->lineventdata != NULL )
613  {
614  for( i = 0; i < consdata->nlinvars; ++i )
615  {
616  if( consdata->lineventdata[i] != NULL )
617  {
618  SCIP_CALL( dropLinearVarEvents(scip, eventhdlr, cons, i) );
619  }
620  }
621  SCIPfreeBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize);
622  }
623 
624  for( i = 0; i < consdata->nquadvars; ++i )
625  {
626  if( consdata->quadvarterms[i].eventdata != NULL )
627  {
628  SCIP_CALL( dropQuadVarEvents(scip, eventhdlr, cons, i) );
629  }
630  }
631 
632  return SCIP_OKAY;
633 }
634 
635 /** locks a linear variable in a constraint */
636 static
638  SCIP* scip, /**< SCIP data structure */
639  SCIP_CONS* cons, /**< constraint where to lock a variable */
640  SCIP_VAR* var, /**< variable to lock */
641  SCIP_Real coef /**< coefficient of variable in constraint */
642  )
643 {
644  SCIP_CONSDATA* consdata;
645 
646  assert(scip != NULL);
647  assert(cons != NULL);
648  assert(var != NULL);
649  assert(coef != 0.0);
650 
651  consdata = SCIPconsGetData(cons);
652  assert(consdata != NULL);
653 
654  if( coef > 0.0 )
655  {
656  SCIP_CALL( SCIPlockVarCons(scip, var, cons, !SCIPisInfinity(scip, -consdata->lhs), !SCIPisInfinity(scip, consdata->rhs)) );
657  }
658  else
659  {
660  SCIP_CALL( SCIPlockVarCons(scip, var, cons, !SCIPisInfinity(scip, consdata->rhs), !SCIPisInfinity(scip, -consdata->lhs)) );
661  }
662 
663  return SCIP_OKAY;
664 }
665 
666 /** unlocks a linear variable in a constraint */
667 static
669  SCIP* scip, /**< SCIP data structure */
670  SCIP_CONS* cons, /**< constraint where to unlock a variable */
671  SCIP_VAR* var, /**< variable to unlock */
672  SCIP_Real coef /**< coefficient of variable in constraint */
673  )
674 {
675  SCIP_CONSDATA* consdata;
676 
677  assert(scip != NULL);
678  assert(cons != NULL);
679  assert(var != NULL);
680  assert(coef != 0.0);
681 
682  consdata = SCIPconsGetData(cons);
683  assert(consdata != NULL);
684 
685  if( coef > 0.0 )
686  {
687  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, !SCIPisInfinity(scip, -consdata->lhs), !SCIPisInfinity(scip, consdata->rhs)) );
688  }
689  else
690  {
691  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, !SCIPisInfinity(scip, consdata->rhs), !SCIPisInfinity(scip, -consdata->lhs)) );
692  }
693 
694  return SCIP_OKAY;
695 }
696 
697 /** locks a quadratic variable in a constraint */
698 static
700  SCIP* scip, /**< SCIP data structure */
701  SCIP_CONS* cons, /**< constraint where to lock a variable */
702  SCIP_VAR* var /**< variable to lock */
703  )
704 {
705  SCIP_CALL( SCIPlockVarCons(scip, var, cons, TRUE, TRUE) );
706 
707  return SCIP_OKAY;
708 }
709 
710 /** unlocks a quadratic variable in a constraint */
711 static
713  SCIP* scip, /**< SCIP data structure */
714  SCIP_CONS* cons, /**< constraint where to unlock a variable */
715  SCIP_VAR* var /**< variable to unlock */
716  )
717 {
718  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, TRUE) );
719 
720  return SCIP_OKAY;
721 }
722 
723 /** computes the minimal and maximal activity for the linear part in a constraint data
724  *
725  * Only sums up terms that contribute finite values.
726  * Gives the number of terms that contribute infinite values.
727  * Only computes those activities where the corresponding side of the constraint is finite.
728  */
729 static
731  SCIP* scip, /**< SCIP data structure */
732  SCIP_CONSDATA* consdata, /**< constraint data */
733  SCIP_Real intervalinfty /**< infinity value used in interval operations */
734  )
735 { /*lint --e{666}*/
736  SCIP_ROUNDMODE prevroundmode;
737  int i;
738  SCIP_Real bnd;
739 
740  assert(scip != NULL);
741  assert(consdata != NULL);
742 
743  /* if variable bounds are not strictly consistent, then the activity update methods may yield inconsistent activities
744  * in this case, we also recompute the activities
745  */
746  if( consdata->minlinactivity != SCIP_INVALID && consdata->maxlinactivity != SCIP_INVALID && /*lint !e777 */
747  (consdata->minlinactivityinf > 0 || consdata->maxlinactivityinf > 0 || consdata->minlinactivity <= consdata->maxlinactivity) )
748  {
749  /* activities should be up-to-date */
750  assert(consdata->minlinactivityinf >= 0);
751  assert(consdata->maxlinactivityinf >= 0);
752  return;
753  }
754 
755  consdata->minlinactivityinf = 0;
756  consdata->maxlinactivityinf = 0;
757 
758  /* if lhs is -infinite, then we do not compute a maximal activity, so we set it to infinity
759  * if rhs is infinite, then we do not compute a minimal activity, so we set it to -infinity
760  */
761  consdata->minlinactivity = SCIPisInfinity(scip, consdata->rhs) ? -intervalinfty : 0.0;
762  consdata->maxlinactivity = SCIPisInfinity(scip, -consdata->lhs) ? intervalinfty : 0.0;
763 
764  if( consdata->nlinvars == 0 )
765  return;
766 
767  /* if the activities computed here should be still up-to-date after bound changes,
768  * variable events need to be caught */
769  assert(consdata->lineventdata != NULL);
770 
771  prevroundmode = SCIPintervalGetRoundingMode();
772 
773  if( !SCIPisInfinity(scip, consdata->rhs) )
774  {
775  /* compute minimal activity only if there is a finite right hand side */
777 
778  for( i = 0; i < consdata->nlinvars; ++i )
779  {
780  assert(consdata->lineventdata[i] != NULL);
781  if( consdata->lincoefs[i] >= 0.0 )
782  {
783  bnd = MIN(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
784  if( SCIPisInfinity(scip, -bnd) )
785  {
786  ++consdata->minlinactivityinf;
787  continue;
788  }
789  assert(!SCIPisInfinity(scip, bnd)); /* do not like variables that are fixed at +infinity */
790  }
791  else
792  {
793  bnd = MAX(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
794  if( SCIPisInfinity(scip, bnd) )
795  {
796  ++consdata->minlinactivityinf;
797  continue;
798  }
799  assert(!SCIPisInfinity(scip, -bnd)); /* do not like variables that are fixed at -infinity */
800  }
801  consdata->minlinactivity += consdata->lincoefs[i] * bnd;
802  }
803  }
804 
805  if( !SCIPisInfinity(scip, -consdata->lhs) )
806  {
807  /* compute maximal activity only if there is a finite left hand side */
809 
810  for( i = 0; i < consdata->nlinvars; ++i )
811  {
812  assert(consdata->lineventdata[i] != NULL);
813  if( consdata->lincoefs[i] >= 0.0 )
814  {
815  bnd = MAX(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
816  if( SCIPisInfinity(scip, bnd) )
817  {
818  ++consdata->maxlinactivityinf;
819  continue;
820  }
821  assert(!SCIPisInfinity(scip, -bnd)); /* do not like variables that are fixed at -infinity */
822  }
823  else
824  {
825  bnd = MIN(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
826  if( SCIPisInfinity(scip, -bnd) )
827  {
828  ++consdata->maxlinactivityinf;
829  continue;
830  }
831  assert(!SCIPisInfinity(scip, bnd)); /* do not like variables that are fixed at +infinity */
832  }
833  consdata->maxlinactivity += consdata->lincoefs[i] * bnd;
834  }
835  }
836 
837  SCIPintervalSetRoundingMode(prevroundmode);
838 
839  assert(consdata->minlinactivityinf > 0 || consdata->maxlinactivityinf > 0 || consdata->minlinactivity <= consdata->maxlinactivity);
840 }
841 
842 /** update the linear activities after a change in the lower bound of a variable */
843 static
845  SCIP* scip, /**< SCIP data structure */
846  SCIP_CONSDATA* consdata, /**< constraint data */
847  SCIP_Real coef, /**< coefficient of variable in constraint */
848  SCIP_Real oldbnd, /**< previous lower bound of variable */
849  SCIP_Real newbnd /**< new lower bound of variable */
850  )
851 {
852  SCIP_ROUNDMODE prevroundmode;
853 
854  assert(scip != NULL);
855  assert(consdata != NULL);
856  /* we can't deal with lower bounds at infinity */
857  assert(!SCIPisInfinity(scip, oldbnd));
858  assert(!SCIPisInfinity(scip, newbnd));
859 
860  /* @todo since we check the linear activity for consistency later anyway, we may skip changing the rounding mode here */
861 
862  /* assume lhs <= a*x + y <= rhs, then the following bound changes can be deduced:
863  * a > 0: y <= rhs - a*lb(x), y >= lhs - a*ub(x)
864  * a < 0: y <= rhs - a*ub(x), y >= lhs - a*lb(x)
865  */
866 
867  if( coef > 0.0 )
868  {
869  /* we should only be called if rhs is finite */
870  assert(!SCIPisInfinity(scip, consdata->rhs));
871 
872  /* we have no min activities computed so far, so cannot update */
873  if( consdata->minlinactivity == SCIP_INVALID ) /*lint !e777 */
874  return;
875 
876  prevroundmode = SCIPintervalGetRoundingMode();
878 
879  /* update min activity */
880  if( SCIPisInfinity(scip, -oldbnd) )
881  {
882  --consdata->minlinactivityinf;
883  assert(consdata->minlinactivityinf >= 0);
884  }
885  else
886  {
887  SCIP_Real minuscoef;
888  minuscoef = -coef;
889  consdata->minlinactivity += minuscoef * oldbnd;
890  }
891 
892  if( SCIPisInfinity(scip, -newbnd) )
893  {
894  ++consdata->minlinactivityinf;
895  }
896  else
897  {
898  consdata->minlinactivity += coef * newbnd;
899  }
900 
901  SCIPintervalSetRoundingMode(prevroundmode);
902  }
903  else
904  {
905  /* we should only be called if lhs is finite */
906  assert(!SCIPisInfinity(scip, -consdata->lhs));
907 
908  /* we have no max activities computed so far, so cannot update */
909  if( consdata->maxlinactivity == SCIP_INVALID ) /*lint !e777 */
910  return;
911 
912  prevroundmode = SCIPintervalGetRoundingMode();
914 
915  /* update max activity */
916  if( SCIPisInfinity(scip, -oldbnd) )
917  {
918  --consdata->maxlinactivityinf;
919  assert(consdata->maxlinactivityinf >= 0);
920  }
921  else
922  {
923  SCIP_Real minuscoef;
924  minuscoef = -coef;
925  consdata->maxlinactivity += minuscoef * oldbnd;
926  }
927 
928  if( SCIPisInfinity(scip, -newbnd) )
929  {
930  ++consdata->maxlinactivityinf;
931  }
932  else
933  {
934  consdata->maxlinactivity += coef * newbnd;
935  }
936 
937  SCIPintervalSetRoundingMode(prevroundmode);
938  }
939 }
940 
941 /** update the linear activities after a change in the upper bound of a variable */
942 static
944  SCIP* scip, /**< SCIP data structure */
945  SCIP_CONSDATA* consdata, /**< constraint data */
946  SCIP_Real coef, /**< coefficient of variable in constraint */
947  SCIP_Real oldbnd, /**< previous lower bound of variable */
948  SCIP_Real newbnd /**< new lower bound of variable */
949  )
950 {
951  SCIP_ROUNDMODE prevroundmode;
952 
953  assert(scip != NULL);
954  assert(consdata != NULL);
955  /* we can't deal with upper bounds at -infinity */
956  assert(!SCIPisInfinity(scip, -oldbnd));
957  assert(!SCIPisInfinity(scip, -newbnd));
958 
959  /* @todo since we check the linear activity for consistency later anyway, we may skip changing the rounding mode here */
960 
961  /* assume lhs <= a*x + y <= rhs, then the following bound changes can be deduced:
962  * a > 0: y <= rhs - a*lb(x), y >= lhs - a*ub(x)
963  * a < 0: y <= rhs - a*ub(x), y >= lhs - a*lb(x)
964  */
965 
966  if( coef > 0.0 )
967  {
968  /* we should only be called if lhs is finite */
969  assert(!SCIPisInfinity(scip, -consdata->lhs));
970 
971  /* we have no max activities computed so far, so cannot update */
972  if( consdata->maxlinactivity == SCIP_INVALID ) /*lint !e777 */
973  return;
974 
975  prevroundmode = SCIPintervalGetRoundingMode();
977 
978  /* update max activity */
979  if( SCIPisInfinity(scip, oldbnd) )
980  {
981  --consdata->maxlinactivityinf;
982  assert(consdata->maxlinactivityinf >= 0);
983  }
984  else
985  {
986  SCIP_Real minuscoef;
987  minuscoef = -coef;
988  consdata->maxlinactivity += minuscoef * oldbnd;
989  }
990 
991  if( SCIPisInfinity(scip, newbnd) )
992  {
993  ++consdata->maxlinactivityinf;
994  }
995  else
996  {
997  consdata->maxlinactivity += coef * newbnd;
998  }
999 
1000  SCIPintervalSetRoundingMode(prevroundmode);
1001  }
1002  else
1003  {
1004  /* we should only be called if rhs is finite */
1005  assert(!SCIPisInfinity(scip, consdata->rhs));
1006 
1007  /* we have no min activities computed so far, so cannot update */
1008  if( consdata->minlinactivity == SCIP_INVALID ) /*lint !e777 */
1009  return;
1010 
1011  prevroundmode = SCIPintervalGetRoundingMode();
1013 
1014  /* update min activity */
1015  if( SCIPisInfinity(scip, oldbnd) )
1016  {
1017  --consdata->minlinactivityinf;
1018  assert(consdata->minlinactivityinf >= 0);
1019  }
1020  else
1021  {
1022  SCIP_Real minuscoef;
1023  minuscoef = -coef;
1024  consdata->minlinactivity += minuscoef * oldbnd;
1025  }
1026 
1027  if( SCIPisInfinity(scip, newbnd) )
1028  {
1029  ++consdata->minlinactivityinf;
1030  }
1031  else
1032  {
1033  consdata->minlinactivity += coef * newbnd;
1034  }
1035 
1036  SCIPintervalSetRoundingMode(prevroundmode);
1037  }
1038 }
1039 
1040 /** returns whether a quadratic variable domain can be reduced to its lower or upper bound; this is the case if the
1041  * quadratic variable is in just one single quadratic constraint and (sqrcoef > 0 and LHS = -infinity), or
1042  * (sqrcoef < 0 and RHS = +infinity) hold
1043  */
1044 static
1046  SCIP* scip, /**< SCIP data structure */
1047  SCIP_CONSDATA* consdata, /**< constraint data */
1048  int idx /**< index of quadratic variable */
1049  )
1050 {
1051  SCIP_VAR* var;
1052  SCIP_Real quadcoef;
1053  SCIP_Bool haslhs;
1054  SCIP_Bool hasrhs;
1055 
1056  assert(scip != NULL);
1057  assert(consdata != NULL);
1058  assert(idx >= 0 && idx < consdata->nquadvars);
1059 
1060  var = consdata->quadvarterms[idx].var;
1061  assert(var != NULL);
1062 
1063  quadcoef = consdata->quadvarterms[idx].sqrcoef;
1064  haslhs = !SCIPisInfinity(scip, -consdata->lhs);
1065  hasrhs = !SCIPisInfinity(scip, consdata->rhs);
1066 
1069  && SCIPvarGetType(var) != SCIP_VARTYPE_BINARY && ((quadcoef < 0.0 && !haslhs) || (quadcoef > 0.0 && !hasrhs));
1070 }
1071 
1072 /** processes variable fixing or bound change event */
1073 static
1074 SCIP_DECL_EVENTEXEC(processVarEvent)
1076  SCIP_CONS* cons;
1077  SCIP_CONSDATA* consdata;
1078  SCIP_EVENTTYPE eventtype;
1079  int varidx;
1080 
1081  assert(scip != NULL);
1082  assert(event != NULL);
1083  assert(eventdata != NULL);
1084  assert(eventhdlr != NULL);
1085 
1086  cons = ((SCIP_QUADVAREVENTDATA*)eventdata)->cons;
1087  assert(cons != NULL);
1088  consdata = SCIPconsGetData(cons);
1089  assert(consdata != NULL);
1090 
1091  varidx = ((SCIP_QUADVAREVENTDATA*)eventdata)->varidx;
1092  assert(varidx < 0 || varidx < consdata->nlinvars);
1093  assert(varidx >= 0 || -varidx-1 < consdata->nquadvars);
1094 
1095  eventtype = SCIPeventGetType(event);
1096 
1097  /* process local bound changes */
1098  if( eventtype & SCIP_EVENTTYPE_BOUNDCHANGED )
1099  {
1100  if( varidx < 0 )
1101  {
1102  /* mark activity bounds for quad term as not up to date anymore */
1103  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
1104  }
1105  else
1106  {
1107  /* update activity bounds for linear terms */
1108  if( eventtype & SCIP_EVENTTYPE_LBCHANGED )
1109  consdataUpdateLinearActivityLbChange(scip, consdata, consdata->lincoefs[varidx], SCIPeventGetOldbound(event), SCIPeventGetNewbound(event));
1110  else
1111  consdataUpdateLinearActivityUbChange(scip, consdata, consdata->lincoefs[varidx], SCIPeventGetOldbound(event), SCIPeventGetNewbound(event));
1112  }
1113 
1114  if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
1115  {
1116  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
1117  consdata->ispropagated = FALSE;
1118  }
1119  }
1120 
1121  /* process global bound changes */
1122  if( eventtype & SCIP_EVENTTYPE_GBDCHANGED )
1123  {
1124  SCIP_VAR* var;
1125 
1126  var = varidx < 0 ? consdata->quadvarterms[-varidx-1].var : consdata->linvars[varidx];
1127  assert(var != NULL);
1128 
1129  if( varidx < 0 )
1130  {
1131  SCIP_QUADVARTERM* quadvarterm;
1132 
1133  quadvarterm = &consdata->quadvarterms[-varidx-1];
1134 
1135  /* 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()
1136  * we currently do this only if the binary variable does not show up in any bilinear terms
1137  */
1139  quadvarterm->sqrcoef != 0.0 && quadvarterm->nadjbilin == 0 )
1140  {
1141  consdata->quadvarsmerged = FALSE;
1142  consdata->initialmerge = FALSE;
1143  }
1144  }
1145 
1146  if( SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
1147  consdata->isremovedfixings = FALSE;
1148  }
1149 
1150  /* process variable fixing event */
1151  if( eventtype & SCIP_EVENTTYPE_VARFIXED )
1152  {
1153  consdata->isremovedfixings = FALSE;
1154  }
1155 
1156 #ifdef CHECKIMPLINBILINEAR
1157  if( eventtype & SCIP_EVENTTYPE_IMPLADDED )
1158  {
1159  assert(varidx < 0); /* we catch impladded events only for quadratic variables */
1160  /* 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 */
1161  if( SCIPvarIsBinary(SCIPeventGetVar(event)) && consdata->quadvarterms[-varidx-1].nadjbilin > 0 )
1162  consdata->isimpladded = TRUE;
1163  }
1164 #endif
1165 
1166  return SCIP_OKAY;
1167 }
1168 
1169 /** ensures, that linear vars and coefs arrays can store at least num entries */
1170 static
1172  SCIP* scip, /**< SCIP data structure */
1173  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1174  int num /**< minimum number of entries to store */
1175  )
1176 {
1177  assert(scip != NULL);
1178  assert(consdata != NULL);
1179  assert(consdata->nlinvars <= consdata->linvarssize);
1180 
1181  if( num > consdata->linvarssize )
1182  {
1183  int newsize;
1184 
1185  newsize = SCIPcalcMemGrowSize(scip, num);
1186  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->linvars, consdata->linvarssize, newsize) );
1187  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->lincoefs, consdata->linvarssize, newsize) );
1188  if( consdata->lineventdata != NULL )
1189  {
1190  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize, newsize) );
1191  }
1192  consdata->linvarssize = newsize;
1193  }
1194  assert(num <= consdata->linvarssize);
1195 
1196  return SCIP_OKAY;
1197 }
1198 
1199 /** ensures, that quadratic variable terms array can store at least num entries */
1200 static
1202  SCIP* scip, /**< SCIP data structure */
1203  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1204  int num /**< minimum number of entries to store */
1205  )
1206 {
1207  assert(scip != NULL);
1208  assert(consdata != NULL);
1209  assert(consdata->nquadvars <= consdata->quadvarssize);
1210 
1211  if( num > consdata->quadvarssize )
1212  {
1213  int newsize;
1214 
1215  newsize = SCIPcalcMemGrowSize(scip, num);
1216  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->quadvarterms, consdata->quadvarssize, newsize) );
1217  consdata->quadvarssize = newsize;
1218  }
1219  assert(num <= consdata->quadvarssize);
1220 
1221  return SCIP_OKAY;
1222 }
1223 
1224 /** ensures, that adjacency array can store at least num entries */
1225 static
1227  SCIP* scip, /**< SCIP data structure */
1228  SCIP_QUADVARTERM* quadvarterm, /**< quadratic variable term */
1229  int num /**< minimum number of entries to store */
1230  )
1231 {
1232  assert(scip != NULL);
1233  assert(quadvarterm != NULL);
1234  assert(quadvarterm->nadjbilin <= quadvarterm->adjbilinsize);
1235 
1236  if( num > quadvarterm->adjbilinsize )
1237  {
1238  int newsize;
1239 
1240  newsize = SCIPcalcMemGrowSize(scip, num);
1241  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &quadvarterm->adjbilin, quadvarterm->adjbilinsize, newsize) );
1242  quadvarterm->adjbilinsize = newsize;
1243  }
1244  assert(num <= quadvarterm->adjbilinsize);
1245 
1246  return SCIP_OKAY;
1247 }
1248 
1249 /** ensures, that bilinear term arrays can store at least num entries */
1250 static
1252  SCIP* scip, /**< SCIP data structure */
1253  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1254  int num /**< minimum number of entries to store */
1255  )
1256 {
1257  assert(scip != NULL);
1258  assert(consdata != NULL);
1259  assert(consdata->nbilinterms <= consdata->bilintermssize);
1260 
1261  if( num > consdata->bilintermssize )
1262  {
1263  int newsize;
1264 
1265  newsize = SCIPcalcMemGrowSize(scip, num);
1266  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->bilinterms, consdata->bilintermssize, newsize) );
1267  consdata->bilintermssize = newsize;
1268  }
1269  assert(num <= consdata->bilintermssize);
1270 
1271  return SCIP_OKAY;
1272 }
1273 
1274 /** creates empty constraint data structure */
1275 static
1277  SCIP* scip, /**< SCIP data structure */
1278  SCIP_CONSDATA** consdata /**< a buffer to store pointer to new constraint data */
1279  )
1280 {
1281  assert(scip != NULL);
1282  assert(consdata != NULL);
1283 
1284  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1285  BMSclearMemory(*consdata);
1286 
1287  (*consdata)->lhs = -SCIPinfinity(scip);
1288  (*consdata)->rhs = SCIPinfinity(scip);
1289 
1290  (*consdata)->linvarssorted = TRUE;
1291  (*consdata)->linvarsmerged = TRUE;
1292  (*consdata)->quadvarssorted = TRUE;
1293  (*consdata)->quadvarsmerged = TRUE;
1294  (*consdata)->bilinsorted = TRUE;
1295  (*consdata)->bilinmerged = TRUE;
1296 
1297  (*consdata)->isremovedfixings = TRUE;
1298  (*consdata)->ispropagated = TRUE;
1299  (*consdata)->initialmerge = FALSE;
1300 
1301  (*consdata)->linvar_maydecrease = -1;
1302  (*consdata)->linvar_mayincrease = -1;
1303 
1304  (*consdata)->minlinactivity = SCIP_INVALID;
1305  (*consdata)->maxlinactivity = SCIP_INVALID;
1306  (*consdata)->minlinactivityinf = -1;
1307  (*consdata)->maxlinactivityinf = -1;
1308 
1309  (*consdata)->isgaugeavailable = FALSE;
1310  (*consdata)->isedavailable = FALSE;
1311 
1312  return SCIP_OKAY;
1313 }
1314 
1315 /** creates constraint data structure */
1316 static
1318  SCIP* scip, /**< SCIP data structure */
1319  SCIP_CONSDATA** consdata, /**< a buffer to store pointer to new constraint data */
1320  SCIP_Real lhs, /**< left hand side of constraint */
1321  SCIP_Real rhs, /**< right hand side of constraint */
1322  int nlinvars, /**< number of linear variables */
1323  SCIP_VAR** linvars, /**< array of linear variables */
1324  SCIP_Real* lincoefs, /**< array of coefficients of linear variables */
1325  int nquadvars, /**< number of quadratic variables */
1326  SCIP_QUADVARTERM* quadvarterms, /**< array of quadratic variable terms */
1327  int nbilinterms, /**< number of bilinear terms */
1328  SCIP_BILINTERM* bilinterms, /**< array of bilinear terms */
1329  SCIP_Bool capturevars /**< whether we should capture variables */
1330  )
1331 {
1332  int i;
1333 
1334  assert(scip != NULL);
1335  assert(consdata != NULL);
1336 
1337  assert(nlinvars == 0 || linvars != NULL);
1338  assert(nlinvars == 0 || lincoefs != NULL);
1339  assert(nquadvars == 0 || quadvarterms != NULL);
1340  assert(nbilinterms == 0 || bilinterms != NULL);
1341 
1342  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1343  BMSclearMemory(*consdata);
1344 
1345  (*consdata)->minlinactivity = SCIP_INVALID;
1346  (*consdata)->maxlinactivity = SCIP_INVALID;
1347  (*consdata)->minlinactivityinf = -1;
1348  (*consdata)->maxlinactivityinf = -1;
1349 
1350  (*consdata)->lhs = lhs;
1351  (*consdata)->rhs = rhs;
1352 
1353  if( nlinvars > 0 )
1354  {
1355  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->linvars, linvars, nlinvars) );
1356  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->lincoefs, lincoefs, nlinvars) );
1357  (*consdata)->nlinvars = nlinvars;
1358  (*consdata)->linvarssize = nlinvars;
1359 
1360  if( capturevars )
1361  for( i = 0; i < nlinvars; ++i )
1362  {
1363  SCIP_CALL( SCIPcaptureVar(scip, linvars[i]) );
1364  }
1365  }
1366  else
1367  {
1368  (*consdata)->linvarssorted = TRUE;
1369  (*consdata)->linvarsmerged = TRUE;
1370  (*consdata)->minlinactivity = 0.0;
1371  (*consdata)->maxlinactivity = 0.0;
1372  (*consdata)->minlinactivityinf = 0;
1373  (*consdata)->maxlinactivityinf = 0;
1374  }
1375 
1376  if( nquadvars > 0 )
1377  {
1378  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->quadvarterms, quadvarterms, nquadvars) );
1379 
1380  for( i = 0; i < nquadvars; ++i )
1381  {
1382  (*consdata)->quadvarterms[i].eventdata = NULL;
1383  if( quadvarterms[i].nadjbilin )
1384  {
1385  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->quadvarterms[i].adjbilin, quadvarterms[i].adjbilin, quadvarterms[i].nadjbilin) );
1386  (*consdata)->quadvarterms[i].adjbilinsize = quadvarterms[i].nadjbilin;
1387  }
1388  else
1389  {
1390  assert((*consdata)->quadvarterms[i].nadjbilin == 0);
1391  (*consdata)->quadvarterms[i].adjbilin = NULL;
1392  (*consdata)->quadvarterms[i].adjbilinsize = 0;
1393  }
1394  if( capturevars )
1395  {
1396  SCIP_CALL( SCIPcaptureVar(scip, quadvarterms[i].var) );
1397  }
1398  }
1399 
1400  (*consdata)->nquadvars = nquadvars;
1401  (*consdata)->quadvarssize = nquadvars;
1402  SCIPintervalSetEmpty(&(*consdata)->quadactivitybounds);
1403  }
1404  else
1405  {
1406  (*consdata)->quadvarssorted = TRUE;
1407  (*consdata)->quadvarsmerged = TRUE;
1408  SCIPintervalSet(&(*consdata)->quadactivitybounds, 0.0);
1409  }
1410 
1411  if( nbilinterms > 0 )
1412  {
1413  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->bilinterms, bilinterms, nbilinterms) );
1414  (*consdata)->nbilinterms = nbilinterms;
1415  (*consdata)->bilintermssize = nbilinterms;
1416  }
1417  else
1418  {
1419  (*consdata)->bilinsorted = TRUE;
1420  (*consdata)->bilinmerged = TRUE;
1421  }
1422 
1423  (*consdata)->linvar_maydecrease = -1;
1424  (*consdata)->linvar_mayincrease = -1;
1425 
1426  (*consdata)->activity = SCIP_INVALID;
1427  (*consdata)->lhsviol = SCIPisInfinity(scip, -lhs) ? 0.0 : SCIP_INVALID;
1428  (*consdata)->rhsviol = SCIPisInfinity(scip, rhs) ? 0.0 : SCIP_INVALID;
1429 
1430  (*consdata)->isgaugeavailable = FALSE;
1431 
1432  return SCIP_OKAY;
1433 }
1434 
1435 /** frees constraint data structure */
1436 static
1438  SCIP* scip, /**< SCIP data structure */
1439  SCIP_CONSDATA** consdata /**< pointer to constraint data to free */
1440  )
1441 {
1442  int i;
1443 
1444  assert(scip != NULL);
1445  assert(consdata != NULL);
1446  assert(*consdata != NULL);
1447 
1448  /* free sepa arrays, may exists if constraint is deleted in solving stage */
1449  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->sepaquadvars, (*consdata)->nquadvars);
1450  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->sepabilinvar2pos, (*consdata)->nbilinterms);
1451 
1452  /* release linear variables and free linear part */
1453  if( (*consdata)->linvarssize > 0 )
1454  {
1455  for( i = 0; i < (*consdata)->nlinvars; ++i )
1456  {
1457  assert((*consdata)->lineventdata == NULL || (*consdata)->lineventdata[i] == NULL); /* variable events should have been dropped earlier */
1458  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->linvars[i]) );
1459  }
1460  SCIPfreeBlockMemoryArray(scip, &(*consdata)->linvars, (*consdata)->linvarssize);
1461  SCIPfreeBlockMemoryArray(scip, &(*consdata)->lincoefs, (*consdata)->linvarssize);
1462  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->lineventdata, (*consdata)->linvarssize);
1463  }
1464  assert((*consdata)->linvars == NULL);
1465  assert((*consdata)->lincoefs == NULL);
1466  assert((*consdata)->lineventdata == NULL);
1467 
1468  /* release quadratic variables and free quadratic variable term part */
1469  for( i = 0; i < (*consdata)->nquadvars; ++i )
1470  {
1471  assert((*consdata)->quadvarterms[i].eventdata == NULL); /* variable events should have been dropped earlier */
1472  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->quadvarterms[i].adjbilin, (*consdata)->quadvarterms[i].adjbilinsize);
1473  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->quadvarterms[i].var) );
1474  }
1475  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->quadvarterms, (*consdata)->quadvarssize);
1476 
1477  /* free bilinear terms */
1478  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bilinterms, (*consdata)->bilintermssize);
1479 
1480  /* free nonlinear row representation */
1481  if( (*consdata)->nlrow != NULL )
1482  {
1483  SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
1484  }
1485 
1486  /* free interior point information, may exists if constraint is deleted in solving stage */
1487  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->interiorpoint, (*consdata)->nquadvars);
1488  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->gaugecoefs, (*consdata)->nquadvars);
1489 
1490  /* free eigen decomposition information */
1491  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->eigenvalues, (*consdata)->nquadvars);
1492  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->eigenvectors, (int)((*consdata)->nquadvars*(*consdata)->nquadvars));
1493  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bp, (*consdata)->nquadvars);
1494 
1495  /* free unique indices of bilinear terms array */
1496  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bilintermsidx, (*consdata)->nbilinterms);
1497 
1498  SCIPfreeBlockMemory(scip, consdata);
1499  *consdata = NULL;
1500 
1501  return SCIP_OKAY;
1502 }
1503 
1504 /** sorts linear part of constraint data */
1505 static
1507  SCIP_CONSDATA* consdata /**< quadratic constraint data */
1508  )
1509 {
1510  assert(consdata != NULL);
1511 
1512  if( consdata->linvarssorted )
1513  return;
1514 
1515  if( consdata->nlinvars <= 1 )
1516  {
1517  consdata->linvarssorted = TRUE;
1518  return;
1519  }
1520 
1521  if( consdata->lineventdata == NULL )
1522  {
1523  SCIPsortPtrReal((void**)consdata->linvars, consdata->lincoefs, SCIPvarComp, consdata->nlinvars);
1524  }
1525  else
1526  {
1527  int i;
1528 
1529  SCIPsortPtrPtrReal((void**)consdata->linvars, (void**)consdata->lineventdata, consdata->lincoefs, SCIPvarComp, consdata->nlinvars);
1530 
1531  /* update variable indices in event data */
1532  for( i = 0; i < consdata->nlinvars; ++i )
1533  if( consdata->lineventdata[i] != NULL )
1534  consdata->lineventdata[i]->varidx = i;
1535  }
1536 
1537  consdata->linvarssorted = TRUE;
1538 }
1539 
1540 #ifdef SCIP_DISABLED_CODE /* no-one needs this routine currently */
1541 /** returns the position of variable in the linear coefficients array of a constraint, or -1 if not found */
1542 static
1543 int consdataFindLinearVar(
1544  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1545  SCIP_VAR* var /**< variable to search for */
1546  )
1547 {
1548  int pos;
1549 
1550  assert(consdata != NULL);
1551  assert(var != NULL);
1552 
1553  if( consdata->nlinvars == 0 )
1554  return -1;
1555 
1556  consdataSortLinearVars(consdata);
1557 
1558  if( !SCIPsortedvecFindPtr((void**)consdata->linvars, SCIPvarComp, (void*)var, consdata->nlinvars, &pos) )
1559  pos = -1;
1560 
1561  return pos;
1562 }
1563 #endif
1564 
1565 /** index comparison method for quadratic variable terms: compares two indices of the quadratic variable set in the quadratic constraint */
1566 static
1567 SCIP_DECL_SORTINDCOMP(quadVarTermComp)
1568 { /*lint --e{715}*/
1569  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
1570 
1571  assert(consdata != NULL);
1572  assert(0 <= ind1 && ind1 < consdata->nquadvars);
1573  assert(0 <= ind2 && ind2 < consdata->nquadvars);
1574 
1575  return SCIPvarCompare(consdata->quadvarterms[ind1].var, consdata->quadvarterms[ind2].var);
1576 }
1577 
1578 /** sorting of quadratic variable terms */
1579 static
1581  SCIP* scip, /**< SCIP data structure */
1582  SCIP_CONSDATA* consdata /**< quadratic constraint data */
1583  )
1584 {
1585  int* perm;
1586  int i;
1587  int nexti;
1588  int v;
1589  SCIP_QUADVARTERM quadterm;
1590 
1591  assert(scip != NULL);
1592  assert(consdata != NULL);
1593 
1594  if( consdata->quadvarssorted )
1595  return SCIP_OKAY;
1596 
1597  if( consdata->nquadvars == 0 )
1598  {
1599  consdata->quadvarssorted = TRUE;
1600  return SCIP_OKAY;
1601  }
1602 
1603  /* get temporary memory to store the sorted permutation */
1604  SCIP_CALL( SCIPallocBufferArray(scip, &perm, consdata->nquadvars) );
1605 
1606  /* call bubble sort */
1607  SCIPsort(perm, quadVarTermComp, (void*)consdata, consdata->nquadvars);
1608 
1609  /* permute the quadratic variable terms according to the resulting permutation */
1610  for( v = 0; v < consdata->nquadvars; ++v )
1611  {
1612  if( perm[v] != v )
1613  {
1614  quadterm = consdata->quadvarterms[v];
1615 
1616  i = v;
1617  do
1618  {
1619  assert(0 <= perm[i] && perm[i] < consdata->nquadvars);
1620  assert(perm[i] != i);
1621  consdata->quadvarterms[i] = consdata->quadvarterms[perm[i]];
1622  if( consdata->quadvarterms[i].eventdata != NULL )
1623  {
1624  consdata->quadvarterms[i].eventdata->varidx = -i-1;
1625  }
1626  nexti = perm[i];
1627  perm[i] = i;
1628  i = nexti;
1629  }
1630  while( perm[i] != v );
1631  consdata->quadvarterms[i] = quadterm;
1632  if( consdata->quadvarterms[i].eventdata != NULL )
1633  {
1634  consdata->quadvarterms[i].eventdata->varidx = -i-1;
1635  }
1636  perm[i] = i;
1637  }
1638  }
1639  consdata->quadvarssorted = TRUE;
1640 
1641  /* free temporary memory */
1642  SCIPfreeBufferArray(scip, &perm);
1643 
1644  return SCIP_OKAY;
1645 }
1646 
1647 /** returns the position of variable in the quadratic variable terms array of a constraint, or -1 if not found */
1648 static
1650  SCIP* scip, /**< SCIP data structure */
1651  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1652  SCIP_VAR* var, /**< variable to search for */
1653  int* pos /**< buffer where to store position of var in quadvarterms array, or -1 if not found */
1654  )
1655 {
1656  int left;
1657  int right;
1658  int cmpres;
1659 
1660  assert(consdata != NULL);
1661  assert(var != NULL);
1662  assert(pos != NULL);
1663 
1664  if( consdata->nquadvars == 0 )
1665  {
1666  *pos = -1;
1667  return SCIP_OKAY;
1668  }
1669 
1670  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
1671 
1672  left = 0;
1673  right = consdata->nquadvars - 1;
1674  while( left <= right )
1675  {
1676  int middle;
1677 
1678  middle = (left+right)/2;
1679  assert(0 <= middle && middle < consdata->nquadvars);
1680 
1681  cmpres = SCIPvarCompare(var, consdata->quadvarterms[middle].var);
1682 
1683  if( cmpres < 0 )
1684  right = middle - 1;
1685  else if( cmpres > 0 )
1686  left = middle + 1;
1687  else
1688  {
1689  *pos = middle;
1690  return SCIP_OKAY;
1691  }
1692  }
1693  assert(left == right+1);
1694 
1695  *pos = -1;
1696 
1697  return SCIP_OKAY;
1698 }
1699 
1700 /** index comparison method for bilinear terms: compares two index pairs of the bilinear term set in the quadratic constraint */
1701 static
1702 SCIP_DECL_SORTINDCOMP(bilinTermComp)
1703 { /*lint --e{715}*/
1704  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
1705  int var1cmp;
1706 
1707  assert(consdata != NULL);
1708  assert(0 <= ind1 && ind1 < consdata->nbilinterms);
1709  assert(0 <= ind2 && ind2 < consdata->nbilinterms);
1710 
1711  var1cmp = SCIPvarCompare(consdata->bilinterms[ind1].var1, consdata->bilinterms[ind2].var1);
1712  if( var1cmp != 0 )
1713  return var1cmp;
1714 
1715  return SCIPvarCompare(consdata->bilinterms[ind1].var2, consdata->bilinterms[ind2].var2);
1716 }
1717 
1718 #ifndef NDEBUG
1719 /** checks if all bilinear terms are sorted correctly */
1720 static
1722  SCIP_CONSDATA* consdata
1723  )
1724 {
1725  int i;
1726 
1727  assert(consdata != NULL);
1728 
1729  /* nothing to check if the bilinear terms have not been sorted yet */
1730  if( !consdata->bilinsorted )
1731  return TRUE;
1732 
1733  for( i = 0; i < consdata->nbilinterms - 1; ++i )
1734  {
1735  if( bilinTermComp(consdata, i, i+1) > 0 )
1736  return FALSE;
1737  }
1738  return TRUE;
1739 }
1740 #endif
1741 
1742 /** sorting of bilinear terms */
1743 static
1745  SCIP* scip, /**< SCIP data structure */
1746  SCIP_CONSDATA* consdata /**< quadratic constraint data */
1747  )
1748 {
1749  int* perm;
1750  int* invperm;
1751  int i;
1752  int nexti;
1753  int v;
1754  SCIP_BILINTERM bilinterm;
1755 
1756  assert(scip != NULL);
1757  assert(consdata != NULL);
1758 
1759  if( consdata->bilinsorted )
1760  return SCIP_OKAY;
1761 
1762  if( consdata->nbilinterms == 0 )
1763  {
1764  consdata->bilinsorted = TRUE;
1765  return SCIP_OKAY;
1766  }
1767 
1768  /* get temporary memory to store the sorted permutation and the inverse permutation */
1769  SCIP_CALL( SCIPallocBufferArray(scip, &perm, consdata->nbilinterms) );
1770  SCIP_CALL( SCIPallocBufferArray(scip, &invperm, consdata->nbilinterms) );
1771 
1772  /* call bubble sort */
1773  SCIPsort(perm, bilinTermComp, (void*)consdata, consdata->nbilinterms);
1774 
1775  /* compute inverted permutation */
1776  for( v = 0; v < consdata->nbilinterms; ++v )
1777  {
1778  assert(0 <= perm[v] && perm[v] < consdata->nbilinterms);
1779  invperm[perm[v]] = v;
1780  }
1781 
1782  /* permute the bilinear terms according to the resulting permutation */
1783  for( v = 0; v < consdata->nbilinterms; ++v )
1784  {
1785  if( perm[v] != v )
1786  {
1787  bilinterm = consdata->bilinterms[v];
1788 
1789  i = v;
1790  do
1791  {
1792  assert(0 <= perm[i] && perm[i] < consdata->nbilinterms);
1793  assert(perm[i] != i);
1794  consdata->bilinterms[i] = consdata->bilinterms[perm[i]];
1795  nexti = perm[i];
1796  perm[i] = i;
1797  i = nexti;
1798  }
1799  while( perm[i] != v );
1800  consdata->bilinterms[i] = bilinterm;
1801  perm[i] = i;
1802  }
1803  }
1804 
1805  /* update the adjacency information in the quadratic variable terms */
1806  for( v = 0; v < consdata->nquadvars; ++v )
1807  for( i = 0; i < consdata->quadvarterms[v].nadjbilin; ++i )
1808  consdata->quadvarterms[v].adjbilin[i] = invperm[consdata->quadvarterms[v].adjbilin[i]];
1809 
1810  consdata->bilinsorted = TRUE;
1811  assert(consdataCheckBilinTermsSort(consdata));
1812 
1813  /* free temporary memory */
1814  SCIPfreeBufferArray(scip, &invperm);
1815  SCIPfreeBufferArray(scip, &perm);
1816 
1817  return SCIP_OKAY;
1818 }
1819 
1820 /** moves a linear variable from one position to another */
1821 static
1823  SCIP_CONSDATA* consdata, /**< constraint data */
1824  int oldpos, /**< position of variable that shall be moved */
1825  int newpos /**< new position of variable */
1826  )
1827 {
1828  assert(consdata != NULL);
1829  assert(oldpos >= 0);
1830  assert(oldpos < consdata->nlinvars);
1831  assert(newpos >= 0);
1832  assert(newpos < consdata->linvarssize);
1833 
1834  if( newpos == oldpos )
1835  return;
1836 
1837  consdata->linvars [newpos] = consdata->linvars [oldpos];
1838  consdata->lincoefs[newpos] = consdata->lincoefs[oldpos];
1839 
1840  if( consdata->lineventdata != NULL )
1841  {
1842  assert(newpos >= consdata->nlinvars || consdata->lineventdata[newpos] == NULL);
1843 
1844  consdata->lineventdata[newpos] = consdata->lineventdata[oldpos];
1845  consdata->lineventdata[newpos]->varidx = newpos;
1846 
1847  consdata->lineventdata[oldpos] = NULL;
1848  }
1849 
1850  consdata->linvarssorted = FALSE;
1851 }
1852 
1853 /** moves a quadratic variable from one position to another */
1854 static
1856  SCIP_CONSDATA* consdata, /**< constraint data */
1857  int oldpos, /**< position of variable that shall be moved */
1858  int newpos /**< new position of variable */
1859  )
1860 {
1861  assert(consdata != NULL);
1862  assert(oldpos >= 0);
1863  assert(oldpos < consdata->nquadvars);
1864  assert(newpos >= 0);
1865  assert(newpos < consdata->quadvarssize);
1866 
1867  if( newpos == oldpos )
1868  return;
1869 
1870  assert(newpos >= consdata->nquadvars || consdata->quadvarterms[newpos].eventdata == NULL);
1871 
1872  consdata->quadvarterms[newpos] = consdata->quadvarterms[oldpos];
1873 
1874  if( consdata->quadvarterms[newpos].eventdata != NULL )
1875  {
1876  consdata->quadvarterms[newpos].eventdata->varidx = -newpos-1;
1877  consdata->quadvarterms[oldpos].eventdata = NULL;
1878  }
1879 
1880  consdata->quadvarssorted = FALSE;
1881 }
1882 
1883 /** adds linear coefficient in quadratic constraint */
1884 static
1886  SCIP* scip, /**< SCIP data structure */
1887  SCIP_CONS* cons, /**< quadratic constraint */
1888  SCIP_VAR* var, /**< variable of constraint entry */
1889  SCIP_Real coef /**< coefficient of constraint entry */
1890  )
1891 {
1892  SCIP_CONSDATA* consdata;
1893  SCIP_Bool transformed;
1894 
1895  assert(scip != NULL);
1896  assert(cons != NULL);
1897  assert(var != NULL);
1898 
1899  /* ignore coefficient if it is nearly zero */
1900  if( SCIPisZero(scip, coef) )
1901  return SCIP_OKAY;
1902 
1903  consdata = SCIPconsGetData(cons);
1904  assert(consdata != NULL);
1905 
1906  /* are we in the transformed problem? */
1907  transformed = SCIPconsIsTransformed(cons);
1908 
1909  /* always use transformed variables in transformed constraints */
1910  if( transformed )
1911  {
1912  SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
1913  }
1914  assert(var != NULL);
1915  assert(transformed == SCIPvarIsTransformed(var));
1916 
1917  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars+1) );
1918  consdata->linvars [consdata->nlinvars] = var;
1919  consdata->lincoefs[consdata->nlinvars] = coef;
1920 
1921  ++consdata->nlinvars;
1922 
1923  /* catch variable events */
1924  if( SCIPconsIsEnabled(cons) )
1925  {
1926  SCIP_CONSHDLR* conshdlr;
1927  SCIP_CONSHDLRDATA* conshdlrdata;
1928 
1929  /* get event handler */
1930  conshdlr = SCIPconsGetHdlr(cons);
1931  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1932  assert(conshdlrdata != NULL);
1933  assert(conshdlrdata->eventhdlr != NULL);
1934 
1935  assert(consdata->lineventdata != NULL);
1936  consdata->lineventdata[consdata->nlinvars-1] = NULL;
1937 
1938  /* catch bound change events of variable */
1939  SCIP_CALL( catchLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, consdata->nlinvars-1) );
1940  }
1941 
1942  /* invalidate activity information */
1943  consdata->activity = SCIP_INVALID;
1944  consdata->minlinactivity = SCIP_INVALID;
1945  consdata->maxlinactivity = SCIP_INVALID;
1946  consdata->minlinactivityinf = -1;
1947  consdata->maxlinactivityinf = -1;
1948 
1949  /* invalidate nonlinear row */
1950  if( consdata->nlrow != NULL )
1951  {
1952  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1953  }
1954 
1955  /* install rounding locks for new variable */
1956  SCIP_CALL( lockLinearVariable(scip, cons, var, coef) );
1957 
1958  /* capture new variable */
1959  SCIP_CALL( SCIPcaptureVar(scip, var) );
1960 
1961  consdata->ispropagated = FALSE;
1962  consdata->ispresolved = FALSE;
1963  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var)
1964  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
1965  if( consdata->nlinvars == 1 )
1966  consdata->linvarssorted = TRUE;
1967  else
1968  consdata->linvarssorted = consdata->linvarssorted && (SCIPvarCompare(consdata->linvars[consdata->nlinvars-2], consdata->linvars[consdata->nlinvars-1]) == -1);
1969  /* always set too FALSE since the new linear variable should be checked if already existing as quad var term */
1970  consdata->linvarsmerged = FALSE;
1971 
1972  return SCIP_OKAY;
1973 }
1974 
1975 /** deletes linear coefficient at given position from quadratic constraint data */
1976 static
1978  SCIP* scip, /**< SCIP data structure */
1979  SCIP_CONS* cons, /**< quadratic constraint */
1980  int pos /**< position of coefficient to delete */
1981  )
1982 {
1983  SCIP_CONSDATA* consdata;
1984  SCIP_VAR* var;
1985  SCIP_Real coef;
1986 
1987  assert(scip != NULL);
1988  assert(cons != NULL);
1989 
1990  consdata = SCIPconsGetData(cons);
1991  assert(consdata != NULL);
1992  assert(0 <= pos && pos < consdata->nlinvars);
1993 
1994  var = consdata->linvars[pos];
1995  coef = consdata->lincoefs[pos];
1996  assert(var != NULL);
1997 
1998  /* remove rounding locks for deleted variable */
1999  SCIP_CALL( unlockLinearVariable(scip, cons, var, coef) );
2000 
2001  /* if we catch variable events, drop the events on the variable */
2002  if( consdata->lineventdata != NULL )
2003  {
2004  SCIP_CONSHDLR* conshdlr;
2005  SCIP_CONSHDLRDATA* conshdlrdata;
2006 
2007  /* get event handler */
2008  conshdlr = SCIPconsGetHdlr(cons);
2009  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2010  assert(conshdlrdata != NULL);
2011  assert(conshdlrdata->eventhdlr != NULL);
2012 
2013  /* drop bound change events of variable */
2014  SCIP_CALL( dropLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
2015  }
2016 
2017  /* release variable */
2018  SCIP_CALL( SCIPreleaseVar(scip, &consdata->linvars[pos]) );
2019 
2020  /* move the last variable to the free slot */
2021  consdataMoveLinearVar(consdata, consdata->nlinvars-1, pos);
2022 
2023  --consdata->nlinvars;
2024 
2025  /* invalidate activity */
2026  consdata->activity = SCIP_INVALID;
2027  consdata->minlinactivity = SCIP_INVALID;
2028  consdata->maxlinactivity = SCIP_INVALID;
2029  consdata->minlinactivityinf = -1;
2030  consdata->maxlinactivityinf = -1;
2031 
2032  /* invalidate nonlinear row */
2033  if( consdata->nlrow != NULL )
2034  {
2035  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2036  }
2037 
2038  consdata->ispropagated = FALSE;
2039  consdata->ispresolved = FALSE;
2040 
2041  return SCIP_OKAY;
2042 }
2043 
2044 /** changes linear coefficient value at given position of quadratic constraint */
2045 static
2047  SCIP* scip, /**< SCIP data structure */
2048  SCIP_CONS* cons, /**< quadratic constraint */
2049  int pos, /**< position of linear coefficient to change */
2050  SCIP_Real newcoef /**< new value of linear coefficient */
2051  )
2052 {
2053  SCIP_CONSHDLR* conshdlr;
2054  SCIP_CONSHDLRDATA* conshdlrdata;
2055  SCIP_CONSDATA* consdata;
2056  SCIP_VAR* var;
2057  SCIP_Real coef;
2058 
2059  assert(scip != NULL);
2060  assert(cons != NULL);
2062  assert(!SCIPisZero(scip, newcoef));
2063 
2064  conshdlrdata = NULL;
2065 
2066  consdata = SCIPconsGetData(cons);
2067  assert(consdata != NULL);
2068  assert(0 <= pos);
2069  assert(pos < consdata->nlinvars);
2070  assert(!SCIPisZero(scip, newcoef));
2071 
2072  var = consdata->linvars[pos];
2073  coef = consdata->lincoefs[pos];
2074  assert(var != NULL);
2075  assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
2076 
2077  /* invalidate activity */
2078  consdata->activity = SCIP_INVALID;
2079  consdata->minlinactivity = SCIP_INVALID;
2080  consdata->maxlinactivity = SCIP_INVALID;
2081  consdata->minlinactivityinf = -1;
2082  consdata->maxlinactivityinf = -1;
2083 
2084  /* invalidate nonlinear row */
2085  if( consdata->nlrow != NULL )
2086  {
2087  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2088  }
2089 
2090  /* if necessary, remove the rounding locks and event catching of the variable */
2091  if( newcoef * coef < 0.0 )
2092  {
2093  if( SCIPconsIsLocked(cons) )
2094  {
2095  assert(SCIPconsIsTransformed(cons));
2096 
2097  /* remove rounding locks for variable with old coefficient */
2098  SCIP_CALL( unlockLinearVariable(scip, cons, var, coef) );
2099  }
2100 
2101  if( consdata->lineventdata[pos] != NULL )
2102  {
2103  /* get event handler */
2104  conshdlr = SCIPconsGetHdlr(cons);
2105  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2106  assert(conshdlrdata != NULL);
2107  assert(conshdlrdata->eventhdlr != NULL);
2108 
2109  /* drop bound change events of variable */
2110  SCIP_CALL( dropLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
2111  }
2112  }
2113 
2114  /* change the coefficient */
2115  consdata->lincoefs[pos] = newcoef;
2116 
2117  /* if necessary, install the rounding locks and event catching of the variable again */
2118  if( newcoef * coef < 0.0 )
2119  {
2120  if( SCIPconsIsLocked(cons) )
2121  {
2122  /* install rounding locks for variable with new coefficient */
2123  SCIP_CALL( lockLinearVariable(scip, cons, var, newcoef) );
2124  }
2125 
2126  if( conshdlrdata != NULL )
2127  {
2128  assert(SCIPconsIsEnabled(cons));
2129 
2130  /* catch bound change events of variable */
2131  SCIP_CALL( catchLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
2132  }
2133  }
2134 
2135  consdata->ispropagated = FALSE;
2136  consdata->ispresolved = FALSE;
2137 
2138  return SCIP_OKAY;
2139 }
2140 
2141 /** adds quadratic variable term to quadratic constraint */
2142 static
2144  SCIP* scip, /**< SCIP data structure */
2145  SCIP_CONS* cons, /**< quadratic constraint */
2146  SCIP_VAR* var, /**< variable to add */
2147  SCIP_Real lincoef, /**< linear coefficient of variable */
2148  SCIP_Real sqrcoef /**< square coefficient of variable */
2149  )
2150 {
2151  SCIP_CONSDATA* consdata;
2152  SCIP_Bool transformed;
2153  SCIP_QUADVARTERM* quadvarterm;
2154 
2155  assert(scip != NULL);
2156  assert(cons != NULL);
2157  assert(var != NULL);
2158 
2159  consdata = SCIPconsGetData(cons);
2160  assert(consdata != NULL);
2161 
2162  /* are we in the transformed problem? */
2163  transformed = SCIPconsIsTransformed(cons);
2164 
2165  /* always use transformed variables in transformed constraints */
2166  if( transformed )
2167  {
2168  SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
2169  }
2170  assert(var != NULL);
2171  assert(transformed == SCIPvarIsTransformed(var));
2172 
2173  SCIP_CALL( consdataEnsureQuadVarTermsSize(scip, consdata, consdata->nquadvars+1) );
2174 
2175  quadvarterm = &consdata->quadvarterms[consdata->nquadvars];
2176  quadvarterm->var = var;
2177  quadvarterm->lincoef = lincoef;
2178  quadvarterm->sqrcoef = sqrcoef;
2179  quadvarterm->adjbilinsize = 0;
2180  quadvarterm->nadjbilin = 0;
2181  quadvarterm->adjbilin = NULL;
2182  quadvarterm->eventdata = NULL;
2183 
2184  ++consdata->nquadvars;
2185 
2186  /* capture variable */
2187  SCIP_CALL( SCIPcaptureVar(scip, var) );
2188 
2189  /* catch variable events, if we do so */
2190  if( SCIPconsIsEnabled(cons) )
2191  {
2192  SCIP_CONSHDLR* conshdlr;
2193  SCIP_CONSHDLRDATA* conshdlrdata;
2194 
2195  /* get event handler */
2196  conshdlr = SCIPconsGetHdlr(cons);
2197  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2198  assert(conshdlrdata != NULL);
2199  assert(conshdlrdata->eventhdlr != NULL);
2200 
2201  /* catch bound change events of variable */
2202  SCIP_CALL( catchQuadVarEvents(scip, conshdlrdata->eventhdlr, cons, consdata->nquadvars-1) );
2203  }
2204 
2205  /* invalidate activity information */
2206  consdata->activity = SCIP_INVALID;
2207  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2208 
2209  /* invalidate nonlinear row */
2210  if( consdata->nlrow != NULL )
2211  {
2212  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2213  }
2214 
2215  /* install rounding locks for new variable */
2216  SCIP_CALL( lockQuadraticVariable(scip, cons, var) );
2217 
2218  consdata->ispropagated = FALSE;
2219  consdata->ispresolved = FALSE;
2220  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var)
2221  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
2222  if( consdata->nquadvars == 1 )
2223  consdata->quadvarssorted = TRUE;
2224  else
2225  consdata->quadvarssorted = consdata->quadvarssorted &&
2226  (SCIPvarCompare(consdata->quadvarterms[consdata->nquadvars-2].var, consdata->quadvarterms[consdata->nquadvars-1].var) == -1);
2227  /* also set to FALSE if nquadvars == 1, since the new variable should be checked for linearity and other stuff in mergeAndClean ... */
2228  consdata->quadvarsmerged = FALSE;
2229 
2230  consdata->iscurvchecked = FALSE;
2231 
2232  return SCIP_OKAY;
2233 }
2234 
2235 /** deletes quadratic variable term at given position from quadratic constraint data */
2236 static
2238  SCIP* scip, /**< SCIP data structure */
2239  SCIP_CONS* cons, /**< quadratic constraint */
2240  int pos /**< position of term to delete */
2241  )
2242 {
2243  SCIP_CONSDATA* consdata;
2244  SCIP_VAR* var;
2245 
2246  assert(scip != NULL);
2247  assert(cons != NULL);
2248 
2249  consdata = SCIPconsGetData(cons);
2250  assert(consdata != NULL);
2251  assert(0 <= pos && pos < consdata->nquadvars);
2252 
2253  var = consdata->quadvarterms[pos].var;
2254  assert(var != NULL);
2255  assert(consdata->quadvarterms[pos].nadjbilin == 0);
2256 
2257  /* remove rounding locks for deleted variable */
2258  SCIP_CALL( unlockQuadraticVariable(scip, cons, var) );
2259 
2260  /* if we catch variable events, drop the events on the variable */
2261  if( consdata->quadvarterms[pos].eventdata != NULL )
2262  {
2263  SCIP_CONSHDLR* conshdlr;
2264  SCIP_CONSHDLRDATA* conshdlrdata;
2265 
2266  /* get event handler */
2267  conshdlr = SCIPconsGetHdlr(cons);
2268  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2269  assert(conshdlrdata != NULL);
2270  assert(conshdlrdata->eventhdlr != NULL);
2271 
2272  /* drop bound change events of variable */
2273  SCIP_CALL( dropQuadVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
2274  }
2275 
2276  /* release variable */
2277  SCIP_CALL( SCIPreleaseVar(scip, &consdata->quadvarterms[pos].var) );
2278 
2279  /* free adjacency array */
2280  SCIPfreeBlockMemoryArrayNull(scip, &consdata->quadvarterms[pos].adjbilin, consdata->quadvarterms[pos].adjbilinsize);
2281 
2282  /* move the last variable term to the free slot */
2283  consdataMoveQuadVarTerm(consdata, consdata->nquadvars-1, pos);
2284 
2285  --consdata->nquadvars;
2286 
2287  /* invalidate activity */
2288  consdata->activity = SCIP_INVALID;
2289  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2290 
2291  /* invalidate nonlinear row */
2292  if( consdata->nlrow != NULL )
2293  {
2294  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2295  }
2296 
2297  consdata->ispropagated = FALSE;
2298  consdata->ispresolved = FALSE;
2299  consdata->iscurvchecked = FALSE;
2300 
2301  return SCIP_OKAY;
2302 }
2303 
2304 /** replace variable in quadratic variable term at given position of quadratic constraint data
2305  *
2306  * Allows to replace x by coef*y+offset, thereby maintaining linear and square coefficients and bilinear terms.
2307  */
2308 static
2310  SCIP* scip, /**< SCIP data structure */
2311  SCIP_CONS* cons, /**< quadratic constraint */
2312  int pos, /**< position of term to replace */
2313  SCIP_VAR* var, /**< new variable */
2314  SCIP_Real coef, /**< linear coefficient of new variable */
2315  SCIP_Real offset /**< offset of new variable */
2316  )
2317 {
2318  SCIP_CONSDATA* consdata;
2319  SCIP_QUADVARTERM* quadvarterm;
2320  SCIP_EVENTHDLR* eventhdlr;
2321  SCIP_BILINTERM* bilinterm;
2322  SCIP_Real constant;
2323 
2324  int i;
2325  SCIP_VAR* var2;
2326 
2327  consdata = SCIPconsGetData(cons);
2328  assert(consdata != NULL);
2329  assert(pos >= 0);
2330  assert(pos < consdata->nquadvars);
2331 
2332  quadvarterm = &consdata->quadvarterms[pos];
2333 
2334  /* remove rounding locks for old variable */
2335  SCIP_CALL( unlockQuadraticVariable(scip, cons, quadvarterm->var) );
2336 
2337  /* if we catch variable events, drop the events on the old variable */
2338  if( quadvarterm->eventdata != NULL )
2339  {
2340  SCIP_CONSHDLR* conshdlr;
2341  SCIP_CONSHDLRDATA* conshdlrdata;
2342 
2343  /* get event handler */
2344  conshdlr = SCIPconsGetHdlr(cons);
2345  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2346  assert(conshdlrdata != NULL);
2347  assert(conshdlrdata->eventhdlr != NULL);
2348 
2349  eventhdlr = conshdlrdata->eventhdlr;
2350 
2351  /* drop bound change events of variable */
2352  SCIP_CALL( dropQuadVarEvents(scip, eventhdlr, cons, pos) );
2353  }
2354  else
2355  {
2356  eventhdlr = NULL;
2357  }
2358 
2359  /* compute constant and put into lhs/rhs */
2360  constant = quadvarterm->lincoef * offset + quadvarterm->sqrcoef * offset * offset;
2361  if( constant != 0.0 )
2362  {
2363  /* maintain constant part */
2364  if( !SCIPisInfinity(scip, -consdata->lhs) )
2365  consdata->lhs -= constant;
2366  if( !SCIPisInfinity(scip, consdata->rhs) )
2367  consdata->rhs -= constant;
2368  }
2369 
2370  /* update linear and square coefficient */
2371  quadvarterm->lincoef *= coef;
2372  quadvarterm->lincoef += 2.0 * quadvarterm->sqrcoef * coef * offset;
2373  quadvarterm->sqrcoef *= coef * coef;
2374 
2375  /* update bilinear terms */
2376  for( i = 0; i < quadvarterm->nadjbilin; ++i )
2377  {
2378  bilinterm = &consdata->bilinterms[quadvarterm->adjbilin[i]];
2379 
2380  if( bilinterm->var1 == quadvarterm->var )
2381  {
2382  bilinterm->var1 = var;
2383  var2 = bilinterm->var2;
2384  }
2385  else
2386  {
2387  assert(bilinterm->var2 == quadvarterm->var);
2388  bilinterm->var2 = var;
2389  var2 = bilinterm->var1;
2390  }
2391 
2392  if( var == var2 )
2393  {
2394  /* looks like we actually have a square term here */
2395  quadvarterm->lincoef += bilinterm->coef * offset;
2396  quadvarterm->sqrcoef += bilinterm->coef * coef;
2397  /* deleting bilinear terms is expensive, since it requires updating adjacency information
2398  * thus, for now we just set the coefficient to 0.0 and clear in later when the bilinear terms are merged */
2399  bilinterm->coef = 0.0;
2400  continue;
2401  }
2402 
2403  /* swap var1 and var2 if they are in wrong order */
2404  if( SCIPvarCompare(bilinterm->var1, bilinterm->var2) > 0 )
2405  {
2406  SCIP_VAR* tmp;
2407  tmp = bilinterm->var1;
2408  bilinterm->var1 = bilinterm->var2;
2409  bilinterm->var2 = tmp;
2410  }
2411  assert(SCIPvarCompare(bilinterm->var1, bilinterm->var2) == -1);
2412 
2413  if( offset != 0.0 )
2414  {
2415  /* need to find var2 and add offset*bilinterm->coef to linear coefficient */
2416  int var2pos;
2417 
2418  var2pos = 0;
2419  while( consdata->quadvarterms[var2pos].var != var2 )
2420  {
2421  ++var2pos;
2422  assert(var2pos < consdata->nquadvars);
2423  }
2424 
2425  consdata->quadvarterms[var2pos].lincoef += bilinterm->coef * offset;
2426  }
2427 
2428  bilinterm->coef *= coef;
2429  }
2430 
2431  /* release old variable */
2432  SCIP_CALL( SCIPreleaseVar(scip, &quadvarterm->var) );
2433 
2434  /* set new variable */
2435  quadvarterm->var = var;
2436 
2437  /* capture new variable */
2438  SCIP_CALL( SCIPcaptureVar(scip, quadvarterm->var) );
2439 
2440  /* catch variable events, if we do so */
2441  if( eventhdlr != NULL )
2442  {
2443  assert(SCIPconsIsEnabled(cons));
2444 
2445  /* catch bound change events of variable */
2446  SCIP_CALL( catchQuadVarEvents(scip, eventhdlr, cons, pos) );
2447  }
2448 
2449  /* invalidate activity information */
2450  consdata->activity = SCIP_INVALID;
2451  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2452 
2453  /* invalidate nonlinear row */
2454  if( consdata->nlrow != NULL )
2455  {
2456  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2457  }
2458 
2459  /* install rounding locks for new variable */
2460  SCIP_CALL( lockQuadraticVariable(scip, cons, var) );
2461 
2462  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var)
2463  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
2464  consdata->quadvarssorted = (consdata->nquadvars == 1);
2465  consdata->quadvarsmerged = FALSE;
2466  consdata->bilinsorted &= (quadvarterm->nadjbilin == 0); /*lint !e514*/
2467  consdata->bilinmerged &= (quadvarterm->nadjbilin == 0); /*lint !e514*/
2468 
2469  consdata->ispropagated = FALSE;
2470  consdata->ispresolved = FALSE;
2471  consdata->iscurvchecked = FALSE;
2472 
2473  return SCIP_OKAY;
2474 }
2475 
2476 /** adds a bilinear term to quadratic constraint */
2477 static
2479  SCIP* scip, /**< SCIP data structure */
2480  SCIP_CONS* cons, /**< quadratic constraint */
2481  int var1pos, /**< position of first variable in quadratic variables array */
2482  int var2pos, /**< position of second variable in quadratic variables array */
2483  SCIP_Real coef /**< coefficient of bilinear term */
2484  )
2485 {
2486  SCIP_CONSDATA* consdata;
2487  SCIP_BILINTERM* bilinterm;
2488 
2489  assert(scip != NULL);
2490  assert(cons != NULL);
2491 
2492  if( var1pos == var2pos )
2493  {
2494  SCIPerrorMessage("tried to add bilinear term where both variables are the same\n");
2495  return SCIP_INVALIDDATA;
2496  }
2497 
2498  consdata = SCIPconsGetData(cons);
2499  assert(consdata != NULL);
2500 
2501  /* check if the bilinear terms are sorted */
2502  assert(consdataCheckBilinTermsSort(consdata));
2503 
2504  assert(var1pos >= 0);
2505  assert(var1pos < consdata->nquadvars);
2506  assert(var2pos >= 0);
2507  assert(var2pos < consdata->nquadvars);
2508 
2509  SCIP_CALL( consdataEnsureBilinSize(scip, consdata, consdata->nbilinterms + 1) );
2510 
2511  bilinterm = &consdata->bilinterms[consdata->nbilinterms];
2512  if( SCIPvarCompare(consdata->quadvarterms[var1pos].var, consdata->quadvarterms[var2pos].var) < 0 )
2513  {
2514  bilinterm->var1 = consdata->quadvarterms[var1pos].var;
2515  bilinterm->var2 = consdata->quadvarterms[var2pos].var;
2516  }
2517  else
2518  {
2519  bilinterm->var1 = consdata->quadvarterms[var2pos].var;
2520  bilinterm->var2 = consdata->quadvarterms[var1pos].var;
2521  }
2522  bilinterm->coef = coef;
2523 
2524  if( bilinterm->var1 == bilinterm->var2 )
2525  {
2526  SCIPerrorMessage("tried to add bilinear term where both variables are the same, but appear at different positions in quadvarterms array\n");
2527  return SCIP_INVALIDDATA;
2528  }
2529  assert(SCIPvarCompare(bilinterm->var1, bilinterm->var2) == -1);
2530 
2531  SCIP_CALL( consdataEnsureAdjBilinSize(scip, &consdata->quadvarterms[var1pos], consdata->quadvarterms[var1pos].nadjbilin + 1) );
2532  SCIP_CALL( consdataEnsureAdjBilinSize(scip, &consdata->quadvarterms[var2pos], consdata->quadvarterms[var2pos].nadjbilin + 1) );
2533 
2534  consdata->quadvarterms[var1pos].adjbilin[consdata->quadvarterms[var1pos].nadjbilin] = consdata->nbilinterms;
2535  consdata->quadvarterms[var2pos].adjbilin[consdata->quadvarterms[var2pos].nadjbilin] = consdata->nbilinterms;
2536  ++consdata->quadvarterms[var1pos].nadjbilin;
2537  ++consdata->quadvarterms[var2pos].nadjbilin;
2538 
2539  ++consdata->nbilinterms;
2540 
2541  /* invalidate activity information */
2542  consdata->activity = SCIP_INVALID;
2543  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2544 
2545  /* invalidate nonlinear row */
2546  if( consdata->nlrow != NULL )
2547  {
2548  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2549  }
2550 
2551  consdata->ispropagated = FALSE;
2552  consdata->ispresolved = FALSE;
2553  if( consdata->nbilinterms == 1 )
2554  {
2555  consdata->bilinsorted = TRUE;
2556 
2557  /* we have to take care of the bilinear term in mergeAndCleanBilinearTerms() if the coefficient is zero */
2558  consdata->bilinmerged = !SCIPisZero(scip, consdata->bilinterms[0].coef);
2559  }
2560  else
2561  {
2562  consdata->bilinsorted = consdata->bilinsorted
2563  && (bilinTermComp(consdata, consdata->nbilinterms-2, consdata->nbilinterms-1) <= 0);
2564  consdata->bilinmerged = FALSE;
2565  }
2566 
2567  consdata->iscurvchecked = FALSE;
2568 
2569  /* check if the bilinear terms are sorted */
2570  assert(consdataCheckBilinTermsSort(consdata));
2571 
2572  return SCIP_OKAY;
2573 }
2574 
2575 /** removes a set of bilinear terms and updates adjacency information in quad var terms
2576  *
2577  * Note: this function sorts the given array termposs.
2578  */
2579 static
2581  SCIP* scip, /**< SCIP data structure */
2582  SCIP_CONS* cons, /**< quadratic constraint */
2583  int nterms, /**< number of terms to delete */
2584  int* termposs /**< indices of terms to delete */
2585  )
2586 {
2587  SCIP_CONSDATA* consdata;
2588  int* newpos;
2589  int i;
2590  int j;
2591  int offset;
2592 
2593  assert(scip != NULL);
2594  assert(cons != NULL);
2595  assert(nterms == 0 || termposs != NULL);
2596 
2597  if( nterms == 0 )
2598  return SCIP_OKAY;
2599 
2600  consdata = SCIPconsGetData(cons);
2601  assert(consdata != NULL);
2602 
2603  SCIPsortInt(termposs, nterms);
2604 
2605  SCIP_CALL( SCIPallocBufferArray(scip, &newpos, consdata->nbilinterms) );
2606 
2607  i = 0;
2608  offset = 0;
2609  for( j = 0; j < consdata->nbilinterms; ++j )
2610  {
2611  /* if j'th term is deleted, increase offset and continue */
2612  if( i < nterms && j == termposs[i] )
2613  {
2614  ++offset;
2615  ++i;
2616  newpos[j] = -1;
2617  continue;
2618  }
2619 
2620  /* otherwise, move it forward and remember new position */
2621  if( offset > 0 )
2622  consdata->bilinterms[j-offset] = consdata->bilinterms[j];
2623  newpos[j] = j - offset;
2624  }
2625  assert(offset == nterms);
2626 
2627  /* update adjacency and activity information in quad var terms */
2628  for( i = 0; i < consdata->nquadvars; ++i )
2629  {
2630  offset = 0;
2631  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
2632  {
2633  assert(consdata->quadvarterms[i].adjbilin[j] < consdata->nbilinterms);
2634  if( newpos[consdata->quadvarterms[i].adjbilin[j]] == -1 )
2635  {
2636  /* corresponding bilinear term was deleted, thus increase offset */
2637  ++offset;
2638  }
2639  else
2640  {
2641  /* update index of j'th bilinear term and store at position j-offset */
2642  consdata->quadvarterms[i].adjbilin[j-offset] = newpos[consdata->quadvarterms[i].adjbilin[j]];
2643  }
2644  }
2645  consdata->quadvarterms[i].nadjbilin -= offset;
2646  /* some bilinear term was removed, so invalidate activity bounds */
2647  }
2648 
2649  consdata->nbilinterms -= nterms;
2650 
2651  SCIPfreeBufferArray(scip, &newpos);
2652 
2653  /* some quad vars may be linear now */
2654  consdata->quadvarsmerged = FALSE;
2655 
2656  consdata->ispropagated = FALSE;
2657  consdata->ispresolved = FALSE;
2658  consdata->iscurvchecked = FALSE;
2659 
2660  /* invalidate activity */
2661  consdata->activity = SCIP_INVALID;
2662  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2663 
2664  /* invalidate nonlinear row */
2665  if( consdata->nlrow != NULL )
2666  {
2667  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2668  }
2669 
2670  return SCIP_OKAY;
2671 }
2672 
2673 /** merges quad var terms that correspond to the same variable and does additional cleanup
2674  *
2675  * If a quadratic variable terms is actually linear, makes a linear term out of it
2676  * also replaces squares of binary variables by the binary variables, i.e., adds sqrcoef to lincoef.
2677  */
2678 static
2680  SCIP* scip, /**< SCIP data structure */
2681  SCIP_CONS* cons /**< quadratic constraint */
2682  )
2683 {
2684  SCIP_QUADVARTERM* quadvarterm;
2685  SCIP_CONSDATA* consdata;
2686  int i;
2687  int j;
2688 
2689  assert(scip != NULL);
2690  assert(cons != NULL);
2691 
2692  consdata = SCIPconsGetData(cons);
2693 
2694  if( consdata->quadvarsmerged )
2695  return SCIP_OKAY;
2696 
2697  if( consdata->nquadvars == 0 )
2698  {
2699  consdata->quadvarsmerged = TRUE;
2700  return SCIP_OKAY;
2701  }
2702 
2703  i = 0;
2704  while( i < consdata->nquadvars )
2705  {
2706  /* make sure quad var terms are sorted (do this in every round, since we may move variables around) */
2707  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
2708 
2709  quadvarterm = &consdata->quadvarterms[i];
2710 
2711  for( j = i+1; j < consdata->nquadvars && consdata->quadvarterms[j].var == quadvarterm->var; ++j )
2712  {
2713  /* add quad var term j to current term i */
2714  quadvarterm->lincoef += consdata->quadvarterms[j].lincoef;
2715  quadvarterm->sqrcoef += consdata->quadvarterms[j].sqrcoef;
2716  if( consdata->quadvarterms[j].nadjbilin > 0 )
2717  {
2718  /* move adjacency information from j to i */
2719  SCIP_CALL( consdataEnsureAdjBilinSize(scip, quadvarterm, quadvarterm->nadjbilin + consdata->quadvarterms[j].nadjbilin) );
2720  BMScopyMemoryArray(&quadvarterm->adjbilin[quadvarterm->nadjbilin], consdata->quadvarterms[j].adjbilin, consdata->quadvarterms[j].nadjbilin); /*lint !e866*/
2721  quadvarterm->nadjbilin += consdata->quadvarterms[j].nadjbilin;
2722  consdata->quadvarterms[j].nadjbilin = 0;
2723  }
2724  consdata->quadvarterms[j].lincoef = 0.0;
2725  consdata->quadvarterms[j].sqrcoef = 0.0;
2726  /* mark that activity information in quadvarterm is not up to date anymore */
2727  }
2728 
2729  /* remove quad var terms i+1..j-1 backwards */
2730  for( j = j-1; j > i; --j )
2731  {
2732  SCIP_CALL( delQuadVarTermPos(scip, cons, j) );
2733  }
2734 
2735  /* for binary variables, x^2 = x
2736  * however, we may destroy convexity of a quadratic term that involves also bilinear terms
2737  * thus, we do this step only if the variable does not appear in any bilinear term */
2738  if( quadvarterm->sqrcoef != 0.0 && SCIPvarIsBinary(quadvarterm->var) && quadvarterm->nadjbilin == 0 )
2739  {
2740  SCIPdebugMsg(scip, "replace square of binary variable by itself: <%s>^2 --> <%s>\n", SCIPvarGetName(quadvarterm->var), SCIPvarGetName(quadvarterm->var));
2741  quadvarterm->lincoef += quadvarterm->sqrcoef;
2742  quadvarterm->sqrcoef = 0.0;
2743 
2744  /* invalidate nonlinear row */
2745  if( consdata->nlrow != NULL )
2746  {
2747  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2748  }
2749  }
2750 
2751  /* if its 0.0 or linear, get rid of it */
2752  if( SCIPisZero(scip, quadvarterm->sqrcoef) && quadvarterm->nadjbilin == 0 )
2753  {
2754  if( !SCIPisZero(scip, quadvarterm->lincoef) )
2755  {
2756  /* seem to be a linear term now, thus add as linear term */
2757  SCIP_CALL( addLinearCoef(scip, cons, quadvarterm->var, quadvarterm->lincoef) );
2758  }
2759  /* remove term at pos i */
2760  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
2761  }
2762  else
2763  {
2764  ++i;
2765  }
2766  }
2767 
2768  consdata->quadvarsmerged = TRUE;
2769  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2770 
2771  return SCIP_OKAY;
2772 }
2773 
2774 /** merges entries with same linear variable into one entry and cleans up entries with coefficient 0.0 */
2775 static
2777  SCIP* scip, /**< SCIP data structure */
2778  SCIP_CONS* cons /**< quadratic constraint */
2779  )
2780 {
2781  SCIP_CONSDATA* consdata;
2782  SCIP_Real newcoef;
2783  int i;
2784  int j;
2785  int qvarpos;
2786 
2787  assert(scip != NULL);
2788  assert(cons != NULL);
2789 
2790  consdata = SCIPconsGetData(cons);
2791 
2792  if( consdata->linvarsmerged )
2793  return SCIP_OKAY;
2794 
2795  if( consdata->nlinvars == 0 )
2796  {
2797  consdata->linvarsmerged = TRUE;
2798  return SCIP_OKAY;
2799  }
2800 
2801  i = 0;
2802  while( i < consdata->nlinvars )
2803  {
2804  /* make sure linear variables are sorted (do this in every round, since we may move variables around) */
2805  consdataSortLinearVars(consdata);
2806 
2807  /* sum up coefficients that correspond to variable i */
2808  newcoef = consdata->lincoefs[i];
2809  for( j = i+1; j < consdata->nlinvars && consdata->linvars[i] == consdata->linvars[j]; ++j )
2810  newcoef += consdata->lincoefs[j];
2811  /* delete the additional variables in backward order */
2812  for( j = j-1; j > i; --j )
2813  {
2814  SCIP_CALL( delLinearCoefPos(scip, cons, j) );
2815  }
2816 
2817  /* check if there is already a quadratic variable term with this variable */
2818  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->linvars[i], &qvarpos) );
2819  if( qvarpos >= 0)
2820  {
2821  /* add newcoef to linear coefficient of quadratic variable and mark linear variable as to delete */
2822  assert(qvarpos < consdata->nquadvars);
2823  assert(consdata->quadvarterms[qvarpos].var == consdata->linvars[i]);
2824  consdata->quadvarterms[qvarpos].lincoef += newcoef;
2825  newcoef = 0.0;
2826  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2827  }
2828 
2829  /* delete also entry at position i, if it became zero (or was zero before) */
2830  if( SCIPisZero(scip, newcoef) )
2831  {
2832  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
2833  }
2834  else
2835  {
2836  SCIP_CALL( chgLinearCoefPos(scip, cons, i, newcoef) );
2837  ++i;
2838  }
2839  }
2840 
2841  consdata->linvarsmerged = TRUE;
2842 
2843  return SCIP_OKAY;
2844 }
2845 
2846 /** merges bilinear terms with same variables into a single term, removes bilinear terms with coefficient 0.0 */
2847 static
2849  SCIP* scip, /**< SCIP data structure */
2850  SCIP_CONS* cons /**< quadratic constraint */
2851  )
2852 {
2853  SCIP_CONSDATA* consdata;
2854  SCIP_BILINTERM* bilinterm;
2855  int i;
2856  int j;
2857  int* todelete;
2858  int ntodelete;
2859 
2860  assert(scip != NULL);
2861  assert(cons != NULL);
2862 
2863  consdata = SCIPconsGetData(cons);
2864 
2865  /* check if the bilinear terms are sorted */
2866  assert(consdataCheckBilinTermsSort(consdata));
2867 
2868  if( consdata->bilinmerged )
2869  return SCIP_OKAY;
2870 
2871  if( consdata->nbilinterms == 0 )
2872  {
2873  consdata->bilinmerged = TRUE;
2874  return SCIP_OKAY;
2875  }
2876 
2877  /* alloc memory for array of terms that need to be deleted finally */
2878  ntodelete = 0;
2879  SCIP_CALL( SCIPallocBufferArray(scip, &todelete, consdata->nbilinterms) );
2880 
2881  /* make sure bilinear terms are sorted */
2882  SCIP_CALL( consdataSortBilinTerms(scip, consdata) );
2883 
2884  i = 0;
2885  while( i < consdata->nbilinterms )
2886  {
2887  bilinterm = &consdata->bilinterms[i];
2888 
2889  /* sum up coefficients that correspond to same variables as term i */
2890  for( j = i+1; j < consdata->nbilinterms && bilinterm->var1 == consdata->bilinterms[j].var1 && bilinterm->var2 == consdata->bilinterms[j].var2; ++j )
2891  {
2892  bilinterm->coef += consdata->bilinterms[j].coef;
2893  todelete[ntodelete++] = j;
2894  }
2895 
2896  /* delete also entry at position i, if it became zero (or was zero before) */
2897  if( SCIPisZero(scip, bilinterm->coef) )
2898  {
2899  todelete[ntodelete++] = i;
2900  }
2901 
2902  /* continue with term after the current series */
2903  i = j;
2904  }
2905 
2906  /* delete bilinear terms */
2907  SCIP_CALL( removeBilinearTermsPos(scip, cons, ntodelete, todelete) );
2908 
2909  SCIPfreeBufferArray(scip, &todelete);
2910 
2911  consdata->bilinmerged = TRUE;
2912 
2913  /* check if the bilinear terms are sorted */
2914  assert(consdataCheckBilinTermsSort(consdata));
2915 
2916  return SCIP_OKAY;
2917 }
2918 
2919 /** removes fixes (or aggregated) variables from a quadratic constraint */
2920 static
2922  SCIP* scip, /**< SCIP data structure */
2923  SCIP_CONS* cons /**< quadratic constraint */
2924  )
2925 {
2926  SCIP_CONSDATA* consdata;
2927  SCIP_BILINTERM* bilinterm;
2928  SCIP_Real bilincoef;
2929  SCIP_Real coef;
2930  SCIP_Real offset;
2931  SCIP_VAR* var;
2932  SCIP_VAR* var2;
2933  int var2pos;
2934  int i;
2935  int j;
2936  int k;
2937 
2938  SCIP_Bool have_change;
2939 
2940  assert(scip != NULL);
2941  assert(cons != NULL);
2942 
2943  consdata = SCIPconsGetData(cons);
2944 
2945  have_change = FALSE;
2946  i = 0;
2947  while( i < consdata->nlinvars )
2948  {
2949  var = consdata->linvars[i];
2950 
2951  if( SCIPvarIsActive(var) && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
2952  {
2953  ++i;
2954  continue;
2955  }
2956 
2957  have_change = TRUE;
2958 
2959  coef = consdata->lincoefs[i];
2960  offset = 0.0;
2961 
2962  if( SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
2963  {
2964  offset = coef * (SCIPvarGetLbGlobal(var) + SCIPvarGetUbGlobal(var)) / 2.0;
2965  coef = 0.0;
2966  }
2967  else
2968  {
2969  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &coef, &offset) );
2970  }
2971 
2972  SCIPdebugMsg(scip, " linear term %g*<%s> is replaced by %g * <%s> + %g\n", consdata->lincoefs[i], SCIPvarGetName(consdata->linvars[i]),
2973  coef, SCIPvarGetName(var), offset);
2974 
2975  /* delete previous variable (this will move another variable to position i) */
2976  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
2977 
2978  /* put constant part into bounds */
2979  if( offset != 0.0 )
2980  {
2981  if( !SCIPisInfinity(scip, -consdata->lhs) )
2982  consdata->lhs -= offset;
2983  if( !SCIPisInfinity(scip, consdata->rhs) )
2984  consdata->rhs -= offset;
2985  }
2986 
2987  /* nothing left to do if variable had been fixed */
2988  if( coef == 0.0 )
2989  continue;
2990 
2991  /* if GetProbvar gave a linear variable, just add it
2992  * if it's a multilinear variable, add it's disaggregated variables */
2993  if( SCIPvarIsActive(var) )
2994  {
2995  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
2996  }
2997  else
2998  {
2999  int naggrs;
3000  SCIP_VAR** aggrvars;
3001  SCIP_Real* aggrscalars;
3002  SCIP_Real aggrconstant;
3003 
3004  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
3005 
3006  naggrs = SCIPvarGetMultaggrNVars(var);
3007  aggrvars = SCIPvarGetMultaggrVars(var);
3008  aggrscalars = SCIPvarGetMultaggrScalars(var);
3009  aggrconstant = SCIPvarGetMultaggrConstant(var);
3010 
3011  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars + naggrs) );
3012 
3013  for( j = 0; j < naggrs; ++j )
3014  {
3015  SCIP_CALL( addLinearCoef(scip, cons, aggrvars[j], coef * aggrscalars[j]) );
3016  }
3017 
3018  if( aggrconstant != 0.0 )
3019  {
3020  if( !SCIPisInfinity(scip, -consdata->lhs) )
3021  consdata->lhs -= coef * aggrconstant;
3022  if( !SCIPisInfinity(scip, consdata->rhs) )
3023  consdata->rhs -= coef * aggrconstant;
3024  }
3025  }
3026  }
3027 
3028  i = 0;
3029  while( i < consdata->nquadvars )
3030  {
3031  var = consdata->quadvarterms[i].var;
3032 
3033  if( SCIPvarIsActive(var) && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
3034  {
3035  ++i;
3036  continue;
3037  }
3038 
3039  have_change = TRUE;
3040 
3041  coef = 1.0;
3042  offset = 0.0;
3043 
3044  if( !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
3045  {
3046  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &coef, &offset) );
3047  }
3048  else
3049  {
3050  coef = 0.0;
3051  offset = (SCIPvarGetLbGlobal(var) + SCIPvarGetUbGlobal(var)) / 2.0;
3052  }
3053 
3054  SCIPdebugMsg(scip, " quadratic variable <%s> with status %d is replaced by %g * <%s> + %g\n", SCIPvarGetName(consdata->quadvarterms[i].var),
3055  SCIPvarGetStatus(consdata->quadvarterms[i].var), coef, SCIPvarGetName(var), offset);
3056 
3057  /* handle fixed variable */
3058  if( coef == 0.0 )
3059  {
3060  /* if not fixed to 0.0, add to linear coefs of vars in bilinear terms, and deal with linear and square term as constant */
3061  if( offset != 0.0 )
3062  {
3063  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
3064  {
3065  bilinterm = &consdata->bilinterms[consdata->quadvarterms[i].adjbilin[j]];
3066 
3067  var2 = bilinterm->var1 == consdata->quadvarterms[i].var ? bilinterm->var2 : bilinterm->var1;
3068  assert(var2 != consdata->quadvarterms[i].var);
3069 
3070  var2pos = 0;
3071  while( consdata->quadvarterms[var2pos].var != var2 )
3072  {
3073  ++var2pos;
3074  assert(var2pos < consdata->nquadvars);
3075  }
3076  consdata->quadvarterms[var2pos].lincoef += bilinterm->coef * offset;
3077  }
3078 
3079  offset = consdata->quadvarterms[i].lincoef * offset + consdata->quadvarterms[i].sqrcoef * offset * offset;
3080  if( !SCIPisInfinity(scip, -consdata->lhs) )
3081  consdata->lhs -= offset;
3082  if( !SCIPisInfinity(scip, consdata->rhs) )
3083  consdata->rhs -= offset;
3084  }
3085 
3086  /* remove bilinear terms */
3087  SCIP_CALL( removeBilinearTermsPos(scip, cons, consdata->quadvarterms[i].nadjbilin, consdata->quadvarterms[i].adjbilin) );
3088 
3089  /* delete quad. var term i */
3090  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
3091 
3092  continue;
3093  }
3094 
3095  assert(var != NULL);
3096 
3097  /* if GetProbvar gave an active variable, replace the quad var term so that it uses the new variable */
3098  if( SCIPvarIsActive(var) )
3099  {
3100  /* replace x by coef*y+offset */
3101  SCIP_CALL( replaceQuadVarTermPos(scip, cons, i, var, coef, offset) );
3102 
3103  continue;
3104  }
3105  else
3106  {
3107  /* if GetProbVar gave a multi-aggregated variable, add new quad var terms and new bilinear terms
3108  * x is replaced by coef * (sum_i a_ix_i + b) + offset
3109  * lcoef * x + scoef * x^2 + bcoef * x * y ->
3110  * (b*coef + offset) * (lcoef + (b*coef + offset) * scoef)
3111  * + sum_i a_i*coef * (lcoef + 2 (b*coef + offset) * scoef) x_i
3112  * + sum_i (a_i*coef)^2 * scoef * x_i^2
3113  * + 2 sum_{i,j, i<j} (a_i a_j coef^2 scoef) x_i x_j
3114  * + bcoef * (b*coef + offset + coef * sum_i a_ix_i) y
3115  */
3116  int naggrs;
3117  SCIP_VAR** aggrvars; /* x_i */
3118  SCIP_Real* aggrscalars; /* a_i */
3119  SCIP_Real aggrconstant; /* b */
3120  int nquadtermsold;
3121 
3122  SCIP_Real lcoef;
3123  SCIP_Real scoef;
3124 
3125  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
3126 
3127  naggrs = SCIPvarGetMultaggrNVars(var);
3128  aggrvars = SCIPvarGetMultaggrVars(var);
3129  aggrscalars = SCIPvarGetMultaggrScalars(var);
3130  aggrconstant = SCIPvarGetMultaggrConstant(var);
3131 
3132  lcoef = consdata->quadvarterms[i].lincoef;
3133  scoef = consdata->quadvarterms[i].sqrcoef;
3134 
3135  nquadtermsold = consdata->nquadvars;
3136 
3137  SCIP_CALL( consdataEnsureQuadVarTermsSize(scip, consdata, consdata->nquadvars + naggrs) );
3138 
3139  /* take care of constant part */
3140  if( aggrconstant != 0.0 || offset != 0.0 )
3141  {
3142  SCIP_Real constant;
3143  constant = (aggrconstant * coef + offset) * (lcoef + (aggrconstant * coef + offset) * scoef);
3144  if( !SCIPisInfinity(scip, -consdata->lhs) )
3145  consdata->lhs -= constant;
3146  if( !SCIPisInfinity(scip, consdata->rhs) )
3147  consdata->rhs -= constant;
3148  }
3149 
3150  /* add x_i's with linear and square coefficients */
3151  for( j = 0; j < naggrs; ++j )
3152  {
3153  SCIP_CALL( addQuadVarTerm(scip, cons, aggrvars[j],
3154  coef * aggrscalars[j] * (lcoef + 2.0 * scoef * (coef * aggrconstant + offset)),
3155  coef * coef * aggrscalars[j] * aggrscalars[j] * scoef) );
3156  }
3157 
3158  /* ensure space for bilinear terms */
3159  SCIP_CALL( consdataEnsureBilinSize(scip, consdata, consdata->nquadvars + (scoef != 0.0 ? (naggrs * (naggrs-1))/2 : 0) + consdata->quadvarterms[j].nadjbilin * naggrs) );
3160 
3161  /* add x_j*x_k's */
3162  if( scoef != 0.0 )
3163  {
3164  for( j = 0; j < naggrs; ++j )
3165  for( k = 0; k < j; ++k )
3166  {
3167  assert(aggrvars[j] != aggrvars[k]);
3168  SCIP_CALL( addBilinearTerm(scip, cons, nquadtermsold + j, nquadtermsold + k,
3169  2.0 * aggrscalars[j] * aggrscalars[k] * coef * coef * scoef) );
3170  }
3171  }
3172 
3173  /* add x_i*y's */
3174  for( k = 0; k < consdata->quadvarterms[i].nadjbilin; ++k )
3175  {
3176  bilinterm = &consdata->bilinterms[consdata->quadvarterms[i].adjbilin[k]];
3177  bilincoef = bilinterm->coef; /* copy coef, as bilinterm pointer may become invalid by realloc in addBilinearTerm() below */
3178  var2 = (bilinterm->var1 == consdata->quadvarterms[i].var) ? bilinterm->var2 : bilinterm->var1;
3179  assert(var2 != consdata->quadvarterms[i].var);
3180 
3181  /* this is not efficient, but we cannot sort the quadratic terms here, since we currently iterate over them */
3182  var2pos = 0;
3183  while( consdata->quadvarterms[var2pos].var != var2 )
3184  {
3185  ++var2pos;
3186  assert(var2pos < consdata->nquadvars);
3187  }
3188 
3189  for( j = 0; j < naggrs; ++j )
3190  {
3191  if( aggrvars[j] == var2 )
3192  { /* x_i == y, so we have a square term here */
3193  consdata->quadvarterms[var2pos].sqrcoef += bilincoef * coef * aggrscalars[j];
3194  }
3195  else
3196  { /* x_i != y, so we need to add a bilinear term here */
3197  SCIP_CALL( addBilinearTerm(scip, cons, nquadtermsold + j, var2pos, bilincoef * coef * aggrscalars[j]) );
3198  }
3199  }
3200 
3201  consdata->quadvarterms[var2pos].lincoef += bilincoef * (aggrconstant * coef + offset);
3202  }
3203 
3204  /* remove bilinear terms */
3205  SCIP_CALL( removeBilinearTermsPos(scip, cons, consdata->quadvarterms[i].nadjbilin, consdata->quadvarterms[i].adjbilin) );
3206 
3207  /* delete quad. var term i */
3208  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
3209  }
3210  }
3211 
3212  consdata->isremovedfixings = TRUE;
3213 
3214  SCIPdebugMsg(scip, "removed fixations from <%s>\n -> ", SCIPconsGetName(cons));
3215  SCIPdebugPrintCons(scip, cons, NULL);
3216 
3217 #ifndef NDEBUG
3218  for( i = 0; i < consdata->nlinvars; ++i )
3219  assert(SCIPvarIsActive(consdata->linvars[i]));
3220 
3221  for( i = 0; i < consdata->nquadvars; ++i )
3222  assert(SCIPvarIsActive(consdata->quadvarterms[i].var));
3223 #endif
3224 
3225  if( !have_change )
3226  return SCIP_OKAY;
3227 
3228  /* some quadratic variable may have been replaced by an already existing linear variable
3229  * in this case, we want the linear variable to be removed, which happens in mergeAndCleanLinearVars
3230  */
3231  consdata->linvarsmerged = FALSE;
3232 
3233  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
3234  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, cons) );
3235  SCIP_CALL( mergeAndCleanLinearVars(scip, cons) );
3236 
3237 #ifndef NDEBUG
3238  for( i = 0; i < consdata->nbilinterms; ++i )
3239  {
3240  assert(consdata->bilinterms[i].var1 != consdata->bilinterms[i].var2);
3241  assert(consdata->bilinterms[i].coef != 0.0);
3242  assert(SCIPvarCompare(consdata->bilinterms[i].var1, consdata->bilinterms[i].var2) < 0);
3243  }
3244 #endif
3245 
3246  return SCIP_OKAY;
3247 }
3248 
3249 /** create a nonlinear row representation of the constraint and stores them in consdata */
3250 static
3252  SCIP* scip, /**< SCIP data structure */
3253  SCIP_CONS* cons /**< quadratic constraint */
3254  )
3255 {
3256  SCIP_CONSDATA* consdata;
3257  int nquadvars; /* number of variables in quadratic terms */
3258  SCIP_VAR** quadvars; /* variables in quadratic terms */
3259  int nquadelems; /* number of quadratic elements (square and bilinear terms) */
3260  SCIP_QUADELEM* quadelems; /* quadratic elements (square and bilinear terms) */
3261  int nquadlinterms; /* number of linear terms using variables that are in quadratic terms */
3262  SCIP_VAR** quadlinvars; /* variables of linear terms using variables that are in quadratic terms */
3263  SCIP_Real* quadlincoefs; /* coefficients of linear terms using variables that are in quadratic terms */
3264  int i;
3265  int idx1;
3266  int idx2;
3267  int lincnt;
3268  int elcnt;
3269  SCIP_VAR* lastvar;
3270  int lastvaridx;
3271  SCIP_EXPRCURV curvature;
3272 
3273  assert(scip != NULL);
3274  assert(cons != NULL);
3275 
3276  consdata = SCIPconsGetData(cons);
3277  assert(consdata != NULL);
3278 
3279  if( consdata->nlrow != NULL )
3280  {
3281  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3282  }
3283 
3284  nquadvars = consdata->nquadvars;
3285  nquadelems = consdata->nbilinterms;
3286  nquadlinterms = 0;
3287  for( i = 0; i < nquadvars; ++i )
3288  {
3289  if( consdata->quadvarterms[i].sqrcoef != 0.0 )
3290  ++nquadelems;
3291  if( !SCIPisZero(scip, consdata->quadvarterms[i].lincoef) )
3292  ++nquadlinterms;
3293  }
3294 
3295  SCIP_CALL( SCIPallocBufferArray(scip, &quadvars, nquadvars) );
3296  SCIP_CALL( SCIPallocBufferArray(scip, &quadelems, nquadelems) );
3297  SCIP_CALL( SCIPallocBufferArray(scip, &quadlinvars, nquadlinterms) );
3298  SCIP_CALL( SCIPallocBufferArray(scip, &quadlincoefs, nquadlinterms) );
3299 
3300  lincnt = 0;
3301  elcnt = 0;
3302  for( i = 0; i < nquadvars; ++i )
3303  {
3304  quadvars[i] = consdata->quadvarterms[i].var;
3305 
3306  if( consdata->quadvarterms[i].sqrcoef != 0.0 )
3307  {
3308  assert(elcnt < nquadelems);
3309  quadelems[elcnt].idx1 = i;
3310  quadelems[elcnt].idx2 = i;
3311  quadelems[elcnt].coef = consdata->quadvarterms[i].sqrcoef;
3312  ++elcnt;
3313  }
3314 
3315  if( !SCIPisZero(scip, consdata->quadvarterms[i].lincoef) )
3316  {
3317  assert(lincnt < nquadlinterms);
3318  quadlinvars [lincnt] = consdata->quadvarterms[i].var;
3319  quadlincoefs[lincnt] = consdata->quadvarterms[i].lincoef;
3320  ++lincnt;
3321  }
3322  }
3323  assert(lincnt == nquadlinterms);
3324 
3325  /* bilinear terms are sorted first by first variable, then by second variable
3326  * 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 */
3327  lastvar = NULL;
3328  lastvaridx = -1;
3329  for( i = 0; i < consdata->nbilinterms; ++i )
3330  {
3331  if( lastvar == consdata->bilinterms[i].var1 )
3332  {
3333  assert(lastvaridx >= 0);
3334  assert(consdata->quadvarterms[lastvaridx].var == consdata->bilinterms[i].var1);
3335  }
3336  else
3337  {
3338  lastvar = consdata->bilinterms[i].var1;
3339  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, lastvar, &lastvaridx) );
3340  }
3341  idx1 = lastvaridx;
3342 
3343  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->bilinterms[i].var2, &idx2) );
3344 
3345  assert(elcnt < nquadelems);
3346  quadelems[elcnt].idx1 = MIN(idx1, idx2);
3347  quadelems[elcnt].idx2 = MAX(idx1, idx2);
3348  quadelems[elcnt].coef = consdata->bilinterms[i].coef;
3349  ++elcnt;
3350  }
3351  assert(elcnt == nquadelems);
3352 
3353  /* set curvature for the nonlinear row */
3354  if( consdata->isconcave && consdata->isconvex )
3355  {
3356  assert(consdata->nbilinterms == 0 && consdata->nquadvars == 0);
3357  curvature = SCIP_EXPRCURV_LINEAR;
3358  }
3359  else if( consdata->isconcave )
3360  curvature = SCIP_EXPRCURV_CONCAVE;
3361  else if( consdata->isconvex )
3362  curvature = SCIP_EXPRCURV_CONVEX;
3363  else
3364  curvature = SCIP_EXPRCURV_UNKNOWN;
3365 
3366  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
3367  consdata->nlinvars, consdata->linvars, consdata->lincoefs,
3368  nquadvars, quadvars, nquadelems, quadelems,
3369  NULL, consdata->lhs, consdata->rhs,
3370  curvature) );
3371 
3372  SCIP_CALL( SCIPaddLinearCoefsToNlRow(scip, consdata->nlrow, nquadlinterms, quadlinvars, quadlincoefs) );
3373 
3374  SCIPfreeBufferArray(scip, &quadlincoefs);
3375  SCIPfreeBufferArray(scip, &quadlinvars);
3376  SCIPfreeBufferArray(scip, &quadelems);
3377  SCIPfreeBufferArray(scip, &quadvars);
3378 
3379  return SCIP_OKAY;
3380 }
3381 
3382 /** solve constraint as presolving */
3383 static
3385  SCIP* scip, /**< SCIP data structure */
3386  SCIP_CONS* cons, /**< constraint */
3387  SCIP_RESULT* result, /**< to store result of solve: cutoff, success, or do-not-find */
3388  SCIP_Bool* redundant, /**< to store whether constraint is redundant now (should be deleted) */
3389  int* naggrvars /**< counter on number of variable aggregations */
3390  )
3391 {
3392  SCIP_CONSDATA* consdata;
3393 
3394  assert(scip != NULL);
3395  assert(cons != NULL);
3396  assert(result != NULL);
3397  assert(redundant != NULL);
3398 
3399  *result = SCIP_DIDNOTFIND;
3400  *redundant = FALSE;
3401 
3402  consdata = SCIPconsGetData(cons);
3403  assert(consdata != NULL);
3404 
3405  /* if constraint is an equality with two variables, at least one of them binary,
3406  * and linear after fixing the binary, then we can aggregate the variables */
3407  if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) && consdata->nlinvars == 0 && consdata->nquadvars == 2 &&
3408  ((SCIPvarIsBinary(consdata->quadvarterms[0].var) && consdata->quadvarterms[1].sqrcoef == 0.0) ||
3409  (SCIPvarIsBinary(consdata->quadvarterms[1].var) && consdata->quadvarterms[0].sqrcoef == 0.0)) )
3410  {
3411  SCIP_Bool infeasible;
3412  SCIP_Bool aggregated;
3413  SCIP_Real a;
3414  SCIP_Real b;
3415  SCIP_Real c;
3416  SCIP_VAR* x;
3417  SCIP_VAR* y;
3418  int binvaridx;
3419 
3420  /* constraint is a*(x+x^2) + b*y + c*x*y = rhs, with x binary variable
3421  * x = 0 -> b*y == rhs
3422  * x = 1 -> (b+c)*y == rhs - a
3423  *
3424  * 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
3425  */
3426 
3427  binvaridx = (SCIPvarIsBinary(consdata->quadvarterms[0].var) && consdata->quadvarterms[1].sqrcoef == 0.0) ? 0 : 1;
3428 
3429  x = consdata->quadvarterms[binvaridx].var;
3430  a = consdata->quadvarterms[binvaridx].sqrcoef + consdata->quadvarterms[binvaridx].lincoef;
3431 
3432  y = consdata->quadvarterms[1-binvaridx].var;
3433  b = consdata->quadvarterms[1-binvaridx].lincoef;
3434 
3435  assert(consdata->nbilinterms <= 1); /* should actually be 1, since constraint is otherwise linear */
3436  c = (consdata->nbilinterms == 1) ? consdata->bilinterms[0].coef : 0.0;
3437 
3438  if( !SCIPisZero(scip, b) && !SCIPisZero(scip, b+c) )
3439  {
3440  SCIPdebugMsg(scip, "<%s> = 0 -> %g*<%s> = %g and <%s> = 1 -> %g*<%s> = %g\n", SCIPvarGetName(x), b, SCIPvarGetName(y), consdata->rhs,
3441  SCIPvarGetName(x), b+c, SCIPvarGetName(y), consdata->rhs - a);
3442  SCIPdebugMsg(scip, "=> attempt aggregation <%s> = %g*<%s> + %g\n", SCIPvarGetName(y), (consdata->rhs-a)/(b+c) - consdata->rhs/b,
3443  SCIPvarGetName(x), consdata->rhs/b);
3444 
3445  SCIP_CALL( SCIPaggregateVars(scip, x, y, (consdata->rhs-a)/(b+c) - consdata->rhs/b, -1.0, -consdata->rhs/b, &infeasible, redundant, &aggregated) );
3446  if( infeasible )
3447  *result = SCIP_CUTOFF;
3448  else if( *redundant || aggregated )
3449  {
3450  /* aggregated (or were already aggregated), so constraint is now redundant */
3451  *result = SCIP_SUCCESS;
3452  *redundant = TRUE;
3453 
3454  if( aggregated )
3455  ++*naggrvars;
3456  }
3457  }
3458 
3459  /* @todo if b is 0 or b+c is 0, or lhs != rhs, then could replace by varbound constraint */
3460  }
3461 
3462  return SCIP_OKAY;
3463 }
3464 
3465 
3466 /** reformulates products of binary variables as AND constraint
3467  *
3468  * 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.
3469  */
3470 static
3472  SCIP* scip, /**< SCIP data structure */
3473  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3474  SCIP_CONS* cons, /**< constraint */
3475  int* naddconss /**< buffer where to add the number of AND constraints added */
3476  )
3477 {
3478  SCIP_CONSHDLRDATA* conshdlrdata;
3479  SCIP_CONSDATA* consdata;
3480  char name[SCIP_MAXSTRLEN];
3481  SCIP_VAR* vars[2];
3482  SCIP_VAR* auxvar;
3483  SCIP_CONS* andcons;
3484  int i;
3485  int ntodelete;
3486  int* todelete;
3487 
3488  assert(scip != NULL);
3489  assert(conshdlr != NULL);
3490  assert(cons != NULL);
3491  assert(naddconss != NULL);
3492 
3493  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3494  assert(conshdlrdata != NULL);
3495 
3496  /* if no binary variables, then we will find nothing to reformulate here
3497  * (note that this does not count in integer variables with {0,1} bounds...)
3498  */
3499  if( SCIPgetNBinVars(scip) == 0 )
3500  return SCIP_OKAY;
3501 
3502  /* if user does not like AND very much, then return */
3503  if( conshdlrdata->empathy4and < 2 )
3504  return SCIP_OKAY;
3505 
3506  consdata = SCIPconsGetData(cons);
3507  assert(consdata != NULL);
3508 
3509  if( consdata->nbilinterms == 0 )
3510  return SCIP_OKAY;
3511 
3512  /* get array to store indices of bilinear terms that shall be deleted */
3513  SCIP_CALL( SCIPallocBufferArray(scip, &todelete, consdata->nbilinterms) );
3514  ntodelete = 0;
3515 
3516  for( i = 0; i < consdata->nbilinterms; ++i )
3517  {
3518  vars[0] = consdata->bilinterms[i].var1;
3519  if( !SCIPvarIsBinary(vars[0]) )
3520  continue;
3521 
3522  vars[1] = consdata->bilinterms[i].var2;
3523  if( !SCIPvarIsBinary(vars[1]) )
3524  continue;
3525 
3526  /* create auxiliary variable */
3527  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_%s", SCIPvarGetName(vars[0]), SCIPvarGetName(vars[1]), SCIPconsGetName(cons));
3528  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY,
3529  SCIPvarIsInitial(vars[0]) || SCIPvarIsInitial(vars[1]), SCIPvarIsRemovable(vars[0]) && SCIPvarIsRemovable(vars[1]), NULL, NULL, NULL, NULL, NULL) );
3530  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3531 #ifdef WITH_DEBUG_SOLUTION
3532  if( SCIPdebugIsMainscip(scip) )
3533  {
3534  SCIP_Real var0val;
3535  SCIP_Real var1val;
3536  SCIP_CALL( SCIPdebugGetSolVal(scip, vars[0], &var0val) );
3537  SCIP_CALL( SCIPdebugGetSolVal(scip, vars[1], &var1val) );
3538  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, var0val * var1val) );
3539  }
3540 #endif
3541 
3542  /* create AND-constraint auxvar = x and y, need to be enforced as not redundant */
3543  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%sAND%s", SCIPvarGetName(vars[0]), SCIPvarGetName(vars[1]));
3544  SCIP_CALL( SCIPcreateConsAnd(scip, &andcons, name, auxvar, 2, vars,
3545  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3546  SCIPconsIsSeparated(cons), TRUE, TRUE,
3549  SCIP_CALL( SCIPaddCons(scip, andcons) );
3550  SCIPdebugMsg(scip, "added AND constraint: ");
3551  SCIPdebugPrintCons(scip, andcons, NULL);
3552  SCIP_CALL( SCIPreleaseCons(scip, &andcons) );
3553  ++*naddconss;
3554 
3555  /* add bilincoef * auxvar to linear terms */
3556  SCIP_CALL( addLinearCoef(scip, cons, auxvar, consdata->bilinterms[i].coef) );
3557  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
3558 
3559  /* remember that we have to delete this bilinear term */
3560  assert(ntodelete < consdata->nbilinterms);
3561  todelete[ntodelete++] = i;
3562  }
3563 
3564  /* remove bilinear terms that have been replaced */
3565  SCIP_CALL( removeBilinearTermsPos(scip, cons, ntodelete, todelete) );
3566  SCIPfreeBufferArray(scip, &todelete);
3567 
3568  return SCIP_OKAY;
3569 }
3570 
3571 /** gets bounds of variable y if x takes a certain value; checks whether x = xval has implications on y */
3572 static
3574  SCIP* scip, /**< SCIP data structure */
3575  SCIP_VAR* x, /**< variable which implications to check */
3576  SCIP_Bool xval, /**< value of x to check for (TRUE for 1, FALSE for 0) */
3577  SCIP_VAR* y, /**< variable to check if bounds can be reduced */
3578  SCIP_INTERVAL* resultant /**< buffer to store bounds on y */
3579  )
3580 {
3581  SCIP_VAR** implvars;
3582  SCIP_BOUNDTYPE* impltypes;
3583  SCIP_Real* implbounds;
3584  int nimpls;
3585  int pos;
3586 
3587  assert(scip != NULL);
3588  assert(x != NULL);
3589  assert(y != NULL);
3590  assert(resultant != NULL);
3591 
3593 
3594  if( !SCIPvarIsBinary(x) || !SCIPvarIsActive(x) )
3595  return SCIP_OKAY;
3596 
3597  /* check in cliques for binary to binary implications */
3598  if( SCIPvarIsBinary(y) )
3599  {
3600  resultant->inf = MAX(resultant->inf, MIN(resultant->sup, 0.0));
3601  resultant->sup = MIN(resultant->sup, MAX(resultant->inf, 1.0));
3602 
3603  if( SCIPhaveVarsCommonClique(scip, x, xval, y, TRUE, FALSE) )
3604  {
3605  resultant->sup = MIN(resultant->sup, MAX(resultant->inf, 0.0));
3606  }
3607  else if( SCIPhaveVarsCommonClique(scip, x, xval, y, FALSE, FALSE) )
3608  {
3609  resultant->inf = MAX(resultant->inf, MIN(resultant->sup, 1.0));
3610  }
3611 
3612  return SCIP_OKAY;
3613  }
3614 
3615  /* analyze implications for x = xval */
3616  nimpls = SCIPvarGetNImpls(x, xval);
3617  if( nimpls == 0 )
3618  return SCIP_OKAY;
3619 
3620  implvars = SCIPvarGetImplVars (x, xval);
3621  impltypes = SCIPvarGetImplTypes (x, xval);
3622  implbounds = SCIPvarGetImplBounds(x, xval);
3623 
3624  assert(implvars != NULL);
3625  assert(impltypes != NULL);
3626  assert(implbounds != NULL);
3627 
3628  /* find implications */
3629  if( !SCIPsortedvecFindPtr((void**)implvars, SCIPvarComp, (void*)y, nimpls, &pos) )
3630  return SCIP_OKAY;
3631 
3632  /* if there are several implications on y, go to the first one */
3633  while( pos > 0 && implvars[pos-1] == y )
3634  --pos;
3635 
3636  /* update implied lower and upper bounds on y
3637  * but make sure that resultant will not be empty, due to tolerances
3638  */
3639  while( pos < nimpls && implvars[pos] == y )
3640  {
3641  if( impltypes[pos] == SCIP_BOUNDTYPE_LOWER )
3642  resultant->inf = MAX(resultant->inf, MIN(resultant->sup, implbounds[pos]));
3643  else
3644  resultant->sup = MIN(resultant->sup, MAX(resultant->inf, implbounds[pos]));
3645  ++pos;
3646  }
3647 
3648  assert(resultant->sup >= resultant->inf);
3649 
3650  return SCIP_OKAY;
3651 }
3652 
3653 /** Reformulates products of binary times bounded continuous variables as system of linear inequalities (plus auxiliary variable).
3654  *
3655  * For a product x*y, with y a binary variable and x a continous variable with finite bounds,
3656  * 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.
3657  *
3658  * 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.
3659  * For each product of linear term of length at most maxnrvar with y, an auxiliary z and linear inequalities are added.
3660  *
3661  * If y is a binary variable, the AND constraint \f$ z = x \wedge y \f$ may be added instead of linear constraints.
3662  */
3663 static
3665  SCIP* scip, /**< SCIP data structure */
3666  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3667  SCIP_CONS* cons, /**< constraint */
3668  int* naddconss /**< buffer where to add the number of auxiliary constraints added */
3669  )
3670 { /*lint --e{666} */
3671  SCIP_CONSHDLRDATA* conshdlrdata;
3672  SCIP_CONSDATA* consdata;
3673  SCIP_VAR** xvars;
3674  SCIP_Real* xcoef;
3675  SCIP_INTERVAL xbndszero;
3676  SCIP_INTERVAL xbndsone;
3677  SCIP_INTERVAL act0;
3678  SCIP_INTERVAL act1;
3679  int nxvars;
3680  SCIP_VAR* y;
3681  SCIP_VAR* bvar;
3682  char name[SCIP_MAXSTRLEN];
3683  int nbilinterms;
3684  SCIP_VAR* auxvar;
3685  SCIP_CONS* auxcons;
3686  int i;
3687  int j;
3688  int k;
3689  int bilinidx;
3690  SCIP_Real bilincoef;
3691  SCIP_Real mincoef;
3692  SCIP_Real maxcoef;
3693  int* todelete;
3694  int ntodelete;
3695  int maxnrvar;
3696  SCIP_Bool integral;
3697  SCIP_Longint gcd;
3698  SCIP_Bool auxvarinitial;
3699  SCIP_Bool auxvarremovable;
3700 
3701  assert(scip != NULL);
3702  assert(conshdlr != NULL);
3703  assert(cons != NULL);
3704  assert(naddconss != NULL);
3705 
3706  /* if no binary variables, then we will find nothing to reformulate here
3707  * (note that this does not count in integer variables with {0,1} bounds...)
3708  */
3709  if( SCIPgetNBinVars(scip) == 0 )
3710  return SCIP_OKAY;
3711 
3712  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3713  assert(conshdlrdata != NULL);
3714 
3715  maxnrvar = conshdlrdata->replacebinaryprodlength;
3716  if( maxnrvar == 0 )
3717  return SCIP_OKAY;
3718 
3719  consdata = SCIPconsGetData(cons);
3720  assert(consdata != NULL);
3721 
3722  xvars = NULL;
3723  xcoef = NULL;
3724  todelete = NULL;
3725  gcd = 0;
3726 
3727  for( i = 0; i < consdata->nquadvars; ++i )
3728  {
3729  y = consdata->quadvarterms[i].var;
3730  if( !SCIPvarIsBinary(y) )
3731  continue;
3732 
3733  nbilinterms = consdata->quadvarterms[i].nadjbilin;
3734  if( nbilinterms == 0 )
3735  continue;
3736 
3737  SCIP_CALL( SCIPreallocBufferArray(scip, &xvars, MIN(maxnrvar, nbilinterms)+2) ); /* add 2 for later use when creating linear constraints */
3738  SCIP_CALL( SCIPreallocBufferArray(scip, &xcoef, MIN(maxnrvar, nbilinterms)+2) );
3739 
3740  /* alloc array to store indices of bilinear terms that shall be deleted */
3741  SCIP_CALL( SCIPreallocBufferArray(scip, &todelete, nbilinterms) );
3742  ntodelete = 0;
3743 
3744  auxvarinitial = SCIPvarIsInitial(y);
3745  auxvarremovable = SCIPvarIsRemovable(y);
3746 
3747  /* 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)
3748  * and compute range of sum_i a_i*x_i for the cases y = 0 and y = 1
3749  * we may need several rounds if maxnrvar < nbilinterms
3750  */
3751  j = 0;
3752  do
3753  {
3754  nxvars = 0;
3755  SCIPintervalSet(&xbndszero, 0.0);
3756  SCIPintervalSet(&xbndsone, 0.0);
3757 
3758  mincoef = SCIPinfinity(scip);
3759  maxcoef = 0.0;
3760  integral = TRUE;
3761 
3762  /* collect at most maxnrvar variables for x term */
3763  for( ; j < nbilinterms && nxvars < maxnrvar; ++j )
3764  {
3765  bilinidx = consdata->quadvarterms[i].adjbilin[j];
3766  assert(bilinidx >= 0);
3767  assert(bilinidx < consdata->nbilinterms);
3768 
3769  bvar = consdata->bilinterms[bilinidx].var1;
3770  if( bvar == y )
3771  bvar = consdata->bilinterms[bilinidx].var2;
3772  assert(bvar != y);
3773 
3774  /* skip products with unbounded variables */
3775  if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(bvar)) || SCIPisInfinity(scip, SCIPvarGetUbGlobal(bvar)) )
3776  {
3777  SCIPdebugMsg(scip, "skip reform of <%s><%s> due to unbounded second variable [%g,%g]\n",
3779  continue;
3780  }
3781 
3782  /* skip products with non-binary variables if binreformbinaryonly is set */
3783  if( conshdlrdata->binreformbinaryonly && !SCIPvarIsBinary(bvar) )
3784  {
3785  SCIPdebugMsg(scip, "skip reform of <%s><%s> because second variable is not binary\n",
3786  SCIPvarGetName(y), SCIPvarGetName(bvar));
3787  continue;
3788  }
3789 
3790  bilincoef = consdata->bilinterms[bilinidx].coef;
3791  assert(bilincoef != 0.0);
3792 
3793  /* get activity of bilincoef * x if y = 0 */
3794  SCIP_CALL( getImpliedBounds(scip, y, FALSE, bvar, &act0) );
3795  SCIPintervalMulScalar(SCIPinfinity(scip), &act0, act0, bilincoef);
3796 
3797  /* get activity of bilincoef * x if y = 1 */
3798  SCIP_CALL( getImpliedBounds(scip, y, TRUE, bvar, &act1) );
3799  SCIPintervalMulScalar(SCIPinfinity(scip), &act1, act1, bilincoef);
3800 
3801  /* skip products that give rise to very large coefficients (big big-M's) */
3802  if( SCIPfeastol(scip) * REALABS(act0.inf) >= conshdlrdata->binreformmaxcoef || SCIPfeastol(scip) * REALABS(act0.sup) >= conshdlrdata->binreformmaxcoef )
3803  {
3804  SCIPdebugMsg(scip, "skip reform of %g<%s><%s> due to huge activity [%g,%g] for <%s> = 0.0\n",
3805  bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar), SCIPintervalGetInf(act0), SCIPintervalGetSup(act0), SCIPvarGetName(y));
3806  continue;
3807  }
3808  if( SCIPfeastol(scip) * REALABS(act1.inf) >= conshdlrdata->binreformmaxcoef || SCIPfeastol(scip) * REALABS(act1.sup) >= conshdlrdata->binreformmaxcoef )
3809  {
3810  SCIPdebugMsg(scip, "skip reform of %g<%s><%s> due to huge activity [%g,%g] for <%s> = 1.0\n",
3811  bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar), SCIPintervalGetInf(act1), SCIPintervalGetSup(act1), SCIPvarGetName(y));
3812  continue;
3813  }
3814  if( !SCIPisZero(scip, MIN(REALABS(act0.inf), REALABS(act0.sup))) &&
3815  SCIPfeastol(scip) * MAX(REALABS(act0.inf), REALABS(act0.sup)) / MIN(REALABS(act0.inf), REALABS(act0.sup)) >= conshdlrdata->binreformmaxcoef )
3816  {
3817  SCIPdebugMsg(scip, "skip reform of %g<%s><%s> due to huge activity ratio %g for <%s> = 0.0\n", bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar),
3818  MAX(REALABS(act0.inf), REALABS(act0.sup)) / MIN(REALABS(act0.inf), REALABS(act0.sup)), SCIPvarGetName(y));
3819  continue;
3820  }
3821  if( !SCIPisZero(scip, MIN(REALABS(act1.inf), REALABS(act1.sup))) &&
3822  SCIPfeastol(scip) * MAX(REALABS(act1.inf), REALABS(act1.sup)) / MIN(REALABS(act1.inf), REALABS(act1.sup)) >= conshdlrdata->binreformmaxcoef )
3823  {
3824  SCIPdebugMsg(scip, "skip reform of %g<%s><%s> due to huge activity ratio %g for <%s> = 0.0\n", bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar),
3825  MAX(REALABS(act1.inf), REALABS(act1.sup)) / MIN(REALABS(act1.inf), REALABS(act1.sup)), SCIPvarGetName(y));
3826  continue;
3827  }
3828 
3829  /* add bvar to x term */
3830  xvars[nxvars] = bvar;
3831  xcoef[nxvars] = bilincoef;
3832  ++nxvars;
3833 
3834  /* update bounds on x term */
3835  SCIPintervalAdd(SCIPinfinity(scip), &xbndszero, xbndszero, act0);
3836  SCIPintervalAdd(SCIPinfinity(scip), &xbndsone, xbndsone, act1);
3837 
3838  if( REALABS(bilincoef) < mincoef )
3839  mincoef = ABS(bilincoef);
3840  if( REALABS(bilincoef) > maxcoef )
3841  maxcoef = ABS(bilincoef);
3842 
3843  /* update whether all coefficients will be integral and if so, compute their gcd */
3844  integral &= (SCIPvarGetType(bvar) < SCIP_VARTYPE_CONTINUOUS) && SCIPisIntegral(scip, bilincoef); /*lint !e514 */
3845  if( integral )
3846  {
3847  if( nxvars == 1 )
3848  gcd = (SCIP_Longint)SCIPround(scip, REALABS(bilincoef));
3849  else
3850  gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)SCIPround(scip, REALABS(bilincoef)));
3851  }
3852 
3853  /* if bvar is initial, then also the auxiliary variable should be initial
3854  * if bvar is not removable, then also the auxiliary variable should not be removable
3855  */
3856  auxvarinitial |= SCIPvarIsInitial(bvar);
3857  auxvarremovable &= SCIPvarIsRemovable(bvar);
3858 
3859  /* remember that we have to remove this bilinear term later */
3860  assert(ntodelete < nbilinterms);
3861  todelete[ntodelete++] = bilinidx;
3862  }
3863 
3864  if( nxvars == 0 ) /* all (remaining) x_j seem to be unbounded */
3865  break;
3866 
3867  assert(!SCIPisInfinity(scip, -SCIPintervalGetInf(xbndszero)));
3868  assert(!SCIPisInfinity(scip, SCIPintervalGetSup(xbndszero)));
3869  assert(!SCIPisInfinity(scip, -SCIPintervalGetInf(xbndsone)));
3870  assert(!SCIPisInfinity(scip, SCIPintervalGetSup(xbndsone)));
3871 
3872 #ifdef SCIP_DEBUG
3873  if( SCIPintervalGetInf(xbndszero) != SCIPintervalGetInf(xbndsone) || /*lint !e777*/
3874  +SCIPintervalGetSup(xbndszero) != SCIPintervalGetSup(xbndsone) ) /*lint !e777*/
3875  {
3876  SCIPdebugMsg(scip, "got different bounds for y = 0: [%g, %g] and y = 1: [%g, %g]\n", xbndszero.inf, xbndszero.sup, xbndsone.inf, xbndsone.sup);
3877  }
3878 #endif
3879 
3880  if( nxvars == 1 && conshdlrdata->empathy4and >= 1 && SCIPvarIsBinary(xvars[0]) )
3881  {
3882  /* product of two binary variables, replace by auxvar and AND constraint */
3883  /* add auxiliary variable z */
3884  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3885  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT,
3886  auxvarinitial, auxvarremovable, NULL, NULL, NULL, NULL, NULL) );
3887  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3888 
3889 #ifdef WITH_DEBUG_SOLUTION
3890  if( SCIPdebugIsMainscip(scip) )
3891  {
3892  SCIP_Real var0val;
3893  SCIP_Real var1val;
3894  SCIP_CALL( SCIPdebugGetSolVal(scip, xvars[0], &var0val) );
3895  SCIP_CALL( SCIPdebugGetSolVal(scip, y, &var1val) );
3896  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, var0val * var1val) );
3897  }
3898 #endif
3899 
3900  /* add constraint z = x and y; need to be enforced, as it is not redundant w.r.t. existing constraints */
3901  xvars[1] = y;
3902  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%sAND%s_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3903  SCIP_CALL( SCIPcreateConsAnd(scip, &auxcons, name, auxvar, 2, xvars,
3904  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3905  SCIPconsIsSeparated(cons), TRUE, TRUE,
3908  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3909  SCIPdebugMsg(scip, "added AND constraint: ");
3910  SCIPdebugPrintCons(scip, auxcons, NULL);
3911  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3912  ++*naddconss;
3913 
3914  /* add linear term coef*auxvar */
3915  SCIP_CALL( addLinearCoef(scip, cons, auxvar, xcoef[0]) );
3916 
3917  /* forget about auxvar */
3918  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
3919  }
3920  else
3921  {
3922  /* product of binary variable with more than one binary or with continuous variables or with binary and user
3923  * did not like AND -> replace by auxvar and linear constraints */
3924  SCIP_Real scale;
3925 
3926  /* scale auxiliary constraint by some nice value,
3927  * if all coefficients are integral, take a value that preserves integrality (-> gcd), so we can make the auxiliary variable impl. integer
3928  */
3929  if( integral )
3930  {
3931  scale = (SCIP_Real)gcd;
3932  assert(scale >= 1.0);
3933  }
3934  else if( nxvars == 1 )
3935  {
3936  /* scaling by the only coefficient gives auxiliary variable = x * y, which thus will be implicit integral provided y is not continuous */
3937  assert(mincoef == maxcoef); /*lint !e777 */
3938  scale = mincoef;
3939  integral = SCIPvarGetType(xvars[0]) < SCIP_VARTYPE_CONTINUOUS;
3940  }
3941  else
3942  {
3943  scale = 1.0;
3944  if( maxcoef < 0.5 )
3945  scale = maxcoef;
3946  if( mincoef > 2.0 )
3947  scale = mincoef;
3948  if( scale != 1.0 )
3949  scale = SCIPselectSimpleValue(scale / 2.0, 1.5 * scale, MAXDNOM);
3950  }
3951  assert(scale > 0.0);
3952  assert(!SCIPisInfinity(scip, scale));
3953 
3954  /* if x-term is always negative for y = 1, negate scale so we get a positive auxiliary variable; maybe this is better sometimes? */
3955  if( !SCIPisPositive(scip, SCIPintervalGetSup(xbndsone)) )
3956  scale = -scale;
3957 
3958  SCIPdebugMsg(scip, "binary reformulation using scale %g, nxvars = %d, integral = %u\n", scale, nxvars, integral);
3959  if( scale != 1.0 )
3960  {
3961  SCIPintervalDivScalar(SCIPinfinity(scip), &xbndszero, xbndszero, scale);
3962  SCIPintervalDivScalar(SCIPinfinity(scip), &xbndsone, xbndsone, scale);
3963  for( k = 0; k < nxvars; ++k )
3964  xcoef[k] /= scale;
3965  }
3966 
3967  /* add auxiliary variable z */
3968  if( nxvars == 1 )
3969  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3970  else
3971  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_more_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3972  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, MIN(0., SCIPintervalGetInf(xbndsone)), MAX(0., SCIPintervalGetSup(xbndsone)),
3974  auxvarinitial, auxvarremovable, NULL, NULL, NULL, NULL, NULL) );
3975  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3976 
3977  /* compute value of auxvar in debug solution */
3978 #ifdef WITH_DEBUG_SOLUTION
3979  if( SCIPdebugIsMainscip(scip) )
3980  {
3981  SCIP_Real debugval;
3982  SCIP_Real varval;
3983 
3984  SCIP_CALL( SCIPdebugGetSolVal(scip, y, &varval) );
3985  if( SCIPisZero(scip, varval) )
3986  {
3987  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, 0.0) );
3988  }
3989  else
3990  {
3991  assert(SCIPisEQ(scip, varval, 1.0));
3992 
3993  debugval = 0.0;
3994  for( k = 0; k < nxvars; ++k )
3995  {
3996  SCIP_CALL( SCIPdebugGetSolVal(scip, xvars[k], &varval) );
3997  debugval += xcoef[k] * varval;
3998  }
3999  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, debugval) );
4000  }
4001  }
4002 #endif
4003 
4004  /* add auxiliary constraints
4005  * it seems to be advantageous to make the varbound constraints initial and the linear constraints not initial
4006  * maybe because it is more likely that a binary variable takes value 0 instead of 1, and thus the varbound constraints
4007  * are more often active, compared to the linear constraints added below
4008  * also, the varbound constraints are more sparse than the linear cons
4009  */
4010  if( SCIPisNegative(scip, SCIPintervalGetInf(xbndsone)) )
4011  {
4012  /* add 0 <= z - xbndsone.inf * y constraint (as varbound constraint), need to be enforced as not redundant */
4013  if( nxvars == 1 )
4014  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_1", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4015  else
4016  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_1", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4017  SCIP_CALL( SCIPcreateConsVarbound(scip, &auxcons, name, auxvar, y, -SCIPintervalGetInf(xbndsone), 0.0, SCIPinfinity(scip),
4018  SCIPconsIsInitial(cons) /*&& conshdlrdata->binreforminitial*/,
4019  SCIPconsIsSeparated(cons), TRUE, TRUE,
4022  SCIP_CALL( SCIPaddCons(scip, auxcons) );
4023  SCIPdebugMsg(scip, "added varbound constraint: ");
4024  SCIPdebugPrintCons(scip, auxcons, NULL);
4025  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
4026  ++*naddconss;
4027  }
4028  if( SCIPisPositive(scip, SCIPintervalGetSup(xbndsone)) )
4029  {
4030  /* add z - xbndsone.sup * y <= 0 constraint (as varbound constraint), need to be enforced as not redundant */
4031  if( nxvars == 1 )
4032  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_2", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4033  else
4034  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_2", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4035  SCIP_CALL( SCIPcreateConsVarbound(scip, &auxcons, name, auxvar, y, -SCIPintervalGetSup(xbndsone), -SCIPinfinity(scip), 0.0,
4036  SCIPconsIsInitial(cons) /*&& conshdlrdata->binreforminitial*/,
4037  SCIPconsIsSeparated(cons), TRUE, TRUE,
4040  SCIP_CALL( SCIPaddCons(scip, auxcons) );
4041  SCIPdebugMsg(scip, "added varbound constraint: ");
4042  SCIPdebugPrintCons(scip, auxcons, NULL);
4043  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
4044  ++*naddconss;
4045  }
4046 
4047  /* add xbndszero.inf <= sum_i a_i*x_i + xbndszero.inf * y - z constraint, need to be enforced as not redundant */
4048  xvars[nxvars] = y;
4049  xvars[nxvars+1] = auxvar;
4050  xcoef[nxvars] = SCIPintervalGetInf(xbndszero);
4051  xcoef[nxvars+1] = -1;
4052 
4053  if( nxvars == 1 )
4054  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_3", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4055  else
4056  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_3", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4057  SCIP_CALL( SCIPcreateConsLinear(scip, &auxcons, name, nxvars+2, xvars, xcoef, SCIPintervalGetInf(xbndszero), SCIPinfinity(scip),
4058  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
4059  SCIPconsIsSeparated(cons), TRUE, TRUE,
4062  SCIP_CALL( SCIPaddCons(scip, auxcons) );
4063  SCIPdebugMsg(scip, "added linear constraint: ");
4064  SCIPdebugPrintCons(scip, auxcons, NULL);
4065  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
4066  ++*naddconss;
4067 
4068  /* add sum_i a_i*x_i + xbndszero.sup * y - z <= xbndszero.sup constraint, need to be enforced as not redundant */
4069  xcoef[nxvars] = SCIPintervalGetSup(xbndszero);
4070 
4071  if( nxvars == 1 )
4072  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_4", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4073  else
4074  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_4", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4075  SCIP_CALL( SCIPcreateConsLinear(scip, &auxcons, name, nxvars+2, xvars, xcoef, -SCIPinfinity(scip), SCIPintervalGetSup(xbndszero),
4076  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
4077  SCIPconsIsSeparated(cons), TRUE, TRUE,
4080  SCIP_CALL( SCIPaddCons(scip, auxcons) );
4081  SCIPdebugMsg(scip, "added linear constraint: ");
4082  SCIPdebugPrintCons(scip, auxcons, NULL);
4083  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
4084  ++*naddconss;
4085 
4086  /* add linear term scale*auxvar to this constraint */
4087  SCIP_CALL( addLinearCoef(scip, cons, auxvar, scale) );
4088 
4089  /* forget about auxvar */
4090  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
4091  }
4092  }
4093  while( j < nbilinterms );
4094 
4095  /* remove bilinear terms that have been replaced */
4096  SCIP_CALL( removeBilinearTermsPos(scip, cons, ntodelete, todelete) );
4097  }
4098  SCIPdebugMsg(scip, "resulting quadratic constraint: ");
4099  SCIPdebugPrintCons(scip, cons, NULL);
4100 
4101  SCIPfreeBufferArrayNull(scip, &xvars);
4102  SCIPfreeBufferArrayNull(scip, &xcoef);
4103  SCIPfreeBufferArrayNull(scip, &todelete);
4104 
4105  return SCIP_OKAY;
4106 }
4107 
4108 /** tries to automatically convert a quadratic constraint (or a part of it) into a more specific and more specialized constraint */
4109 static
4111  SCIP* scip, /**< SCIP data structure */
4112  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
4113  SCIP_CONS* cons, /**< source constraint to try to convert */
4114  SCIP_Bool* upgraded, /**< buffer to store whether constraint was upgraded */
4115  int* nupgdconss, /**< buffer to increase if constraint was upgraded */
4116  int* naddconss, /**< buffer to increase with number of additional constraints created during upgrade */
4117  SCIP_PRESOLTIMING presoltiming /**< current presolving timing */
4118  )
4119 {
4120  SCIP_CONSHDLRDATA* conshdlrdata;
4121  SCIP_CONSDATA* consdata;
4122  SCIP_VAR* var;
4123  SCIP_Real lincoef;
4124  SCIP_Real quadcoef;
4125  SCIP_Real lb;
4126  SCIP_Real ub;
4127  int nbinlin;
4128  int nbinquad;
4129  int nintlin;
4130  int nintquad;
4131  int nimpllin;
4132  int nimplquad;
4133  int ncontlin;
4134  int ncontquad;
4135  SCIP_Bool integral;
4136  int i;
4137  int j;
4138  SCIP_CONS** upgdconss;
4139  int upgdconsssize;
4140  int nupgdconss_;
4141 
4142  assert(scip != NULL);
4143  assert(conshdlr != NULL);
4144  assert(cons != NULL);
4145  assert(!SCIPconsIsModifiable(cons));
4146  assert(upgraded != NULL);
4147  assert(nupgdconss != NULL);
4148  assert(naddconss != NULL);
4149 
4150  *upgraded = FALSE;
4151 
4152  nupgdconss_ = 0;
4153 
4154  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4155  assert(conshdlrdata != NULL);
4156 
4157  /* if there are no upgrade methods, we can also stop */
4158  if( conshdlrdata->nquadconsupgrades == 0 )
4159  return SCIP_OKAY;
4160 
4161  upgdconsssize = 2;
4162  SCIP_CALL( SCIPallocBufferArray(scip, &upgdconss, upgdconsssize) );
4163 
4164  consdata = SCIPconsGetData(cons);
4165  assert(consdata != NULL);
4166 
4167  /* calculate some statistics on quadratic constraint */
4168  nbinlin = 0;
4169  nbinquad = 0;
4170  nintlin = 0;
4171  nintquad = 0;
4172  nimpllin = 0;
4173  nimplquad = 0;
4174  ncontlin = 0;
4175  ncontquad = 0;
4176  integral = TRUE;
4177  for( i = 0; i < consdata->nlinvars; ++i )
4178  {
4179  var = consdata->linvars[i];
4180  lincoef = consdata->lincoefs[i];
4181  lb = SCIPvarGetLbLocal(var);
4182  ub = SCIPvarGetUbLocal(var);
4183  assert(!SCIPisZero(scip, lincoef));
4184 
4185  switch( SCIPvarGetType(var) )
4186  {
4187  case SCIP_VARTYPE_BINARY:
4188  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4189  integral = integral && SCIPisIntegral(scip, lincoef);
4190  nbinlin++;
4191  break;
4192  case SCIP_VARTYPE_INTEGER:
4193  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4194  integral = integral && SCIPisIntegral(scip, lincoef);
4195  nintlin++;
4196  break;
4197  case SCIP_VARTYPE_IMPLINT:
4198  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4199  integral = integral && SCIPisIntegral(scip, lincoef);
4200  nimpllin++;
4201  break;
4203  integral = integral && SCIPisRelEQ(scip, lb, ub) && SCIPisIntegral(scip, lincoef * lb);
4204  ncontlin++;
4205  break;
4206  default:
4207  SCIPerrorMessage("unknown variable type\n");
4208  return SCIP_INVALIDDATA;
4209  }
4210  }
4211 
4212  for( i = 0; i < consdata->nquadvars; ++i )
4213  {
4214  var = consdata->quadvarterms[i].var;
4215  lincoef = consdata->quadvarterms[i].lincoef;
4216  quadcoef = consdata->quadvarterms[i].sqrcoef;
4217  lb = SCIPvarGetLbLocal(var);
4218  ub = SCIPvarGetUbLocal(var);
4219 
4220  switch( SCIPvarGetType(var) )
4221  {
4222  case SCIP_VARTYPE_BINARY:
4223  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4224  integral = integral && SCIPisIntegral(scip, lincoef) && SCIPisIntegral(scip, quadcoef);
4225  nbinquad++;
4226  break;
4227  case SCIP_VARTYPE_INTEGER:
4228  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4229  integral = integral && SCIPisIntegral(scip, lincoef) && SCIPisIntegral(scip, quadcoef);
4230  nintquad++;
4231  break;
4232  case SCIP_VARTYPE_IMPLINT:
4233  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4234  integral = integral && SCIPisIntegral(scip, lincoef) && SCIPisIntegral(scip, quadcoef);
4235  nimplquad++;
4236  break;
4238  integral = integral && SCIPisRelEQ(scip, lb, ub) && SCIPisIntegral(scip, lincoef * lb + quadcoef * lb * lb);
4239  ncontquad++;
4240  break;
4241  default:
4242  SCIPerrorMessage("unknown variable type\n");
4243  return SCIP_INVALIDDATA;
4244  }
4245  }
4246 
4247  if( integral )
4248  {
4249  for( i = 0; i < consdata->nbilinterms && integral; ++i )
4250  {
4251  if( SCIPvarGetType(consdata->bilinterms[i].var1) < SCIP_VARTYPE_CONTINUOUS && SCIPvarGetType(consdata->bilinterms[i].var2) < SCIP_VARTYPE_CONTINUOUS )
4252  integral = integral && SCIPisIntegral(scip, consdata->bilinterms[i].coef);
4253  else
4254  integral = FALSE;
4255  }
4256  }
4257 
4258  /* call the upgrading methods */
4259 
4260  SCIPdebugMsg(scip, "upgrading quadratic constraint <%s> (%d upgrade methods):\n",
4261  SCIPconsGetName(cons), conshdlrdata->nquadconsupgrades);
4262  SCIPdebugMsg(scip, " binlin=%d binquad=%d intlin=%d intquad=%d impllin=%d implquad=%d contlin=%d contquad=%d integral=%u\n",
4263  nbinlin, nbinquad, nintlin, nintquad, nimpllin, nimplquad, ncontlin, ncontquad, integral);
4264  SCIPdebugPrintCons(scip, cons, NULL);
4265 
4266  /* try all upgrading methods in priority order in case the upgrading step is enable */
4267  for( i = 0; i < conshdlrdata->nquadconsupgrades; ++i )
4268  {
4269  if( !conshdlrdata->quadconsupgrades[i]->active )
4270  continue;
4271 
4272  SCIP_CALL( conshdlrdata->quadconsupgrades[i]->quadconsupgd(scip, cons,
4273  nbinlin, nbinquad, nintlin, nintquad, nimpllin, nimplquad, ncontlin, ncontquad, integral,
4274  &nupgdconss_, upgdconss, upgdconsssize, presoltiming) );
4275 
4276  while( nupgdconss_ < 0 )
4277  {
4278  /* upgrade function requires more memory: resize upgdconss and call again */
4279  assert(-nupgdconss_ > upgdconsssize);
4280  upgdconsssize = -nupgdconss_;
4281  SCIP_CALL( SCIPreallocBufferArray(scip, &upgdconss, -nupgdconss_) );
4282 
4283  SCIP_CALL( conshdlrdata->quadconsupgrades[i]->quadconsupgd(scip, cons,
4284  nbinlin, nbinquad, nintlin, nintquad, nimpllin, nimplquad, ncontlin, ncontquad, integral,
4285  &nupgdconss_, upgdconss, upgdconsssize, presoltiming) );
4286 
4287  assert(nupgdconss_ != 0);
4288  }
4289 
4290  if( nupgdconss_ > 0 )
4291  {
4292  /* got upgrade */
4293  SCIPdebugPrintCons(scip, cons, NULL);
4294  SCIPdebugMsg(scip, " -> upgraded to %d constraints:\n", nupgdconss_);
4295 
4296  /* add the upgraded constraints to the problem and forget them */
4297  for( j = 0; j < nupgdconss_; ++j )
4298  {
4299  SCIPdebugMsgPrint(scip, "\t");
4300  SCIPdebugPrintCons(scip, upgdconss[j], NULL);
4301 
4302  SCIP_CALL( SCIPaddCons(scip, upgdconss[j]) ); /*lint !e613*/
4303  SCIP_CALL( SCIPreleaseCons(scip, &upgdconss[j]) ); /*lint !e613*/
4304  }
4305 
4306  /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
4307  *nupgdconss += 1;
4308  *naddconss += nupgdconss_ - 1;
4309  *upgraded = TRUE;
4310 
4311  /* delete upgraded constraint */
4312  SCIPdebugMsg(scip, "delete constraint <%s> after upgrade\n", SCIPconsGetName(cons));
4313  SCIP_CALL( SCIPdelCons(scip, cons) );
4314 
4315  break;
4316  }
4317  }
4318 
4319  SCIPfreeBufferArray(scip, &upgdconss);
4320 
4321  return SCIP_OKAY;
4322 }
4323 
4324 /** helper function for presolveDisaggregate */
4325 static
4327  SCIP* scip, /**< SCIP data structure */
4328  SCIP_CONSDATA* consdata, /**< constraint data */
4329  int quadvaridx, /**< index of quadratic variable to mark */
4330  SCIP_HASHMAP* var2component, /**< variables to components mapping */
4331  int componentnr, /**< the component number to mark to */
4332  int* componentsize /**< buffer to store size of component (incremented by 1) */
4333  )
4334 {
4335  SCIP_QUADVARTERM* quadvarterm;
4336  SCIP_VAR* othervar;
4337  int othervaridx;
4338  int i;
4339 
4340  assert(consdata != NULL);
4341  assert(quadvaridx >= 0);
4342  assert(quadvaridx < consdata->nquadvars);
4343  assert(var2component != NULL);
4344  assert(componentnr >= 0);
4345 
4346  quadvarterm = &consdata->quadvarterms[quadvaridx];
4347 
4348  if( SCIPhashmapExists(var2component, quadvarterm->var) )
4349  {
4350  /* if we saw the variable before, then it should have the same component number */
4351  assert((int)(size_t)SCIPhashmapGetImage(var2component, quadvarterm->var) == componentnr);
4352  return SCIP_OKAY;
4353  }
4354 
4355  /* assign component number to variable */
4356  SCIP_CALL( SCIPhashmapInsert(var2component, quadvarterm->var, (void*)(size_t)componentnr) );
4357  ++*componentsize;
4358 
4359  /* assign same component number to all variables this variable is multiplied with */
4360  for( i = 0; i < quadvarterm->nadjbilin; ++i )
4361  {
4362  othervar = consdata->bilinterms[quadvarterm->adjbilin[i]].var1 == quadvarterm->var ?
4363  consdata->bilinterms[quadvarterm->adjbilin[i]].var2 : consdata->bilinterms[quadvarterm->adjbilin[i]].var1;
4364  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, othervar, &othervaridx) );
4365  assert(othervaridx >= 0);
4366  SCIP_CALL( presolveDisaggregateMarkComponent(scip, consdata, othervaridx, var2component, componentnr, componentsize) );
4367  }
4368 
4369  return SCIP_OKAY;
4370 }
4371 
4372 /** merges components in variables connectivity graph */
4373 static
4375  SCIP* scip, /**< SCIP data structure */
4376  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
4377  SCIP_HASHMAP* var2component, /**< variables to component mapping */
4378  int nvars, /**< number of variables */
4379  int* ncomponents, /**< number of components */
4380  int* componentssize /**< size of components */
4381  )
4382 {
4383  SCIP_CONSHDLRDATA* conshdlrdata;
4384  SCIP_HASHMAPENTRY* entry;
4385  int maxncomponents;
4386  int* oldcompidx;
4387  int* newcompidx;
4388  int i;
4389  int oldcomponent;
4390  int newcomponent;
4391 
4392  assert(scip != NULL);
4393  assert(conshdlr != NULL);
4394  assert(var2component != NULL);
4395  assert(ncomponents != NULL);
4396  assert(componentssize != NULL);
4397 
4398  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4399  assert(conshdlrdata != NULL);
4400 
4401  maxncomponents = conshdlrdata->maxdisaggrsize;
4402  assert(maxncomponents > 0);
4403 
4404  /* if already not too many components, then nothing to do */
4405  if( *ncomponents <= maxncomponents )
4406  return SCIP_OKAY;
4407 
4408  /*
4409  printf("component sizes before:");
4410  for( i = 0; i < *ncomponents; ++i )
4411  printf(" %d", componentssize[i]);
4412  printf("\n");
4413  */
4414 
4415  SCIP_CALL( SCIPallocBufferArray(scip, &oldcompidx, *ncomponents) );
4416  SCIP_CALL( SCIPallocBufferArray(scip, &newcompidx, *ncomponents) );
4417 
4418  for( i = 0; i < *ncomponents; ++i )
4419  oldcompidx[i] = i;
4420 
4421  switch( conshdlrdata->disaggrmergemethod )
4422  {
4423  case 's' :
4424  /* sort components by size, increasing order */
4425  SCIPsortIntInt(componentssize, oldcompidx, *ncomponents);
4426  break;
4427  case 'b' :
4428  case 'm' :
4429  /* sort components by size, decreasing order */
4430  SCIPsortDownIntInt(componentssize, oldcompidx, *ncomponents);
4431  break;
4432  default :
4433  SCIPerrorMessage("invalid value for constraints/quadratic/disaggrmergemethod parameter");
4434  return SCIP_PARAMETERWRONGVAL;
4435  }
4436 
4437  SCIPdebugMsg(scip, "%-30s: % 4d components of size % 4d to % 4d, median: % 4d\n", SCIPgetProbName(scip), *ncomponents, componentssize[0], componentssize[*ncomponents-1], componentssize[*ncomponents/2]);
4438 
4439  if( conshdlrdata->disaggrmergemethod == 'm' )
4440  {
4441  SCIP_Real targetsize;
4442  int count = 0;
4443 
4444  /* a minimal component size we should reach to have all components roughly the same size */
4445  targetsize = nvars / maxncomponents; /*lint !e653*/
4446  for( i = 0; i < *ncomponents; ++i )
4447  {
4448  newcompidx[oldcompidx[i]] = i;
4449  count += componentssize[i];
4450 
4451  /* fill with small components until we reach targetsize
4452  * Since targetsize might be fractional, we also add another component if
4453  * the number of variables remaining (=nvars-count) is larger than
4454  * what we expect to put into the remaining components (=targetsize * (maxncomponents - i-1)).
4455  * Thus, from time to time, a component is made larger than the targetsize to avoid
4456  * having to add much into the last component.
4457  */
4458  while( i < *ncomponents-1 && (componentssize[i] + componentssize[*ncomponents-1] <= targetsize ||
4459  nvars - count > targetsize * (maxncomponents - i)) )
4460  {
4461  /* map last (=smallest) component to component i */
4462  newcompidx[oldcompidx[*ncomponents-1]] = i;
4463 
4464  /* increase size of component i accordingly */
4465  componentssize[i] += componentssize[*ncomponents-1];
4466  count += componentssize[*ncomponents-1];
4467 
4468  /* forget about last component */
4469  --*ncomponents;
4470  }
4471  }
4472  assert(count == nvars);
4473  }
4474  else
4475  {
4476  /* get inverse permutation */
4477  for( i = 0; i < *ncomponents; ++i )
4478  newcompidx[oldcompidx[i]] = i;
4479  }
4480 
4481  /* assign new component numbers to variables, cutting off at maxncomponents */
4482  for( i = 0; i < SCIPhashmapGetNEntries(var2component); ++i )
4483  {
4484  entry = SCIPhashmapGetEntry(var2component, i);
4485  if( entry == NULL )
4486  continue;
4487 
4488  oldcomponent = (int)(size_t)SCIPhashmapEntryGetImage(entry);
4489 
4490  newcomponent = newcompidx[oldcomponent];
4491  if( newcomponent >= maxncomponents )
4492  {
4493  newcomponent = maxncomponents-1;
4494  ++componentssize[maxncomponents-1];
4495  }
4496 
4497  SCIPhashmapEntrySetImage(entry, (void*)(size_t)newcomponent); /*lint !e571*/
4498  }
4499  if( *ncomponents > maxncomponents )
4500  *ncomponents = maxncomponents;
4501 
4502  /*
4503  printf("component sizes after :");
4504  for( i = 0; i < *ncomponents; ++i )
4505  printf(" %d", componentssize[i]);
4506  printf("\n");
4507  */
4508 
4509  SCIPfreeBufferArray(scip, &newcompidx);
4510  SCIPfreeBufferArray(scip, &oldcompidx);
4511 
4512  return SCIP_OKAY;
4513 }
4514 
4515 /** compute the next highest power of 2 for a 32-bit argument
4516  *
4517  * Source: https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
4518  *
4519  * @note Returns 0 for v=0.
4520  */
4521 static
4522 unsigned int nextPowerOf2(
4523  unsigned int v /**< input */
4524  )
4525 {
4526  v--;
4527  v |= v >> 1;
4528  v |= v >> 2;
4529  v |= v >> 4;
4530  v |= v >> 8;
4531  v |= v >> 16;
4532  v++;
4533 
4534  return v;
4535 }
4536 
4537 
4538 /** for quadratic constraints that consists of a sum of quadratic terms, disaggregates the sum into a set of constraints by introducing auxiliary variables
4539  *
4540  * Assume the quadratic constraint can be written in the form
4541  * lhs <= b'x + sum_{k=1..p} q_k(x_k) <= rhs
4542  * where x_k denotes a subset of the variables in x and these subsets are pairwise disjunct
4543  * and q_k(.) is a quadratic form.
4544  * p is selected as large as possible, but to be <= conshdlrdata->maxdisaggrsize.
4545  *
4546  * Without additional scaling, the constraint is disaggregated into
4547  * lhs <= b'x + sum_k c_k z_k <= rhs
4548  * c_k z_k ~ q_k(x)
4549  * where "~" is either "<=", "==", or ">=", depending on whether lhs or rhs are infinite.
4550  * Further, c_k is chosen to be the maximal absolute value of the coefficients of the quadratic terms in q_k(x).
4551  * This is done to ensure that z_k takes values with a similar magnitute as the variables in x_k (better for separation).
4552  *
4553  * However, a solution of this disaggregated system can violate the original constraint by (p+1)*epsilon
4554  * (assuming unscaled violations are used, which is the default).
4555  * Therefore, all constraints are scaled by p+1:
4556  * (p+1)*lhs <= (p+1)*b'x + (p+1) * sum_k c_k z_k <= (p+1) * rhs
4557  * (p+1)*c_k z_k ~ (p+1)*q_k(x)
4558  */
4559 static
4561  SCIP* scip, /**< SCIP data structure */
4562  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
4563  SCIP_CONS* cons, /**< source constraint to try to convert */
4564  int* naddconss /**< pointer to counter of added constraints */
4565  )
4566 {
4567  SCIP_CONSDATA* consdata;
4568  SCIP_HASHMAP* var2component;
4569  int* componentssize;
4570  int ncomponents;
4571  int i;
4572  int comp;
4573  SCIP_CONS** auxconss;
4574  SCIP_VAR** auxvars;
4575  SCIP_Real* auxcoefs;
4576 #ifdef WITH_DEBUG_SOLUTION
4577  SCIP_Real* auxsolvals; /* value of auxiliary variable in debug solution */
4578 #endif
4579  SCIP_Real scale;
4580  char name[SCIP_MAXSTRLEN];
4581 
4582  assert(scip != NULL);
4583  assert(conshdlr != NULL);
4584  assert(cons != NULL);
4585  assert(naddconss != NULL);
4586 
4587  consdata = SCIPconsGetData(cons);
4588  assert(consdata != NULL);
4589 
4590  /* skip if constraint has been already disaggregated */
4591  if( consdata->isdisaggregated )
4592  return SCIP_OKAY;
4593 
4594  consdata->isdisaggregated = TRUE;
4595 
4596  /* make sure there are no quadratic variables without coefficients */
4597  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
4598  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, cons) );
4599 
4600  if( consdata->nquadvars <= 1 )
4601  return SCIP_OKAY;
4602 
4603  /* sort quadratic variable terms here, so we can later search in it without reordering the array */
4604  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
4605 
4606  /* check how many quadratic terms with non-overlapping variables we have
4607  * in other words, the number of components in the sparsity graph of the quadratic term matrix
4608  */
4609  ncomponents = 0;
4610  SCIP_CALL( SCIPhashmapCreate(&var2component, SCIPblkmem(scip), consdata->nquadvars) );
4611  SCIP_CALL( SCIPallocBufferArray(scip, &componentssize, consdata->nquadvars) );
4612  for( i = 0; i < consdata->nquadvars; ++i )
4613  {
4614  /* if variable was marked already, skip it */
4615  if( SCIPhashmapExists(var2component, (void*)consdata->quadvarterms[i].var) )
4616  continue;
4617 
4618  /* start a new component with variable i */
4619  componentssize[ncomponents] = 0;
4620  SCIP_CALL( presolveDisaggregateMarkComponent(scip, consdata, i, var2component, ncomponents, componentssize + ncomponents) );
4621  ++ncomponents;
4622  }
4623 
4624  assert(ncomponents >= 1);
4625 
4626  /* if there is only one component, we cannot disaggregate
4627  * @todo we could still split the constraint into several while keeping the number of variables sharing several constraints as small as possible
4628  */
4629  if( ncomponents == 1 )
4630  {
4631  SCIPhashmapFree(&var2component);
4632  SCIPfreeBufferArray(scip, &componentssize);
4633  return SCIP_OKAY;
4634  }
4635 
4636  /* merge some components, if necessary */
4637  SCIP_CALL( presolveDisaggregateMergeComponents(scip, conshdlr, var2component, consdata->nquadvars, &ncomponents, componentssize) );
4638 
4639  SCIPfreeBufferArray(scip, &componentssize);
4640 
4641  /* scale all new constraints (ncomponents+1 many) by ncomponents+1 (or its next power of 2), so violations sum up to at most epsilon */
4642  scale = nextPowerOf2((unsigned int)ncomponents + 1);
4643 
4644  SCIP_CALL( SCIPallocBufferArray(scip, &auxconss, ncomponents) );
4645  SCIP_CALL( SCIPallocBufferArray(scip, &auxvars, ncomponents) );
4646  SCIP_CALL( SCIPallocBufferArray(scip, &auxcoefs, ncomponents) );
4647 #ifdef WITH_DEBUG_SOLUTION
4648  SCIP_CALL( SCIPallocClearBufferArray(scip, &auxsolvals, ncomponents) );
4649 #endif
4650 
4651  /* create auxiliary variables and empty constraints for each component */
4652  for( comp = 0; comp < ncomponents; ++comp )
4653  {
4654  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_comp%d", SCIPconsGetName(cons), comp);
4655 
4656  SCIP_CALL( SCIPcreateVar(scip, &auxvars[comp], name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
4658 
4659  SCIP_CALL( SCIPcreateConsQuadratic2(scip, &auxconss[comp], name, 0, NULL, NULL, 0, NULL, 0, NULL,
4660  (SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : 0.0),
4661  (SCIPisInfinity(scip, consdata->rhs) ? SCIPinfinity(scip) : 0.0),
4664  SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons)) );
4665 
4666  auxcoefs[comp] = SCIPinfinity(scip);
4667  }
4668 
4669  /* add quadratic variables to each component constraint
4670  * delete adjacency information */
4671  for( i = 0; i < consdata->nquadvars; ++i )
4672  {
4673  assert(SCIPhashmapExists(var2component, consdata->quadvarterms[i].var));
4674 
4675  comp = (int)(size_t) SCIPhashmapGetImage(var2component, consdata->quadvarterms[i].var);
4676  assert(comp >= 0);
4677  assert(comp < ncomponents);
4678 
4679  /* add variable term to corresponding constraint */
4680  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, auxconss[comp], consdata->quadvarterms[i].var, scale * consdata->quadvarterms[i].lincoef, scale * consdata->quadvarterms[i].sqrcoef) );
4681 
4682  /* reduce coefficient of aux variable */
4683  if( !SCIPisZero(scip, consdata->quadvarterms[i].lincoef) && ABS(consdata->quadvarterms[i].lincoef) < auxcoefs[comp] )
4684  auxcoefs[comp] = REALABS(consdata->quadvarterms[i].lincoef);
4685  if( !SCIPisZero(scip, consdata->quadvarterms[i].sqrcoef) && ABS(consdata->quadvarterms[i].sqrcoef) < auxcoefs[comp] )
4686  auxcoefs[comp] = REALABS(consdata->quadvarterms[i].sqrcoef);
4687 
4688  SCIPfreeBlockMemoryArray(scip, &consdata->quadvarterms[i].adjbilin, consdata->quadvarterms[i].adjbilinsize);
4689  consdata->quadvarterms[i].nadjbilin = 0;
4690  consdata->quadvarterms[i].adjbilinsize = 0;
4691 
4692 #ifdef WITH_DEBUG_SOLUTION
4693  if( SCIPdebugIsMainscip(scip) )
4694  {
4695  SCIP_Real debugvarval;
4696 
4697  SCIP_CALL( SCIPdebugGetSolVal(scip, consdata->quadvarterms[i].var, &debugvarval) );
4698  auxsolvals[comp] += consdata->quadvarterms[i].lincoef * debugvarval + consdata->quadvarterms[i].sqrcoef * debugvarval * debugvarval;
4699  }
4700 #endif
4701  }
4702 
4703  /* add bilinear terms to each component constraint */
4704  for( i = 0; i < consdata->nbilinterms; ++i )
4705  {
4706  assert(SCIPhashmapExists(var2component, consdata->bilinterms[i].var1));
4707  assert(SCIPhashmapExists(var2component, consdata->bilinterms[i].var2));
4708 
4709  comp = (int)(size_t) SCIPhashmapGetImage(var2component, consdata->bilinterms[i].var1);
4710  assert(comp == (int)(size_t) SCIPhashmapGetImage(var2component, consdata->bilinterms[i].var2));
4711  assert(!SCIPisZero(scip, consdata->bilinterms[i].coef));
4712 
4713  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, auxconss[comp],
4714  consdata->bilinterms[i].var1, consdata->bilinterms[i].var2, scale * consdata->bilinterms[i].coef) );
4715 
4716  if( ABS(consdata->bilinterms[i].coef) < auxcoefs[comp] )
4717  auxcoefs[comp] = ABS(consdata->bilinterms[i].coef);
4718 
4719 #ifdef WITH_DEBUG_SOLUTION
4720  if( SCIPdebugIsMainscip(scip) )
4721  {
4722  SCIP_Real debugvarval1;
4723  SCIP_Real debugvarval2;
4724 
4725  SCIP_CALL( SCIPdebugGetSolVal(scip, consdata->bilinterms[i].var1, &debugvarval1) );
4726  SCIP_CALL( SCIPdebugGetSolVal(scip, consdata->bilinterms[i].var2, &debugvarval2) );
4727  auxsolvals[comp] += consdata->bilinterms[i].coef * debugvarval1 * debugvarval2;
4728  }
4729 #endif
4730  }
4731 
4732  /* forget about bilinear terms in cons */
4733  SCIPfreeBlockMemoryArray(scip, &consdata->bilinterms, consdata->bilintermssize);
4734  consdata->nbilinterms = 0;
4735  consdata->bilintermssize = 0;
4736 
4737  /* remove quadratic variable terms from cons */
4738  for( i = consdata->nquadvars - 1; i >= 0; --i )
4739  {
4740  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
4741  }
4742  assert(consdata->nquadvars == 0);
4743 
4744  /* scale remaining linear variables and sides by scale */
4745  for( i = 0; i < consdata->nlinvars; ++i )
4746  {
4747  SCIP_CALL( chgLinearCoefPos(scip, cons, i, scale * consdata->lincoefs[i]) );
4748  }
4749  if( !SCIPisInfinity(scip, -consdata->lhs) )
4750  {
4751  consdata->lhs *= scale;
4752  assert(!SCIPisInfinity(scip, -consdata->lhs) );
4753  }
4754  if( !SCIPisInfinity(scip, consdata->rhs) )
4755  {
4756  consdata->rhs *= scale;
4757  assert(!SCIPisInfinity(scip, consdata->rhs) );
4758  }
4759 
4760  /* add auxiliary variables to auxiliary constraints
4761  * add aux vars and constraints to SCIP
4762  * add aux vars to this constraint
4763  * set value of aux vars in debug solution, if any
4764  */
4765  SCIPdebugMsg(scip, "add %d constraints for disaggregation of quadratic constraint <%s>\n", ncomponents, SCIPconsGetName(cons));
4766  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars + ncomponents) );
4767  for( comp = 0; comp < ncomponents; ++comp )
4768  {
4769  SCIP_CONSDATA* auxconsdata;
4770 
4771  SCIP_CALL( SCIPaddLinearVarQuadratic(scip, auxconss[comp], auxvars[comp], -scale * auxcoefs[comp]) );
4772 
4773  SCIP_CALL( SCIPaddVar(scip, auxvars[comp]) );
4774 
4775  SCIP_CALL( SCIPaddCons(scip, auxconss[comp]) );
4776  SCIPdebugPrintCons(scip, auxconss[comp], NULL);
4777 
4778  SCIP_CALL( addLinearCoef(scip, cons, auxvars[comp], scale * auxcoefs[comp]) );
4779 
4780  /* mark that the constraint should not further be disaggregated */
4781  auxconsdata = SCIPconsGetData(auxconss[comp]);
4782  assert(auxconsdata != NULL);
4783  auxconsdata->isdisaggregated = TRUE;
4784 
4785 #ifdef WITH_DEBUG_SOLUTION
4786  if( SCIPdebugIsMainscip(scip) )
4787  {
4788  /* auxvar should take value from auxsolvals in debug solution, but we also scaled auxvar by auxcoefs[comp] */
4789  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvars[comp], auxsolvals[comp] / auxcoefs[comp]) );
4790  }
4791 #endif
4792 
4793  SCIP_CALL( SCIPreleaseCons(scip, &auxconss[comp]) );
4794  SCIP_CALL( SCIPreleaseVar(scip, &auxvars[comp]) );
4795  }
4796  *naddconss += ncomponents;
4797 
4798  SCIPdebugPrintCons(scip, cons, NULL);
4799 
4800  SCIPfreeBufferArray(scip, &auxconss);
4801  SCIPfreeBufferArray(scip, &auxvars);
4802  SCIPfreeBufferArray(scip, &auxcoefs);
4803 #ifdef WITH_DEBUG_SOLUTION
4804  SCIPfreeBufferArray(scip, &auxsolvals);
4805 #endif
4806  SCIPhashmapFree(&var2component);
4807 
4808  return SCIP_OKAY;
4809 }
4810 
4811 #ifdef CHECKIMPLINBILINEAR
4812 /** checks if there are bilinear terms x*y with a binary variable x and an implication x = {0,1} -> y = 0
4813  *
4814  * In this case, the bilinear term can be removed (x=0 case) or replaced by y (x=1 case).
4815  */
4816 static
4817 SCIP_RETCODE presolveApplyImplications(
4818  SCIP* scip, /**< SCIP data structure */
4819  SCIP_CONS* cons, /**< quadratic constraint */
4820  int* nbilinremoved /**< buffer to store number of removed bilinear terms */
4821  )
4822 {
4823  SCIP_CONSDATA* consdata;
4824  SCIP_VAR* x;
4825  SCIP_VAR* y;
4826  SCIP_INTERVAL implbnds;
4827  int i;
4828  int j;
4829  int k;
4830 
4831  assert(scip != NULL);
4832  assert(cons != NULL);
4833  assert(nbilinremoved != NULL);
4834 
4835  *nbilinremoved = 0;
4836 
4837  consdata = SCIPconsGetData(cons);
4838  assert(consdata != NULL);
4839 
4840  SCIPdebugMsg(scip, "apply implications in <%s>\n", SCIPconsGetName(cons));
4841 
4842  /* sort quadvarterms in case we need to search */
4843  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
4844 
4845  for( i = 0; i < consdata->nquadvars; ++i )
4846  {
4847  x = consdata->quadvarterms[i].var;
4848  assert(x != NULL);
4849 
4850  if( consdata->quadvarterms[i].nadjbilin == 0 )
4851  continue;
4852 
4853  if( !SCIPvarIsBinary(x) )
4854  continue;
4855 
4856  if( !SCIPvarIsActive(x) )
4857  continue;
4858 
4859  if( SCIPvarGetNImpls(x, TRUE) == 0 && SCIPvarGetNImpls(x, FALSE) == 0 )
4860  continue;
4861 
4862  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
4863  {
4864  k = consdata->quadvarterms[i].adjbilin[j];
4865  assert(k >= 0);
4866  assert(k < consdata->nbilinterms);
4867 
4868  if( consdata->bilinterms[k].coef == 0.0 )
4869  continue;
4870 
4871  y = consdata->bilinterms[k].var1 == x ? consdata->bilinterms[k].var2 : consdata->bilinterms[k].var1;
4872  assert(x != y);
4873 
4874  SCIP_CALL( getImpliedBounds(scip, x, TRUE, y, &implbnds) );
4875  if( SCIPisZero(scip, implbnds.inf) && SCIPisZero(scip, implbnds.sup) )
4876  {
4877  /* if x = 1 implies y = 0, then we can remove the bilinear term x*y, since it is always 0
4878  * we only set the coefficient to 0.0 here and mark the bilinterms as not merged */
4879  SCIPdebugMsg(scip, "remove bilinear term %g<%s><%s> from <%s> due to implication\n", consdata->bilinterms[k].coef, SCIPvarGetName(x), SCIPvarGetName(y), SCIPconsGetName(cons));
4880  consdata->bilinterms[k].coef = 0.0;
4881  consdata->bilinmerged = FALSE;
4882  ++*nbilinremoved;
4883  continue;
4884  }
4885 
4886  SCIP_CALL( getImpliedBounds(scip, x, FALSE, y, &implbnds) );
4887  if( SCIPisZero(scip, implbnds.inf) && SCIPisZero(scip, implbnds.sup) )
4888  {
4889  /* if x = 0 implies y = 0, then we can replace the bilinear term x*y by y
4890  * we only move the coefficient to the linear coef of y here and mark the bilinterms as not merged */
4891  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));
4892  assert(consdata->quadvarssorted);
4893  SCIP_CALL( SCIPaddQuadVarLinearCoefQuadratic(scip, cons, y, consdata->bilinterms[k].coef) );
4894  consdata->bilinterms[k].coef = 0.0;
4895  consdata->bilinmerged = FALSE;
4896  ++*nbilinremoved;
4897  }
4898  }
4899  }
4900 
4901  if( *nbilinremoved > 0 )
4902  {
4903  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
4904 
4905  /* invalidate nonlinear row */
4906  if( consdata->nlrow != NULL )
4907  {
4908  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
4909  }
4910 
4911  consdata->ispropagated = FALSE;
4912  consdata->ispresolved = FALSE;
4913  consdata->iscurvchecked = FALSE;
4914  }
4915 
4916  consdata->isimpladded = FALSE;
4917 
4918  return SCIP_OKAY;
4919 }
4920 #endif
4921 
4922 /** checks a quadratic constraint for convexity and/or concavity without checking multivariate functions */
4923 static
4924 void checkCurvatureEasy(
4925  SCIP* scip, /**< SCIP data structure */
4926  SCIP_CONS* cons, /**< quadratic constraint */
4927  SCIP_Bool* determined, /**< pointer to store whether the curvature could be determined */
4928  SCIP_Bool checkmultivariate /**< whether curvature will be checked later on for multivariate functions */
4929  )
4930 {
4931  SCIP_CONSDATA* consdata;
4932  int nquadvars;
4933 
4934  assert(scip != NULL);
4935  assert(cons != NULL);
4936  assert(determined != NULL);
4937 
4938  consdata = SCIPconsGetData(cons);
4939  assert(consdata != NULL);
4940 
4941  nquadvars = consdata->nquadvars;
4942  *determined = TRUE;
4943 
4944  if( consdata->iscurvchecked )
4945  return;
4946 
4947  SCIPdebugMsg(scip, "Checking curvature of constraint <%s> without multivariate functions\n", SCIPconsGetName(cons));
4948 
4949  consdata->maxnonconvexity = 0.0;
4950  if( nquadvars == 1 )
4951  {
4952  assert(consdata->nbilinterms == 0);
4953  consdata->isconvex = !SCIPisNegative(scip, consdata->quadvarterms[0].sqrcoef);
4954  consdata->isconcave = !SCIPisPositive(scip, consdata->quadvarterms[0].sqrcoef);
4955  consdata->iscurvchecked = TRUE;
4956 
4957  if( !SCIPisInfinity(scip, -consdata->lhs) && consdata->quadvarterms[0].sqrcoef > 0.0 )
4958  consdata->maxnonconvexity = consdata->quadvarterms[0].sqrcoef;
4959  if( !SCIPisInfinity(scip, consdata->rhs) && consdata->quadvarterms[0].sqrcoef < 0.0 )
4960  consdata->maxnonconvexity = -consdata->quadvarterms[0].sqrcoef;
4961  }
4962  else if( nquadvars == 0 )
4963  {
4964  consdata->isconvex = TRUE;
4965  consdata->isconcave = TRUE;
4966  consdata->iscurvchecked = TRUE;
4967  }
4968  else if( consdata->nbilinterms == 0 )
4969  {
4970  int v;
4971 
4972  consdata->isconvex = TRUE;
4973  consdata->isconcave = TRUE;
4974 
4975  for( v = nquadvars - 1; v >= 0; --v )
4976  {
4977  consdata->isconvex = consdata->isconvex && !SCIPisNegative(scip, consdata->quadvarterms[v].sqrcoef);
4978  consdata->isconcave = consdata->isconcave && !SCIPisPositive(scip, consdata->quadvarterms[v].sqrcoef);
4979 
4980  if( !SCIPisInfinity(scip, -consdata->lhs) && consdata->quadvarterms[v].sqrcoef > consdata->maxnonconvexity )
4981  consdata->maxnonconvexity = consdata->quadvarterms[0].sqrcoef;
4982  if( !SCIPisInfinity(scip, consdata->rhs) && -consdata->quadvarterms[v].sqrcoef > consdata->maxnonconvexity )
4983  consdata->maxnonconvexity = -consdata->quadvarterms[0].sqrcoef;
4984  }
4985 
4986  consdata->iscurvchecked = TRUE;
4987  }
4988  else if( !checkmultivariate )
4989  {
4990  consdata->isconvex = FALSE;
4991  consdata->isconcave = FALSE;
4992  consdata->iscurvchecked = TRUE;
4993  consdata->maxnonconvexity = SCIPinfinity(scip);
4994  }
4995  else
4996  *determined = FALSE;
4997 }
4998 
4999 /** checks a quadratic constraint for convexity and/or concavity */
5000 static
5002  SCIP* scip, /**< SCIP data structure */
5003  SCIP_CONS* cons, /**< quadratic constraint */
5004  SCIP_Bool checkmultivariate /**< whether curvature should also be checked for multivariate functions */
5005  )
5006 {
5007  SCIP_CONSDATA* consdata;
5008  double* matrix;
5009  SCIP_HASHMAP* var2index;
5010  int i;
5011  int n;
5012  int nn;
5013  int row;
5014  int col;
5015  double* alleigval;
5016  SCIP_Bool determined;
5017 
5018  assert(scip != NULL);
5019  assert(cons != NULL);
5020 
5021  consdata = SCIPconsGetData(cons);
5022  assert(consdata != NULL);
5023 
5024  n = consdata->nquadvars;
5025 
5026  if( consdata->iscurvchecked )
5027  return SCIP_OKAY;
5028 
5029  /* easy checks for curvature detection */
5030  checkCurvatureEasy(scip, cons, &determined, checkmultivariate);
5031 
5032  /* if curvature was already detected stop */
5033  if( determined )
5034  {
5035  return SCIP_OKAY;
5036  }
5037 
5038  SCIPdebugMsg(scip, "Checking curvature of constraint <%s> with multivariate functions\n", SCIPconsGetName(cons));
5039 
5040  if( n == 2 )
5041  {
5042  SCIP_Real tracehalf;
5043  SCIP_Real discriminantroot;
5044 
5045  /* compute eigenvalues by hand */
5046  assert(consdata->nbilinterms == 1);
5047  consdata->isconvex =
5048  consdata->quadvarterms[0].sqrcoef >= 0 &&
5049  consdata->quadvarterms[1].sqrcoef >= 0 &&
5050  4 * consdata->quadvarterms[0].sqrcoef * consdata->quadvarterms[1].sqrcoef >= consdata->bilinterms[0].coef * consdata->bilinterms[0].coef;
5051  consdata->isconcave =
5052  consdata->quadvarterms[0].sqrcoef <= 0 &&
5053  consdata->quadvarterms[1].sqrcoef <= 0 &&
5054  4 * consdata->quadvarterms[0].sqrcoef * consdata->quadvarterms[1].sqrcoef >= consdata->bilinterms[0].coef * consdata->bilinterms[0].coef;
5055 
5056  /* store largest eigenvalue causing nonconvexity according to sides */
5057  tracehalf = (consdata->quadvarterms[0].sqrcoef + consdata->quadvarterms[1].sqrcoef) / 2.0;
5058  discriminantroot = consdata->quadvarterms[0].sqrcoef * consdata->quadvarterms[1].sqrcoef - SQR(consdata->bilinterms[0].coef / 2.0);
5059  discriminantroot = SQR(tracehalf) - discriminantroot;
5060  assert(!SCIPisNegative(scip, discriminantroot));
5061  discriminantroot = SQRT(MAX(0.0, discriminantroot));
5062 
5063  consdata->maxnonconvexity = 0.0;
5064  if( !SCIPisInfinity(scip, -consdata->lhs) )
5065  consdata->maxnonconvexity = MAX(consdata->maxnonconvexity, tracehalf + discriminantroot);
5066  if( !SCIPisInfinity(scip, consdata->rhs) )
5067  consdata->maxnonconvexity = MAX(consdata->maxnonconvexity, discriminantroot - tracehalf);
5068 
5069  consdata->iscurvchecked = TRUE;
5070  return SCIP_OKAY;
5071  }
5072 
5073  /* do not check curvature if n is too large */
5074  nn = n * n;
5075  if( nn < 0 || (unsigned) (int) nn > UINT_MAX / sizeof(SCIP_Real) )
5076  {
5077  SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL, "cons_quadratic - n is too large to check the curvature\n");
5078  consdata->isconvex = FALSE;
5079  consdata->isconcave = FALSE;
5080  consdata->iscurvchecked = TRUE;
5081  consdata->maxnonconvexity = SCIPinfinity(scip);
5082  return SCIP_OKAY;
5083  }
5084 
5085  /* lower triangular of quadratic term matrix */
5086  SCIP_CALL( SCIPallocBufferArray(scip, &matrix, nn) );
5087  BMSclearMemoryArray(matrix, nn);
5088 
5089  consdata->isconvex = TRUE;
5090  consdata->isconcave = TRUE;
5091  consdata->maxnonconvexity = 0.0;
5092 
5093  SCIP_CALL( SCIPhashmapCreate(&var2index, SCIPblkmem(scip), n) );
5094  for( i = 0; i < n; ++i )
5095  {
5096  if( consdata->quadvarterms[i].nadjbilin > 0 )
5097  {
5098  SCIP_CALL( SCIPhashmapInsert(var2index, consdata->quadvarterms[i].var, (void*)(size_t)i) );
5099  matrix[i*n + i] = consdata->quadvarterms[i].sqrcoef;
5100  }
5101  else
5102  {
5103  /* if pure square term, then update maximal nonconvex eigenvalue, as it will not be considered in lapack call below */
5104  if( !SCIPisInfinity(scip, -consdata->lhs) && consdata->quadvarterms[i].sqrcoef > consdata->maxnonconvexity )
5105  consdata->maxnonconvexity = consdata->quadvarterms[i].sqrcoef;
5106  if( !SCIPisInfinity(scip, consdata->rhs) && -consdata->quadvarterms[i].sqrcoef > consdata->maxnonconvexity )
5107  consdata->maxnonconvexity = -consdata->quadvarterms[i].sqrcoef;
5108  }
5109  /* nonzero elements on diagonal tell a lot about convexity/concavity */
5110  if( SCIPisNegative(scip, consdata->quadvarterms[i].sqrcoef) )
5111  consdata->isconvex = FALSE;
5112  if( SCIPisPositive(scip, consdata->quadvarterms[i].sqrcoef) )
5113  consdata->isconcave = FALSE;
5114  }
5115 
5116  /* skip lapack call, if we know already that we are indefinite
5117  * NOTE: this will leave out updating consdata->maxnonconvexity, so that it only provides a lower bound in this case
5118  */
5119  if( !consdata->isconvex && !consdata->isconcave )
5120  {
5121  SCIPfreeBufferArray(scip, &matrix);
5122  SCIPhashmapFree(&var2index);
5123  consdata->iscurvchecked = TRUE;
5124  /* make sure that maxnonconvexity is strictly different from zero if nonconvex
5125  * TODO one could think about doing some eigenvalue estimation here (Gershgorin)
5126  */
5127  consdata->maxnonconvexity = MAX(1000.0, consdata->maxnonconvexity);
5128  return SCIP_OKAY;
5129  }
5130 
5132  {
5133  for( i = 0; i < consdata->nbilinterms; ++i )
5134  {
5135  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var1));
5136  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var2));
5137  row = (int)(size_t)SCIPhashmapGetImage(var2index, consdata->bilinterms[i].var1);
5138  col = (int)(size_t)SCIPhashmapGetImage(var2index, consdata->bilinterms[i].var2);
5139  if( row < col )
5140  matrix[row * n + col] = consdata->bilinterms[i].coef/2;
5141  else
5142  matrix[col * n + row] = consdata->bilinterms[i].coef/2;
5143  }
5144 
5145  SCIP_CALL( SCIPallocBufferArray(scip, &alleigval, n) );
5146  /* @todo Can we compute only min and max eigen value?
5147  * @todo Can we estimate the numerical error?
5148  * @todo Trying a cholesky factorization may be much faster.
5149  */
5150  if( LapackDsyev(FALSE, n, matrix, alleigval) != SCIP_OKAY )
5151  {
5152  SCIPwarningMessage(scip, "Failed to compute eigenvalues of quadratic coefficient matrix of constraint %s. Assuming matrix is indefinite.\n", SCIPconsGetName(cons));
5153  consdata->isconvex = FALSE;
5154  consdata->isconcave = FALSE;
5155  }
5156  else
5157  {
5158  /* deconvexification reformulates a stricly convex quadratic function in binaries such that it becomes not-strictly convex
5159  * by adding the -lambda*(x^2-x) terms for lambda the smallest eigenvalue of the matrix
5160  * 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
5161  */
5162 #ifdef DECONVEXIFY
5163  SCIP_Bool allbinary;
5164  printf("cons <%s>[%g,%g] spectrum = [%g,%g]\n", SCIPconsGetName(cons), consdata->lhs, consdata->rhs, alleigval[0], alleigval[n-1]);
5165 #endif
5166  consdata->isconvex &= !SCIPisNegative(scip, alleigval[0]); /*lint !e514*/
5167  consdata->isconcave &= !SCIPisPositive(scip, alleigval[n-1]); /*lint !e514*/
5168  consdata->iscurvchecked = TRUE;
5169 #ifdef DECONVEXIFY
5170  for( i = 0; i < consdata->nquadvars; ++i )
5171  if( !SCIPvarIsBinary(consdata->quadvarterms[i].var) )
5172  break;
5173  allbinary = i == consdata->nquadvars;
5174 
5175  if( !SCIPisInfinity(scip, consdata->rhs) && alleigval[0] > 0.1 && allbinary )
5176  {
5177  printf("deconvexify cons <%s> by shifting hessian by %g\n", SCIPconsGetName(cons), alleigval[0]);
5178  for( i = 0; i < consdata->nquadvars; ++i )
5179  {
5180  consdata->quadvarterms[i].sqrcoef -= alleigval[0];
5181  consdata->quadvarterms[i].lincoef += alleigval[0];
5182  }
5183  }
5184 
5185  if( !SCIPisInfinity(scip, consdata->lhs) && alleigval[n-1] < -0.1 && allbinary )
5186  {
5187  printf("deconcavify cons <%s> by shifting hessian by %g\n", SCIPconsGetName(cons), alleigval[n-1]);
5188  for( i = 0; i < consdata->nquadvars; ++i )
5189  {
5190  consdata->quadvarterms[i].sqrcoef -= alleigval[n-1];
5191  consdata->quadvarterms[i].lincoef += alleigval[n-1];
5192  }
5193  }
5194 #endif
5195  }
5196 
5197  /* update largest eigenvalue causing nonconvexity according to sides */
5198  if( !SCIPisInfinity(scip, -consdata->lhs) )
5199  consdata->maxnonconvexity = MAX(consdata->maxnonconvexity, alleigval[n-1]);
5200  if( !SCIPisInfinity(scip, consdata->rhs) )
5201  consdata->maxnonconvexity = MAX(consdata->maxnonconvexity, -alleigval[0]);
5202 
5203  SCIPfreeBufferArray(scip, &alleigval);
5204  }
5205  else
5206  {
5207  consdata->isconvex = FALSE;
5208  consdata->isconcave = FALSE;
5209  consdata->iscurvchecked = TRUE; /* set to TRUE since it does not help to repeat this procedure again and again (that will not bring Ipopt in) */
5210  consdata->maxnonconvexity = SCIPinfinity(scip);
5211  }
5212 
5213  SCIPhashmapFree(&var2index);
5214  SCIPfreeBufferArray(scip, &matrix);
5215 
5216  return SCIP_OKAY;
5217 }
5218 
5219 /** check whether indefinite constraint function is factorable and store corresponding coefficients */
5220 static
5222  SCIP* scip, /**< SCIP data structure */
5223  SCIP_CONS* cons /**< constraint */
5224  )
5225 {
5226  SCIP_BILINTERM* bilinterm;
5227  SCIP_CONSDATA* consdata;
5228  SCIP_Real* a;
5229  SCIP_Real* eigvals;
5230  SCIP_Real sigma1;
5231  SCIP_Real sigma2;
5232  SCIP_Bool success;
5233  int n;
5234  int i;
5235  int idx1;
5236  int idx2;
5237  int posidx;
5238  int negidx;
5239 
5240  assert(scip != NULL);
5241  assert(cons != NULL);
5242 
5243  consdata = SCIPconsGetData(cons);
5244  assert(consdata != NULL);
5245  assert(consdata->factorleft == NULL);
5246  assert(consdata->factorright == NULL);
5247 
5248  /* we don't need this if there are no bilinear terms */
5249  if( consdata->nbilinterms == 0 )
5250  return SCIP_OKAY;
5251 
5252  /* write constraint as lhs <= linear + x'^T A x' <= rhs where x' = (x,1) and
5253  * A = ( Q b/2 )
5254  * ( b^T/2 0 )
5255  * compute an eigenvalue factorization of A and check if there are one positive and one negative eigenvalue
5256  * 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
5257  * thus, x'^T A x' = sigma1^2 (v1^T x')^2 - sigma2^2 (v2^T x')^2
5258  * = (sigma1 (v1^T x') - sigma2 (v2^T x')) * (sigma1 (v1^T x') + sigma2 (v2^T x'))
5259  * we then store sigma1 v1^T - sigma2 v2^T as left factor coef, and sigma1 v1^T + sigma2 v2^T as right factor coef
5260  */
5261 
5262  /* if we already know that there are only positive or only negative eigenvalues, then don't try */
5263  if( consdata->iscurvchecked && (consdata->isconvex || consdata->isconcave) )
5264  return SCIP_OKAY;
5265 
5266  n = consdata->nquadvars + 1;
5267 
5268  /* @todo handle case n=3 explicitly */
5269 
5270  /* skip too large matrices */
5271  if( n > 50 )
5272  return SCIP_OKAY;
5273 
5274  /* need routine to compute eigenvalues/eigenvectors */
5275  if( !SCIPisIpoptAvailableIpopt() )
5276  return SCIP_OKAY;
5277 
5278  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
5279 
5280  SCIP_CALL( SCIPallocBufferArray(scip, &a, n*n) );
5281  BMSclearMemoryArray(a, n*n);
5282 
5283  /* set lower triangular entries of A corresponding to bilinear terms */
5284  for( i = 0; i < consdata->nbilinterms; ++i )
5285  {
5286  bilinterm = &consdata->bilinterms[i];
5287 
5288  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var1, &idx1) );
5289  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var2, &idx2) );
5290  assert(idx1 >= 0);
5291  assert(idx2 >= 0);
5292  assert(idx1 != idx2);
5293 
5294  a[MIN(idx1,idx2) * n + MAX(idx1,idx2)] = bilinterm->coef / 2.0;
5295  }
5296 
5297  /* set lower triangular entries of A corresponding to square and linear terms */
5298  for( i = 0; i < consdata->nquadvars; ++i )
5299  {
5300  a[i*n + i] = consdata->quadvarterms[i].sqrcoef;
5301  a[i*n + n-1] = consdata->quadvarterms[i].lincoef / 2.0;
5302  }
5303 
5304  SCIP_CALL( SCIPallocBufferArray(scip, &eigvals, n) );
5305  if( LapackDsyev(TRUE, n, a, eigvals) != SCIP_OKAY )
5306  {
5307  SCIPdebugMsg(scip, "Failed to compute eigenvalues and eigenvectors of augmented quadratic form matrix for constraint <%s>.\n", SCIPconsGetName(cons));
5308  goto CLEANUP;
5309  }
5310 
5311  /* check if there is exactly one positive and one negative eigenvalue */
5312  posidx = -1;
5313  negidx = -1;
5314  for( i = 0; i < n; ++i )
5315  {
5316  if( SCIPisPositive(scip, eigvals[i]) )
5317  {
5318  if( posidx == -1 )
5319  posidx = i;
5320  else
5321  break;
5322  }
5323  else if( SCIPisNegative(scip, eigvals[i]) )
5324  {
5325  if( negidx == -1 )
5326  negidx = i;
5327  else
5328  break;
5329  }
5330  }
5331  if( i < n || posidx == -1 || negidx == -1 )
5332  {
5333  SCIPdebugMsg(scip, "Augmented quadratic form of constraint <%s> is not factorable.\n", SCIPconsGetName(cons));
5334  goto CLEANUP;
5335  }
5336  assert(SCIPisPositive(scip, eigvals[posidx]));
5337  assert(SCIPisNegative(scip, eigvals[negidx]));
5338 
5339  /* compute factorleft and factorright */
5340  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->factorleft, consdata->nquadvars + 1) );
5341  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->factorright, consdata->nquadvars + 1) );
5342 
5343  /* eigenvectors are stored in a, inverse eigenvector matrix is transposed of a
5344  * it seems that v1 and v2 are at &a[posidx*n] and &a[negidx*n]
5345  */
5346  sigma1 = sqrt( eigvals[posidx]);
5347  sigma2 = sqrt(-eigvals[negidx]);
5348  for( i = 0; i < n; ++i )
5349  {
5350  consdata->factorleft[i] = sigma1 * a[posidx * n + i] - sigma2 * a[negidx * n + i];
5351  consdata->factorright[i] = sigma1 * a[posidx * n + i] + sigma2 * a[negidx * n + i];
5352  /* set almost-zero elements to zero */
5353  if( SCIPisZero(scip, consdata->factorleft[i]) )
5354  consdata->factorleft[i] = 0.0;
5355  if( SCIPisZero(scip, consdata->factorright[i]) )
5356  consdata->factorright[i] = 0.0;
5357  }
5358 
5359 #ifdef SCIP_DEBUG
5360  SCIPdebugMsg(scip, "constraint <%s> has factorable quadratic form: (%g", SCIPconsGetName(cons), consdata->factorleft[n-1]);
5361  for( i = 0; i < consdata->nquadvars; ++i )
5362  {
5363  if( consdata->factorleft[i] != 0.0 )
5364  SCIPdebugMsgPrint(scip, " %+g<%s>", consdata->factorleft[i], SCIPvarGetName(consdata->quadvarterms[i].var));
5365  }
5366  SCIPdebugMsgPrint(scip, ") * (%g", consdata->factorright[n-1]);
5367  for( i = 0; i < consdata->nquadvars; ++i )
5368  {
5369  if( consdata->factorright[i] != 0.0 )
5370  SCIPdebugMsgPrint(scip, " %+g<%s>", consdata->factorright[i], SCIPvarGetName(consdata->quadvarterms[i].var));
5371  }
5372  SCIPdebugMsgPrint(scip, ")\n");
5373 #endif
5374 
5375  /* check whether factorleft * factorright^T is matrix of augmented quadratic form
5376  * we check here only the nonzero entries from the quadratic form
5377  */
5378  success = TRUE;
5379 
5380  /* check bilinear terms */
5381  for( i = 0; i < consdata->nbilinterms; ++i )
5382  {
5383  bilinterm = &consdata->bilinterms[i];
5384 
5385  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var1, &idx1) );
5386  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var2, &idx2) );
5387 
5388  if( !SCIPisRelEQ(scip, consdata->factorleft[idx1] * consdata->factorright[idx2] + consdata->factorleft[idx2] * consdata->factorright[idx1], bilinterm->coef) )
5389  {
5390  success = FALSE;
5391  break;
5392  }
5393  }
5394 
5395  /* set lower triangular entries of A corresponding to square and linear terms */
5396  for( i = 0; i < consdata->nquadvars; ++i )
5397  {
5398  if( !SCIPisRelEQ(scip, consdata->factorleft[i] * consdata->factorright[i], consdata->quadvarterms[i].sqrcoef) )
5399  {
5400  success = FALSE;
5401  break;
5402  }
5403 
5404  if( !SCIPisRelEQ(scip, consdata->factorleft[n-1] * consdata->factorright[i] + consdata->factorleft[i] * consdata->factorright[n-1], consdata->quadvarterms[i].lincoef) )
5405  {
5406  success = FALSE;
5407  break;
5408  }
5409  }
5410 
5411  if( !success )
5412  {
5413  SCIPdebugMsg(scip, "Factorization not accurate enough. Dropping it.\n");
5414  SCIPfreeBlockMemoryArray(scip, &consdata->factorleft, consdata->nquadvars + 1);
5415  SCIPfreeBlockMemoryArray(scip, &consdata->factorright, consdata->nquadvars + 1);
5416  }
5417 
5418  CLEANUP:
5419  SCIPfreeBufferArray(scip, &a);
5420  SCIPfreeBufferArray(scip, &eigvals);
5421 
5422  return SCIP_OKAY;
5423 }
5424 
5425 /** computes activity and violation of a constraint
5426  *
5427  * If solution violates bounds by more than feastol, the violation is still computed, but *solviolbounds is set to TRUE
5428  */
5429 static
5431  SCIP* scip, /**< SCIP data structure */
5432  SCIP_CONS* cons, /**< constraint */
5433  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
5434  SCIP_Bool* solviolbounds /**< buffer to store whether quadratic variables in solution are outside their bounds by more than feastol */
5435  )
5436 { /*lint --e{666}*/
5437  SCIP_CONSDATA* consdata;
5438  SCIP_Real varval;
5439  SCIP_Real varval2;
5440  SCIP_Real absviol;
5441  SCIP_Real relviol;
5442  SCIP_VAR* var;
5443  SCIP_VAR* var2;
5444  int i;
5445  int j;
5446 
5447  assert(scip != NULL);
5448  assert(cons != NULL);
5449  assert(solviolbounds != NULL);
5450 
5451  consdata = SCIPconsGetData(cons);
5452  assert(consdata != NULL);
5453 
5454  *solviolbounds = FALSE;
5455  consdata->activity = 0.0;
5456  consdata->lhsviol = 0.0;
5457  consdata->rhsviol = 0.0;
5458 
5459  for( i = 0; i < consdata->nlinvars; ++i )
5460  {
5461  SCIP_Real activity;
5462 
5463  var = consdata->linvars[i];
5464  varval = SCIPgetSolVal(scip, sol, var);
5465  activity = consdata->lincoefs[i] * varval;
5466 
5467  /* the contribution of a variable with |varval| = +inf is +inf when activity > 0.0, -inf when activity < 0.0, and
5468  * 0.0 otherwise
5469  */
5470  if( SCIPisInfinity(scip, REALABS(varval)) )
5471  {
5472  if( activity > 0.0 && !SCIPisInfinity(scip, consdata->rhs) )
5473  {
5474  consdata->activity = SCIPinfinity(scip);
5475  consdata->rhsviol = SCIPinfinity(scip);
5476  return SCIP_OKAY;
5477  }
5478 
5479  if( activity < 0.0 && !SCIPisInfinity(scip, -consdata->lhs) )
5480  {
5481  consdata->activity = -SCIPinfinity(scip);
5482  consdata->lhsviol = SCIPinfinity(scip);
5483  return SCIP_OKAY;
5484  }
5485  }
5486 
5487  consdata->activity += activity;
5488  }
5489 
5490  for( j = 0; j < consdata->nquadvars; ++j )
5491  {
5492  SCIP_Real activity;
5493 
5494  var = consdata->quadvarterms[j].var;
5495  varval = SCIPgetSolVal(scip, sol, var);
5496  activity = (consdata->quadvarterms[j].lincoef + consdata->quadvarterms[j].sqrcoef * varval) * varval;
5497 
5498  /* the contribution of a variable with |varval| = +inf is +inf when activity > 0.0, -inf when activity < 0.0, and
5499  * 0.0 otherwise
5500  */
5501  if( SCIPisInfinity(scip, REALABS(varval)) )
5502  {
5503  if( activity > 0.0 && !SCIPisInfinity(scip, consdata->rhs) )
5504  {
5505  consdata->activity = SCIPinfinity(scip);
5506  consdata->rhsviol = SCIPinfinity(scip);
5507  return SCIP_OKAY;
5508  }
5509 
5510  if( activity < 0.0 && !SCIPisInfinity(scip, -consdata->lhs) )
5511  {
5512  consdata->activity = -SCIPinfinity(scip);
5513  consdata->lhsviol = SCIPinfinity(scip);
5514  return SCIP_OKAY;
5515  }
5516  }
5517 
5518  /* project onto local box, in case the LP solution is slightly outside the bounds (which is not our job to enforce) */
5519  if( sol == NULL )
5520  {
5521  /* 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 */
5522  if( (!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) && !SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var))) ||
5523  (!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) && !SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var))) )
5524  *solviolbounds = TRUE;
5525  else
5526  {
5527  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
5528  activity = (consdata->quadvarterms[j].lincoef + consdata->quadvarterms[j].sqrcoef * varval) * varval;
5529  }
5530  }
5531 
5532  consdata->activity += activity;
5533  }
5534 
5535  for( j = 0; j < consdata->nbilinterms; ++j )
5536  {
5537  SCIP_Real activity;
5538 
5539  var = consdata->bilinterms[j].var1;
5540  var2 = consdata->bilinterms[j].var2;
5541  varval = SCIPgetSolVal(scip, sol, var);
5542  varval2 = SCIPgetSolVal(scip, sol, var2);
5543 
5544  /* project onto local box, in case the LP solution is slightly outside the bounds (which is not our job to enforce) */
5545  if( sol == NULL )
5546  {
5547  /* 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 */
5548  if( (!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) && !SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var))) ||
5549  (!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) && !SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var))) )
5550  *solviolbounds = TRUE;
5551  else
5552  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
5553 
5554  /* 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 */
5555  if( (!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var2)) && !SCIPisFeasGE(scip, varval2, SCIPvarGetLbLocal(var2))) ||
5556  (!SCIPisInfinity(scip, SCIPvarGetUbLocal(var2)) && !SCIPisFeasLE(scip, varval2, SCIPvarGetUbLocal(var2))) )
5557  *solviolbounds = TRUE;
5558  else
5559  varval2 = MAX(SCIPvarGetLbLocal(var2), MIN(SCIPvarGetUbLocal(var2), varval2));
5560  }
5561 
5562  activity = consdata->bilinterms[j].coef * varval * varval2;
5563 
5564  /* consider var*var2 as a new variable and handle it as it would appear linearly */
5565  if( SCIPisInfinity(scip, REALABS(varval*varval2)) )
5566  {
5567  if( activity > 0.0 && !SCIPisInfinity(scip, consdata->rhs) )
5568  {
5569  consdata->activity = SCIPinfinity(scip);
5570  consdata->rhsviol = SCIPinfinity(scip);
5571  return SCIP_OKAY;
5572  }
5573 
5574  if( activity < 0.0 && !SCIPisInfinity(scip, -consdata->lhs) )
5575  {
5576  consdata->activity = -SCIPinfinity(scip);
5577  consdata->lhsviol = SCIPinfinity(scip);
5578  return SCIP_OKAY;
5579  }
5580  }
5581 
5582  consdata->activity += activity;
5583  }
5584 
5585  absviol = 0.0;
5586  relviol = 0.0;
5587  /* compute absolute violation left hand side */
5588  if( consdata->activity < consdata->lhs && !SCIPisInfinity(scip, -consdata->lhs) )
5589  {
5590  consdata->lhsviol = consdata->lhs - consdata->activity;
5591  absviol = consdata->lhsviol;
5592  relviol = SCIPrelDiff(consdata->lhs, consdata->activity);
5593  }
5594  else
5595  consdata->lhsviol = 0.0;
5596 
5597  /* compute absolute violation right hand side */
5598  if( consdata->activity > consdata->rhs && !SCIPisInfinity(scip, consdata->rhs) )
5599  {
5600  consdata->rhsviol = consdata->activity - consdata->rhs;
5601  absviol = consdata->rhsviol;
5602  relviol = SCIPrelDiff(consdata->activity, consdata->rhs);
5603  }
5604  else
5605  consdata->rhsviol = 0.0;
5606 
5607  /* update absolute and relative violation of the solution */
5608  if( sol != NULL )
5609  SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
5610 
5611  return SCIP_OKAY;
5612 }
5613 
5614 /** computes violation of a set of constraints */
5615 static
5617  SCIP* scip, /**< SCIP data structure */
5618  SCIP_CONS** conss, /**< constraints */
5619  int nconss, /**< number of constraints */
5620  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
5621  SCIP_Bool* solviolbounds, /**< buffer to store whether quadratic variables in solution are outside their bounds by more than feastol in some constraint */
5622  SCIP_CONS** maxviolcon /**< buffer to store constraint with largest violation, or NULL if solution is feasible */
5623  )
5624 {
5625  SCIP_CONSDATA* consdata;
5626  SCIP_Real viol;
5627  SCIP_Real maxviol;
5628  SCIP_Bool solviolbounds1;
5629  int c;
5630 
5631  assert(scip != NULL);
5632  assert(conss != NULL || nconss == 0);
5633  assert(solviolbounds != NULL);
5634  assert(maxviolcon != NULL);
5635 
5636  *solviolbounds = FALSE;
5637  *maxviolcon = NULL;
5638 
5639  maxviol = 0.0;
5640 
5641  for( c = 0; c < nconss; ++c )
5642  {
5643  assert(conss != NULL);
5644  assert(conss[c] != NULL);
5645 
5646  SCIP_CALL( computeViolation(scip, conss[c], sol, &solviolbounds1) );
5647  *solviolbounds |= solviolbounds1;
5648 
5649  consdata = SCIPconsGetData(conss[c]);
5650  assert(consdata != NULL);
5651 
5652  viol = MAX(consdata->lhsviol, consdata->rhsviol);
5653  if( viol > maxviol && SCIPisGT(scip, viol, SCIPfeastol(scip)) )
5654  {
5655  maxviol = viol;
5656  *maxviolcon = conss[c];
5657  }
5658  }
5659 
5660  return SCIP_OKAY;
5661 }
5662 
5663 
5664 /** index comparison method for bilinear terms */
5665 static
5666 SCIP_DECL_SORTINDCOMP(bilinTermComp2)
5667 { /*lint --e{715}*/
5668  SCIP_BILINTERM* bilinterms = (SCIP_BILINTERM*)dataptr;
5669  int var1cmp;
5670 
5671  assert(bilinterms != NULL);
5672 
5673  var1cmp = SCIPvarCompare(bilinterms[ind1].var1, bilinterms[ind2].var1);
5674  if( var1cmp != 0 )
5675  return var1cmp;
5676 
5677  return SCIPvarCompare(bilinterms[ind1].var2, bilinterms[ind2].var2);
5678 }
5679 
5680 /** volume comparison method for bilinear terms; prioritizes bilinear products with a larger volume */
5681 static
5682 SCIP_DECL_SORTINDCOMP(bilinTermCompVolume)
5683 { /*lint --e{715}*/
5684  SCIP_BILINTERM* bilinterms = (SCIP_BILINTERM*)dataptr;
5685  SCIP_Real vol1;
5686  SCIP_Real vol2;
5687 
5688  assert(bilinterms != NULL);
5689 
5690  vol1 = (SCIPvarGetUbLocal(bilinterms[ind1].var1) - SCIPvarGetLbLocal(bilinterms[ind1].var1))
5691  * (SCIPvarGetUbLocal(bilinterms[ind1].var2) - SCIPvarGetLbLocal(bilinterms[ind1].var2));
5692  vol2 = (SCIPvarGetUbLocal(bilinterms[ind2].var1) - SCIPvarGetLbLocal(bilinterms[ind2].var1))
5693  * (SCIPvarGetUbLocal(bilinterms[ind2].var2) - SCIPvarGetLbLocal(bilinterms[ind2].var2));
5694 
5695  if( vol1 > vol2 )
5696  return -1;
5697  else if( vol1 < vol2 )
5698  return 1;
5699  return bilinTermComp2(dataptr, ind1, ind2);
5700 }
5701 
5702 /** helper function to sort all bilinear terms in the constraint handler data */
5703 static
5705  SCIP* scip, /**< SCIP data structure */
5706  SCIP_BILINTERM* bilinterms, /**< array containing all bilinear terms */
5707  int nbilinterms, /**< total number of bilinear terms */
5708  SCIP_CONS** bilinconss, /**< array for mapping each term to its constraint */
5709  int* bilinposs /**< array for mapping each term to its position in the corresponding
5710  * bilinconss constraint */
5711  )
5712 {
5713  int* perm;
5714  int i;
5715  int nexti;
5716  int v;
5717  SCIP_BILINTERM bilinterm;
5718  SCIP_CONS* bilincons;
5719  int bilinpos;
5720 
5721  assert(scip != NULL);
5722  assert(bilinterms != NULL);
5723  assert(nbilinterms > 0);
5724  assert(bilinconss != NULL);
5725  assert(bilinposs != NULL);
5726 
5727  /* get temporary memory to store the sorted permutation and the inverse permutation */
5728  SCIP_CALL( SCIPallocBufferArray(scip, &perm, nbilinterms) );
5729 
5730  /* call quicksort */
5731  SCIPsort(perm, bilinTermCompVolume, (void*)bilinterms, nbilinterms);
5732 
5733  /* permute the bilinear terms according to the resulting permutation */
5734  for( v = 0; v < nbilinterms; ++v )
5735  {
5736  if( perm[v] != v )
5737  {
5738  bilinterm = bilinterms[v];
5739  bilincons = bilinconss[v];
5740  bilinpos = bilinposs[v];
5741 
5742  i = v;
5743  do
5744  {
5745  assert(0 <= perm[i] && perm[i] < nbilinterms);
5746  assert(perm[i] != i);
5747 
5748  bilinterms[i] = bilinterms[perm[i]];
5749  bilinconss[i] = bilinconss[perm[i]];
5750  bilinposs[i] = bilinposs[perm[i]];
5751 
5752  nexti = perm[i];
5753  perm[i] = i;
5754  i = nexti;
5755  }
5756  while( perm[i] != v );
5757  bilinterms[i] = bilinterm;
5758  bilinconss[i] = bilincons;
5759  bilinposs[i] = bilinpos;
5760  perm[i] = i;
5761  }
5762  }
5763 
5764  /* free temporary memory */
5765  SCIPfreeBufferArray(scip, &perm);
5766 
5767  return SCIP_OKAY;
5768 }
5769 
5770 /** stores all bilinear terms in the quadratic constraint handler data; in addition, for each bilinear term we store
5771  * the number of nonconvex constraints that require to over- or underestimate this term, which only depends on the
5772  * lhs, rhs, and the bilinear coefficient
5773  */
5774 static
5776  SCIP* scip, /**< SCIP data structure */
5777  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5778  SCIP_CONS** conss, /**< constraints to process */
5779  int nconss /**< number of constraints */
5780  )
5781 {
5782  SCIP_BILINTERM* bilinterms;
5783  SCIP_CONS** bilincons;
5784  int* bilinpos;
5785  int nbilinterms;
5786  int pos;
5787  int c;
5788  int i;
5789 
5790  assert(scip != NULL);
5791  assert(conshdlrdata != NULL);
5792  assert(conss != NULL);
5793 
5794  /* check for all cases for which we don't want to spend time for collecting all bilinear terms */
5795  if( nconss == 0 || conshdlrdata->storedbilinearterms || SCIPgetSubscipDepth(scip) != 0 || SCIPgetDepth(scip) >= 1
5796  || SCIPinProbing(scip) || SCIPinDive(scip) )
5797  return SCIP_OKAY;
5798 
5799  assert(conshdlrdata->bilinestimators == NULL);
5800  assert(conshdlrdata->nbilinterms == 0);
5801 
5802  conshdlrdata->storedbilinearterms = TRUE;
5803  nbilinterms = 0;
5804 
5805  /* count the number of bilinear terms (including duplicates) */
5806  for( c = 0; c < nconss; ++c )
5807  {
5808  SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]);
5809  assert(consdata != NULL);
5810  nbilinterms += consdata->nbilinterms;
5811  }
5812 
5813  /* no bilinear terms available -> stop */
5814  if( nbilinterms == 0 )
5815  return SCIP_OKAY;
5816 
5817  /* allocate temporary memory for sorting all bilinear terms (including duplicates) */
5818  SCIP_CALL( SCIPallocBufferArray(scip, &bilinterms, nbilinterms) );
5819  SCIP_CALL( SCIPallocBufferArray(scip, &bilincons, nbilinterms) );
5820  SCIP_CALL( SCIPallocBufferArray(scip, &bilinpos, nbilinterms) );
5821 
5822  /* copy all bilinear terms; note that we need separate entries for x*y and y*x */
5823  pos = 0;
5824  for( c = 0; c < nconss; ++c )
5825  {
5826  SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]);
5827 
5828  /* allocate memory to store the later computed indices of each bilinear term in the bilinterms array of the
5829  * constraint handler data
5830  */
5831  if( consdata->nbilinterms > 0 )
5832  {
5833  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->bilintermsidx, consdata->nbilinterms) );
5834  }
5835 
5836  for( i = 0; i < consdata->nbilinterms; ++i )
5837  {
5838  assert(consdata->bilinterms != NULL);
5839  assert(consdata->bilinterms[i].var1 != consdata->bilinterms[i].var2);
5840 
5841  /* add xy */
5842  bilinterms[pos] = consdata->bilinterms[i];
5843  bilincons[pos] = conss[c];
5844  bilinpos[pos] = i;
5845  ++pos;
5846 
5847  /* invalidate bilinear term index */
5848  assert(consdata->bilintermsidx != NULL);
5849  consdata->bilintermsidx[i] = -1;
5850  }
5851  }
5852  assert(pos == nbilinterms);
5853 
5854  /* sorts all bilinear terms (including duplicates) */
5855  SCIP_CALL( sortAllBilinTerms(scip, bilinterms, nbilinterms, bilincons, bilinpos) );
5856 
5857  /* count the number of bilinear terms without duplicates */
5858  conshdlrdata->nbilinterms = nbilinterms;
5859  for( i = 0; i < nbilinterms - 1; ++i )
5860  {
5861  assert(bilinTermCompVolume((void*)bilinterms, i, i+1) != 0 || bilinTermComp2((void*)bilinterms, i, i+1) <= 0);
5862 
5863  if( bilinTermComp2((void*)bilinterms, i, i+1) == 0 )
5864  --(conshdlrdata->nbilinterms);
5865  }
5866  assert(conshdlrdata->nbilinterms <= nbilinterms && conshdlrdata->nbilinterms > 0);
5867 
5868  /* store all information for each bilinear term into the constraint handler data */
5869  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bilinestimators, conshdlrdata->nbilinterms) );
5870 
5871  /* filter duplicates and update entries in the corresponding constraint datas */
5872  pos = 0;
5873  for( i = 0; i < nbilinterms; ++i )
5874  {
5875  SCIP_CONSDATA* consdata = SCIPconsGetData(bilincons[i]);
5876  SCIP_VAR* x;
5877  SCIP_Bool haslhs = !SCIPisInfinity(scip, -consdata->lhs);
5878  SCIP_Bool hasrhs = !SCIPisInfinity(scip, consdata->rhs);
5879 
5880  assert(consdata != NULL);
5881  assert(bilinpos[i] >= 0 && bilinpos[i] < consdata->nbilinterms);
5882 
5883  /* check for a new bilinear term */
5884  if( i == 0 || bilinTermComp2((void*)bilinterms, i-1, i) != 0 )
5885  {
5886  conshdlrdata->bilinestimators[pos].x = bilinterms[i].var1;
5887  conshdlrdata->bilinestimators[pos].y = bilinterms[i].var2;
5888  conshdlrdata->bilinestimators[pos].lastimprfac = 0.0;
5889  conshdlrdata->bilinestimators[pos].maxnonconvexity = 0.0;
5890  ++pos;
5891  }
5892 
5893  /* store whether under- or overestimation is needed for each bilinear term; note that we do not consider convex
5894  * constraints because they will not be used in separated generateCutNonConvex(), which is the only function that
5895  * uses a term-wise relaxation
5896  */
5897  if( SCIPisPositive(scip, bilinterms[i].coef) )
5898  {
5899  conshdlrdata->bilinestimators[pos-1].nunderest += (hasrhs && !consdata->isconvex) ? 1 : 0;
5900  conshdlrdata->bilinestimators[pos-1].noverest += (haslhs && !consdata->isconcave) ? 1 : 0;
5901  conshdlrdata->bilinestimators[pos-1].maxnonconvexity = MAX(conshdlrdata->bilinestimators[pos-1].maxnonconvexity, consdata->maxnonconvexity);
5902  }
5903  else
5904  {
5905  assert(SCIPisNegative(scip, bilinterms[i].coef));
5906  conshdlrdata->bilinestimators[pos-1].nunderest += (haslhs && !consdata->isconcave) ? 1 : 0;
5907  conshdlrdata->bilinestimators[pos-1].noverest += (hasrhs && !consdata->isconvex) ? 1 : 0;
5908  conshdlrdata->bilinestimators[pos-1].maxnonconvexity = MAX(conshdlrdata->bilinestimators[pos-1].maxnonconvexity, consdata->maxnonconvexity);
5909  }
5910 
5911  /* update index of bilinear term in the constraint data */
5912  x = consdata->bilinterms[bilinpos[i]].var1;
5913 
5914  assert(pos > 0);
5915  if( x == conshdlrdata->bilinestimators[pos-1].x )
5916  {
5917  assert(consdata->bilinterms[bilinpos[i]].var2 == conshdlrdata->bilinestimators[pos-1].y);
5918  consdata->bilintermsidx[bilinpos[i]] = pos-1;
5919  }
5920  }
5921  assert(pos == conshdlrdata->nbilinterms);
5922 
5923 #ifndef NDEBUG
5924  /* check whether
5925  * - all bilintermsidx entries have been set
5926  * - variables in bilinear terms of each constraint data and the constraint handler data match
5927  */
5928  for( c = 0; c < nconss; ++c )
5929  {
5930  SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]);
5931  assert(consdata != NULL);
5932 
5933  for( i = 0; i < consdata->nbilinterms; ++i )
5934  {
5935  SCIP_VAR* x = consdata->bilinterms[i].var1;
5936  SCIP_VAR* y = consdata->bilinterms[i].var2;
5937  int idx = consdata->bilintermsidx[i];
5938 
5939  assert(idx >= 0 && idx < conshdlrdata->nbilinterms);
5940  assert(x == conshdlrdata->bilinestimators[idx].x);
5941  assert(y == conshdlrdata->bilinestimators[idx].y);
5942 
5943  /* at least one direction is important if the constraint is not convex */
5944  if( !SCIPisInfinity(scip, consdata->rhs) && !consdata->isconvex )
5945  assert(conshdlrdata->bilinestimators[idx].nunderest + conshdlrdata->bilinestimators[idx].noverest > 0);
5946  if( !SCIPisInfinity(scip, -consdata->lhs) && !consdata->isconcave )
5947  assert(conshdlrdata->bilinestimators[idx].nunderest + conshdlrdata->bilinestimators[idx].noverest > 0);
5948  }
5949  }
5950 #endif
5951 
5952  /* free memory */
5953  SCIPfreeBufferArray(scip, &bilinpos);
5954  SCIPfreeBufferArray(scip, &bilincons);
5955  SCIPfreeBufferArray(scip, &bilinterms);
5956 
5957  return SCIP_OKAY;
5958 }
5959 
5960 /** frees memory allocated in storeAllBilinearTerms() */
5961 static
5963  SCIP* scip, /**< SCIP data structure */
5964  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5965  SCIP_CONS** conss, /**< constraints to process */
5966  int nconss /**< number of constraints */
5967 
5968  )
5969 {
5970  int c;
5971 
5972  assert(conshdlrdata != NULL);
5973 
5974  for( c = 0; c < nconss; ++c )
5975  {
5976  SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
5977  assert(consdata != NULL);
5978 
5979  SCIPfreeBlockMemoryArrayNull(scip, &consdata->bilintermsidx, consdata->nbilinterms);
5980  }
5981 
5982  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bilinestimators, conshdlrdata->nbilinterms);
5983 
5984  conshdlrdata->nbilinterms = 0;
5985  conshdlrdata->storedbilinearterms = FALSE;
5986 
5987  return SCIP_OKAY;
5988 }
5989 
5990 /** tries to compute cut for multleft * <coefleft, x'> * multright <= rhs / (multright * <coefright, x'>) where x'=(x,1) */
5991 static
5993  SCIP* scip, /**< SCIP data structure */
5994  SCIP_CONS* cons, /**< constraint */
5995  SCIP_Real* ref, /**< reference solution where to generate the cut */
5996  SCIP_Real multleft, /**< multiplicator on lhs */
5997  SCIP_Real* coefleft, /**< coefficient for factor on lhs */
5998  SCIP_Real multright, /**< multiplicator on both sides */
5999  SCIP_Real* coefright, /**< coefficient for factor that goes to rhs */
6000  SCIP_Real rightminactivity, /**< minimal activity of <coefright, x> */
6001  SCIP_Real rightmaxactivity, /**< maximal activity of <coefright, x> */
6002  SCIP_Real rhs, /**< denominator on rhs */
6003  SCIP_ROWPREP* rowprep, /**< rowprep to store cut coefs and constant */
6004  SCIP_Bool* success /**< buffer to indicate whether a cut was successfully computed */
6005  )
6006 {
6007  SCIP_CONSDATA* consdata;
6008  SCIP_Real constant;
6009  SCIP_Real coef;
6010  int i;
6011 
6012  assert(rowprep != NULL);
6013  assert(rightminactivity * multright > 0.0);
6014  assert(rightmaxactivity * multright > 0.0);
6015  assert(multright == 1.0 || multright == -1.0);
6016 
6017  consdata = SCIPconsGetData(cons);
6018  assert(consdata != NULL);
6019 
6020  rowprep->sidetype = SCIP_SIDETYPE_RIGHT;
6021 
6022  if( rhs > 0.0 )
6023  {
6024  /* if rhs > 0.0, then rhs / (multright * <coefright, x'>) is convex, thus need secant:
6025  * 1 / multright*<coefright, x'> <= 1/minact + 1/maxact - 1/(minact * maxact) multright*<coefright, x'>
6026  * where [minact, maxact] = multright * [rightminactivity, rightmaxactivity]
6027  *
6028  * assuming multright is either -1 or 1, and substituting gives
6029  * multright/rightminactivity + multright/rightmaxactivity - multright/(rightminactivity * rightmaxactivity) *<coefright, x'>
6030  *
6031  * multiplying by rhs, gives the estimate
6032  * rhs / (multright * <coefright, x'>) <= rhs * multright * (1/rightminactivity + 1/rightmaxactivity - 1/(rightminactivity * rightmaxactivity) * <coefright, x'>)
6033  */
6034 
6035  /* cannot do if unbounded */
6036  if( SCIPisInfinity(scip, rightmaxactivity * multright) )
6037  {
6038  *success = FALSE;
6039  return SCIP_OKAY;
6040  }
6041 
6042  assert(SCIPisFeasLE(scip, rightminactivity, rightmaxactivity));
6043 
6044  constant = multleft * multright * coefleft[consdata->nquadvars];
6045  constant -= rhs * multright * (1.0 / rightminactivity + 1.0 / rightmaxactivity);
6046  constant += rhs * multright * coefright[consdata->nquadvars] / (rightminactivity * rightmaxactivity);
6047 
6048  SCIPaddRowprepConstant(rowprep, constant);
6049 
6050  for( i = 0; i < consdata->nquadvars; ++i )
6051  {
6052  coef = multleft * multright * coefleft[i];
6053  coef += rhs * multright / (rightminactivity * rightmaxactivity) * coefright[i];
6054  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, consdata->quadvarterms[i].var, coef) );
6055  }
6056 
6057  (void) SCIPsnprintf(rowprep->name, SCIP_MAXSTRLEN, "%s_factorablesecant_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
6058 
6059  rowprep->local = TRUE;
6060  }
6061  else
6062  {
6063  SCIP_Real refvalue;
6064 
6065  /* if rhs < 0.0, then rhs / (multright * <coefright, x'>) is convex, thus need linearization:
6066  * rhs / (multright * <coefright, x'>)
6067  * <= rhs / (multright * <coefright, ref'>) - rhs / (multright * <coefright, ref'>)^2 * (multright * <coefright, x'> - multright * <coefright, ref'>)
6068  * = 2*rhs / (multright * <coefright, ref'>) - rhs / (multright * <coefright, ref'>)^2 * (multright * <coefright, x'>)
6069  *
6070  * where ref' = (ref, 1)
6071  */
6072 
6073  /* compute <coefright, ref'> */
6074  refvalue = coefright[consdata->nquadvars];
6075  for( i = 0; i < consdata->nquadvars; ++i )
6076  refvalue += coefright[i] * ref[i];
6077 
6078  /* should not happen, since we checked activity of <coefright,x> before, and assume ref within bounds */
6079  assert(!SCIPisZero(scip, refvalue));
6080 
6081  constant = multleft * multright * coefleft[consdata->nquadvars];
6082  constant -= 2.0 * rhs / (multright * refvalue);
6083  constant += rhs / (refvalue * refvalue) * multright * coefright[consdata->nquadvars];
6084 
6085  SCIPaddRowprepConstant(rowprep, constant);
6086 
6087  for( i = 0; i < consdata->nquadvars; ++i )
6088  {
6089  coef = multleft * multright * coefleft[i];
6090  coef += rhs / (refvalue * refvalue) * multright * coefright[i];
6091  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, consdata->quadvarterms[i].var, coef) );
6092  }
6093 
6094  (void) SCIPsnprintf(rowprep->name, SCIP_MAXSTRLEN, "%s_factorablelinearization_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
6095  }
6096 
6097  *success = TRUE;
6098 
6099  return SCIP_OKAY;
6100 }
6101 
6102 /** tries to generate a cut if constraint quadratic function is factorable and there are no linear variables
6103  * (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
6104  */
6105 static
6107  SCIP* scip, /**< SCIP data structure */
6108  SCIP_CONS* cons, /**< constraint */
6109  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
6110  SCIP_Real* ref, /**< reference solution where to generate the cut */
6111  SCIP_ROWPREP* rowprep, /**< data structure to store cut coefficients */
6112  SCIP_Bool* success /**< buffer to indicate whether a cut was successfully computed */
6113  )
6114 {
6115  SCIP_CONSDATA* consdata;
6116  SCIP_Real leftminactivity;
6117  SCIP_Real leftmaxactivity;
6118  SCIP_Real rightminactivity;
6119  SCIP_Real rightmaxactivity;
6120  SCIP_Real leftminactivityglobal;
6121  SCIP_Real leftmaxactivityglobal;
6122  SCIP_Real rightminactivityglobal;
6123  SCIP_Real rightmaxactivityglobal;
6124  SCIP_Real multleft;
6125  SCIP_Real multright;
6126  SCIP_Real rhs;
6127  int i;
6128 
6129  assert(scip != NULL);
6130  assert(cons != NULL);
6131  assert(ref != NULL);
6132  assert(rowprep != NULL);
6133  assert(success != NULL);
6134 
6135  consdata = SCIPconsGetData(cons);
6136  assert(consdata != NULL);
6137  assert(consdata->nlinvars == 0);
6138  assert(consdata->factorleft != NULL);
6139  assert(consdata->factorright != NULL);
6140 
6141  *success = FALSE;
6142 
6143  leftminactivityglobal = leftminactivity = consdata->factorleft[consdata->nquadvars];
6144  leftmaxactivityglobal = leftmaxactivity = consdata->factorleft[consdata->nquadvars];
6145  rightminactivityglobal = rightminactivity = consdata->factorright[consdata->nquadvars];
6146  rightmaxactivityglobal = rightmaxactivity = consdata->factorright[consdata->nquadvars];
6147  for( i = 0; i < consdata->nquadvars; ++i )
6148  {
6149  if( !SCIPisInfinity(scip, -leftminactivity) )
6150  {
6151  if( consdata->factorleft[i] > 0.0 )
6152  {
6153  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6154  leftminactivity = -SCIPinfinity(scip);
6155  else
6156  leftminactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6157  }
6158  else if( consdata->factorleft[i] < 0.0 )
6159  {
6160  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6161  leftminactivity = -SCIPinfinity(scip);
6162  else
6163  leftminactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6164  }
6165  }
6166  if( !SCIPisInfinity(scip, leftmaxactivity) )
6167  {
6168  if( consdata->factorleft[i] > 0.0 )
6169  {
6170  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6171  leftmaxactivity = SCIPinfinity(scip);
6172  else
6173  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6174  }
6175  else if( consdata->factorleft[i] < 0.0 )
6176  {
6177  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6178  leftmaxactivity = SCIPinfinity(scip);
6179  else
6180  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6181  }
6182  }
6183 
6184  if( !SCIPisInfinity(scip, -rightminactivity) )
6185  {
6186  if( consdata->factorright[i] > 0.0 )
6187  {
6188  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6189  rightminactivity = -SCIPinfinity(scip);
6190  else
6191  rightminactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6192  }
6193  else if( consdata->factorright[i] < 0.0 )
6194  {
6195  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6196  rightminactivity = -SCIPinfinity(scip);
6197  else
6198  rightminactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6199  }
6200  }
6201  if( !SCIPisInfinity(scip, rightmaxactivity) )
6202  {
6203  if( consdata->factorright[i] > 0.0 )
6204  {
6205  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6206  rightmaxactivity = SCIPinfinity(scip);
6207  else
6208  rightmaxactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6209  }
6210  else if( consdata->factorright[i] < 0.0 )
6211  {
6212  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6213  rightmaxactivity = SCIPinfinity(scip);
6214  else
6215  rightmaxactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6216  }
6217  }
6218 
6219  if( SCIPgetDepth(scip) > 0 )
6220  {
6221  if( !SCIPisInfinity(scip, -leftminactivityglobal) )
6222  {
6223  if( consdata->factorleft[i] > 0.0 )
6224  {
6225  if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(consdata->quadvarterms[i].var)) )
6226  leftminactivityglobal = -SCIPinfinity(scip);
6227  else
6228  leftminactivityglobal += consdata->factorleft[i] * SCIPvarGetLbGlobal(consdata->quadvarterms[i].var);
6229  }
6230  else if( consdata->factorleft[i] < 0.0 )
6231  {
6232  if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(consdata->quadvarterms[i].var)) )
6233  leftminactivityglobal = -SCIPinfinity(scip);
6234  else
6235  leftminactivityglobal += consdata->factorleft[i] * SCIPvarGetUbGlobal(consdata->quadvarterms[i].var);
6236  }
6237  }
6238  if( !SCIPisInfinity(scip, leftmaxactivityglobal) )
6239  {
6240  if( consdata->factorleft[i] > 0.0 )
6241  {
6242  if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(consdata->quadvarterms[i].var)) )
6243  leftmaxactivityglobal = SCIPinfinity(scip);
6244  else
6245  leftmaxactivityglobal += consdata->factorleft[i] * SCIPvarGetUbGlobal(consdata->quadvarterms[i].var);
6246  }
6247  else if( consdata->factorleft[i] < 0.0 )
6248  {
6249  if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(consdata->quadvarterms[i].var)) )
6250  leftmaxactivityglobal = SCIPinfinity(scip);
6251  else
6252  leftmaxactivityglobal += consdata->factorleft[i] * SCIPvarGetLbGlobal(consdata->quadvarterms[i].var);
6253  }
6254  }
6255 
6256  if( !SCIPisInfinity(scip, -rightminactivityglobal) )
6257  {
6258  if( consdata->factorright[i] > 0.0 )
6259  {
6260  if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(consdata->quadvarterms[i].var)) )
6261  rightminactivityglobal = -SCIPinfinity(scip);
6262  else
6263  rightminactivityglobal += consdata->factorright[i] * SCIPvarGetLbGlobal(consdata->quadvarterms[i].var);
6264  }
6265  else if( consdata->factorright[i] < 0.0 )
6266  {
6267  if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(consdata->quadvarterms[i].var)) )
6268  rightminactivityglobal = -SCIPinfinity(scip);
6269  else
6270  rightminactivityglobal += consdata->factorright[i] * SCIPvarGetUbGlobal(consdata->quadvarterms[i].var);
6271  }
6272  }
6273  if( !SCIPisInfinity(scip, rightmaxactivityglobal) )
6274  {
6275  if( consdata->factorright[i] > 0.0 )
6276  {
6277  if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(consdata->quadvarterms[i].var)) )
6278  rightmaxactivityglobal = SCIPinfinity(scip);
6279  else
6280  rightmaxactivityglobal += consdata->factorright[i] * SCIPvarGetUbGlobal(consdata->quadvarterms[i].var);
6281  }
6282  else if( consdata->factorright[i] < 0.0 )
6283  {
6284  if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(consdata->quadvarterms[i].var)) )
6285  rightmaxactivityglobal = SCIPinfinity(scip);
6286  else
6287  rightmaxactivityglobal += consdata->factorright[i] * SCIPvarGetLbGlobal(consdata->quadvarterms[i].var);
6288  }
6289  }
6290  }
6291  }
6292 
6293  /* write violated constraints as multleft * factorleft * factorright <= rhs */
6294  if( violside == SCIP_SIDETYPE_RIGHT )
6295  {
6296  rhs = consdata->rhs;
6297  multleft = 1.0;
6298  }
6299  else
6300  {
6301  rhs = -consdata->lhs;
6302  multleft = -1.0;
6303  }
6304 
6305  if( SCIPisZero(scip, rhs) )
6306  {
6307  /* @todo do something for rhs == 0.0? */
6308  return SCIP_OKAY;
6309  }
6310 
6311  if( !SCIPisFeasPositive(scip, leftminactivity) && !SCIPisFeasNegative(scip, leftmaxactivity) )
6312  {
6313  /* left factor has 0 within activity bounds, or is very close, at least */
6314  if( !SCIPisFeasPositive(scip, rightminactivity) && !SCIPisFeasNegative(scip, rightmaxactivity) )
6315  {
6316  /* right factor also has 0 within activity bounds, or is very close, at least
6317  * -> cannot separate
6318  */
6319  return SCIP_OKAY;
6320  }
6321 
6322  /* write violated constraint as multleft * factorleft * multright * (multright * factorright) <= rhs
6323  * such that multright * factorright > 0.0
6324  */
6325  if( rightminactivity < 0.0 )
6326  multright = -1.0;
6327  else
6328  multright = 1.0;
6329 
6330  /* generate cut for multleft * factorleft * multright <= rhs / (factorright * multright) */
6331  SCIP_CALL( generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorleft, multright, consdata->factorright, rightminactivity, rightmaxactivity, rhs, rowprep, success) );
6332 
6333  /* if right factor has 0 within global activity bounds, then the added linearization is not globally valid */
6334  if( rhs < 0.0 && SCIPgetDepth(scip) > 0 && rightminactivityglobal < 0.0 && rightmaxactivityglobal > 0.0 )
6335  rowprep->local = TRUE;
6336  }
6337  else if( !SCIPisFeasPositive(scip, rightminactivity) && !SCIPisFeasNegative(scip, rightmaxactivity) )
6338  {
6339  /* left factor is bounded away from 0
6340  * right factor has 0 within activity bounds, or is very close, at least
6341  * -> so divide by left factor
6342  */
6343 
6344  /* write violated constraint as multleft * factorright * multright * (multright * factorleft) <= rhs
6345  * such that multright * factorleft > 0.0
6346  */
6347  if( leftminactivity < 0.0 )
6348  multright = -1.0;
6349  else
6350  multright = 1.0;
6351 
6352  /* generate cut for multleft * factorright * multright <= rhs / (factorleft * multright) */
6353  SCIP_CALL( generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorright, multright, consdata->factorleft, leftminactivity, leftmaxactivity, rhs, rowprep, success) );
6354 
6355  /* if left factor has 0 within global activity bounds, then the added linearization is not globally valid */
6356  if( rhs < 0.0 && SCIPgetDepth(scip) > 0 && leftminactivityglobal < 0.0 && leftmaxactivityglobal > 0.0 )
6357  rowprep->local = TRUE;
6358  }
6359  else if( SCIPisInfinity(scip, -leftminactivity) || SCIPisInfinity(scip, leftmaxactivity) ||
6360  (!SCIPisInfinity(scip, -rightminactivity) && !SCIPisInfinity(scip, rightmaxactivity) && rightmaxactivity - rightminactivity < leftmaxactivity - leftminactivity) )
6361  {
6362  /* both factors are bounded away from 0, but the right one has a smaller activity range, so divide by that one */
6363 
6364  /* write violated constraint as multleft * factorleft * multright * (multright * factorright) <= rhs
6365  * such that multright * factorright > 0.0
6366  */
6367  if( rightminactivity < 0.0 )
6368  multright = -1.0;
6369  else
6370  multright = 1.0;
6371 
6372  /* generate cut for multleft * factorleft * multright <= rhs / (factorright * multright) */
6373  SCIP_CALL( generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorleft, multright, consdata->factorright, rightminactivity, rightmaxactivity, rhs, rowprep, success) );
6374 
6375  /* if right factor has 0 within global activity bounds, then the added linearization is not globally valid */
6376  if( rhs < 0.0 && SCIPgetDepth(scip) > 0 && rightminactivityglobal < 0.0 && rightmaxactivityglobal > 0.0 )
6377  rowprep->local = TRUE;
6378  }
6379  else
6380  {
6381  /* both factors are bounded away from 0, but the left one has a smaller activity range, so divide by that one */
6382 
6383  /* write violated constraint as multleft * factorright * multright * (multright * factorleft) <= rhs
6384  * such that multright * factorleft > 0.0
6385  */
6386  if( leftminactivity < 0.0 )
6387  multright = -1.0;
6388  else
6389  multright = 1.0;
6390 
6391  /* generate cut for multleft * factorright * multright <= rhs / (factorleft * multright) */
6392  SCIP_CALL( generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorright, multright, consdata->factorleft, leftminactivity, leftmaxactivity, rhs, rowprep, success) );
6393 
6394  /* if left factor has 0 within global activity bounds, then the added linearization is not globally valid */
6395  if( rhs < 0.0 && SCIPgetDepth(scip) > 0 && leftminactivityglobal < 0.0 && leftmaxactivityglobal > 0.0 )
6396  rowprep->local = TRUE;
6397  }
6398 
6399  return SCIP_OKAY;
6400 }
6401 
6402 /* finds intersections of a parametric line (x,y) = (x0,y0) + t [(x1,y1) - (x0,y0)] on curves x*y = wl and x*y = wu;
6403  * returns TRUE if unsuccessful and FALSE otherwise
6404  */
6405 static
6407  SCIP* scip,
6408  SCIP_Real x0,
6409  SCIP_Real y0_,
6410  SCIP_Real x1,
6411  SCIP_Real y1_,
6412  SCIP_Real wl,
6413  SCIP_Real wu,
6414  SCIP_Real* xl,
6415  SCIP_Real* yl,
6416  SCIP_Real* xu,
6417  SCIP_Real* yu
6418  )
6419 {
6420  SCIP_Real a;
6421  SCIP_Real b;
6422  SCIP_Real c;
6423  SCIP_Real tl;
6424  SCIP_Real tu;
6425 
6426  assert(wl == SCIP_INVALID || (xl != NULL && yl != NULL)); /*lint !e777 */
6427  assert(wu == SCIP_INVALID || (xu != NULL && yu != NULL)); /*lint !e777 */
6428 
6429  /* The parametric line is of the form
6430  *
6431  * x = x0 + t (x1-x0)
6432  * y = y0 + t (y1-y0)
6433  *
6434  * and for that to satisfy xy = wl and xy = wu we must have
6435  *
6436  * x0 y0 + t [x0 (y1-y0) + y0 (x1-x0)] + t^2 (x1-x0) (y1-y0) = wl
6437  * = wu
6438  *
6439  * or a t^2 + b t + c - wl = 0 for proper values of a,b,c.
6440  * a t^2 + b t + c - wu = 0
6441  *
6442  * Because of the way this procedure will be used, one of the two
6443  * solutions found we must always use the minimum nonnegative one
6444  */
6445 
6446  a = (x1 - x0) * (y1_ - y0_);
6447  c = x0 * y0_;
6448  b = x0 * y1_ + y0_ * x1 - 2.0 * c;
6449 
6450  tl = 0.0;
6451  tu = 0.0;
6452 
6453  if( !SCIPisZero(scip, (SCIP_Real)a) )
6454  {
6455  if( wl != SCIP_INVALID ) /*lint !e777 */
6456  {
6457  SCIP_Real tl1;
6458  SCIP_Real tl2;
6459  SCIP_Real denom;
6460  SCIP_Real q;
6461 
6462  if( b * b - 4.0 * a * (c - wl) < 0.0 )
6463  {
6464  SCIPdebugMsg(scip, "probable numerical difficulties, give up\n");
6465  return TRUE;
6466  }
6467 
6468  denom = sqrt(b * b - 4.0 * a * (c - wl));
6469  q = -0.5 * (b + COPYSIGN(denom, b));
6470  tl1 = q / a;
6471  tl2 = (c - wl) / q;
6472 
6473  /* choose the smallest non-negative root */
6474  tl = (tl1 >= 0.0 && (tl2 < 0.0 || tl1 < tl2)) ? tl1 : tl2;
6475  }
6476 
6477  if( wu != SCIP_INVALID ) /*lint !e777 */
6478  {
6479  SCIP_Real tu1;
6480  SCIP_Real tu2;
6481  SCIP_Real denom;
6482  SCIP_Real q;
6483 
6484  if( b * b - 4.0 * a * (c - wu) < 0.0 )
6485  {
6486  SCIPdebugMsg(scip, "probable numerical difficulties, give up\n");
6487  return TRUE;
6488  }
6489 
6490  denom = sqrt(b * b - 4.0 * a * (c - wu));
6491  q = -0.5 * (b + COPYSIGN(denom, b));
6492  tu1 = q / a;
6493  tu2 = (c - wu) / q;
6494 
6495  /* choose the smallest non-negative root */
6496  tu = (tu1 >= 0.0 && (tu2 < 0.0 || tu1 < tu2)) ? tu1 : tu2;
6497  }
6498  }
6499  else if( !SCIPisZero(scip, (SCIP_Real)b) )
6500  {
6501  if( wl != SCIP_INVALID ) /*lint !e777 */
6502  tl = (wl - c) / b;
6503  if( wu != SCIP_INVALID ) /*lint !e777 */
6504  tu = (wu - c) / b;
6505  }
6506  else
6507  {
6508  /* no or infinitely many solutions */
6509  return TRUE;
6510  }
6511 
6512  if( wl != SCIP_INVALID ) /*lint !e777 */
6513  {
6514  *xl = (SCIP_Real)(x0 + tl * (x1 - x0 ));
6515  *yl = (SCIP_Real)(y0_ + tl * (y1_ - y0_));
6516 
6517  if( !SCIPisRelEQ(scip, *xl * *yl, wl) )
6518  {
6519  SCIPdebugMsg(scip, "probable numerical difficulties, give up\n");
6520  return TRUE;
6521  }
6522  }
6523 
6524  if( wu != SCIP_INVALID ) /*lint !e777 */
6525  {
6526  *xu = (SCIP_Real)(x0 + tu * (x1 - x0));
6527  *yu = (SCIP_Real)(y0_ + tu * (y1_ - y0_));
6528 
6529  if( !SCIPisRelEQ(scip, *xu * *yu, wu) )
6530  {
6531  SCIPdebugMsg(scip, "probable numerical difficulties, give up\n");
6532  return TRUE;
6533  }
6534  }
6535 
6536  /* do not use the computed points if one of the components is infinite */
6537  if( (xu != NULL && SCIPisInfinity(scip, *xu)) || (xl != NULL && SCIPisInfinity(scip, -*xl)) ||
6538  (yu != NULL && SCIPisInfinity(scip, *yu)) || (yl != NULL && SCIPisInfinity(scip, -*yl)) )
6539  {
6540  SCIPdebugMsg(scip, "probable numerical difficulties, give up\n");
6541  return TRUE;
6542  }
6543 
6544  return FALSE;
6545 }
6546 
6547 /** generate coefficients for a plane through points (x1, y1_, x1*y1) and (x2, y2, x2*y2)
6548  * such that intersecting it with one of them (the first if whichuse is FALSE, the second otherwise)
6549  * gives a tangent to the curve x*y = k
6550  *
6551  * Returns TRUE on error and FALSE on success.
6552  */
6553 static
6555  SCIP* scip,
6556  SCIP_Real x1,
6557  SCIP_Real y1_,
6558  SCIP_Real x2,
6559  SCIP_Real y2,
6560  SCIP_Bool whichuse,
6561  SCIP_Real* cx,
6562  SCIP_Real* cy,
6563  SCIP_Real* cw
6564  )
6565 {
6566  SCIP_Real xd;
6567  SCIP_Real yd;
6568  SCIP_Real xo;
6569  SCIP_Real yo;
6570 
6571  assert(cx != NULL);
6572  assert(cy != NULL);
6573  assert(cw != NULL);
6574 
6575  /* the x-y slope of this constraint must be tangent to a curve x*y = k at (xD,yD) */
6576  if( !whichuse )
6577  {
6578  xd = x1;
6579  xo = x2;
6580  yd = y1_;
6581  yo = y2;
6582  }
6583  else
6584  {
6585  xd = x2;
6586  xo = x1;
6587  yd = y2;
6588  yo = y1_;
6589  }
6590 
6591  *cx = yd;
6592  *cy = xd;
6593 
6594  /* lift it so that it touches the other curve */
6595 
6596  /* if the two points are on the same curve, then no cut */
6597  if( SCIPisZero(scip, xo * yo - xd * yd) )
6598  return TRUE;
6599 
6600  /* should ALWAYS be negative */
6601  *cw = (2.0 * xd * yd - (*cx * xo + *cy * yo)) / (xo * yo - xd * yd);
6602 
6603  return FALSE;
6604 }
6605 
6606 /** computes coefficients of a lifted-tangent inequality for x*y = w
6607  *
6608  * The code is an adaptation of the methods in exprMul-upperHull.cpp in Couenne/stable/0.4 rev773,
6609  * written by P. Belotti and licensed under Eclipse Public License.
6610  */
6611 static
6613  SCIP* scip, /**< SCIP data structure */
6614  SCIP_Real xl, /**< lower bound on x */
6615  SCIP_Real xu, /**< upper bound on x */
6616  SCIP_Real x0, /**< reference point for x */
6617  SCIP_Real yl, /**< lower bound on y */
6618  SCIP_Real yu, /**< upper bound on y */
6619  SCIP_Real y0_, /**< reference point for y */
6620  SCIP_Real wl, /**< lower bound on w */
6621  SCIP_Real wu, /**< upper bound on w */
6622  SCIP_Real w0, /**< reference point for w */
6623  SCIP_Real* cx, /**< buffer where to store cut coefficient for x */
6624  SCIP_Real* cy, /**< buffer where to store cut coefficient for y */
6625  SCIP_Real* cw, /**< buffer where to store cut coefficient for w */
6626  SCIP_Real* c0, /**< buffer where to store cut left-hand-side */
6627  SCIP_Bool* success /**< buffer where to indicate whether cut coefficients were computed */
6628  )
6629 {
6630  SCIP_Bool flipx;
6631  SCIP_Bool flipy;
6632  SCIP_Bool flipw;
6633  SCIP_Real tmp;
6634  SCIP_Real xlow;
6635  SCIP_Real ylow;
6636  SCIP_Real xupp;
6637  SCIP_Real yupp;
6638  SCIP_Real c0x;
6639  SCIP_Real c0y;
6640  SCIP_Real c0w;
6641 
6642  assert(scip != NULL);
6643  assert(cx != NULL);
6644  assert(cy != NULL);
6645  assert(cw != NULL);
6646  assert(c0 != NULL);
6647  assert(success != NULL);
6648 
6649  *success = FALSE;
6650  *cx = 0.0;
6651  *cy = 0.0;
6652  *cw = 0.0;
6653  *c0 = 0.0;
6654 
6655  SCIPdebugMsg(scip, "entering points:\n");
6656  SCIPdebugMsg(scip, "x: %9g\t[%9g\t%9g]\n", x0, xl, xu);
6657  SCIPdebugMsg(scip, "y: %9g\t[%9g\t%9g]\n", y0_, yl, yu);
6658  SCIPdebugMsg(scip, "w: %9g\t[%9g\t%9g]\n", w0, wl, wu);
6659 
6660  /* generateCutLTI should have recognized these */
6661  assert(wl >= 0.0 || wu <= 0.0);
6662  assert(!SCIPisInfinity(scip, -wl));
6663  assert(!SCIPisInfinity(scip, wu));
6664 
6665  assert(SCIPisFeasGE(scip, x0, xl));
6666  assert(SCIPisFeasLE(scip, x0, xu));
6667  assert(SCIPisFeasGE(scip, y0_, yl));
6668  assert(SCIPisFeasLE(scip, y0_, yu));
6669 
6670  /* preliminary bound tightening */
6671  if( wl >= 0.0 )
6672  {
6673  if( xl >= 0.0 || yl >= 0.0 || SCIPisLT(scip, xl * yl, wl) )
6674  {
6675  xl = MAX(xl, 0.0);
6676  yl = MAX(yl, 0.0);
6677  }
6678  else if( xu <= 0.0 || yu <= 0.0 || SCIPisLT(scip, xu * yu, wl) )
6679  {
6680  xu = MIN(xu, 0.0);
6681  yu = MIN(yu, 0.0);
6682  }
6683  else
6684  {
6685  /* both variables have mixed sign (xl < 0 && xu > 0 && yl < 0 && yu > 0) and both xl*yl and xu*yu are feasible
6686  * cannot generate cut for this
6687  */
6688  return;
6689  }
6690  }
6691  else
6692  {
6693  if( xl >= 0.0 || yu <= 0.0 || SCIPisGT(scip, xl * yu, wu) )
6694  {
6695  xl = MAX(xl, 0.0);
6696  yu = MIN(yu, 0.0);
6697  }
6698  else if( xu <= 0.0 || yl >= 0.0 || SCIPisGT(scip, xu * yl, wu))
6699  {
6700  xu = MIN(xu, 0.0);
6701  yl = MAX(yl, 0.0);
6702  }
6703  else
6704  {
6705  /* both variables have mixed sign (xl < 0 && xu > 0 && yl < 0 && yu > 0) and both xl*yu and xu*yl are feasible
6706  * cannot generate cut for this
6707  */
6708  return;
6709  }
6710  }
6711 
6712  /* if x or y is fixed now or even infeasible, then do not think about a cut */
6713  if( SCIPisGE(scip, xl, xu) || SCIPisGE(scip, yl, yu) )
6714  return;
6715 
6716  /* reduce to positive orthant by flipping variables */
6717  if( xl < 0.0 )
6718  {
6719  flipx = TRUE;
6720  tmp = xu;
6721  xu = -xl;
6722  xl = -tmp;
6723  x0 = -x0;
6724  }
6725  else
6726  flipx = FALSE;
6727 
6728  if( yl < 0.0 )
6729  {
6730  flipy = TRUE;
6731  tmp = yu;
6732  yu = -yl;
6733  yl = -tmp;
6734  y0_ = -y0_;
6735  }
6736  else
6737  flipy = FALSE;
6738 
6739  if( flipx ^ flipy )
6740  {
6741  flipw = TRUE;
6742  tmp = wu;
6743  wu = -wl;
6744  wl = -tmp;
6745  w0 = -w0;
6746  }
6747  else
6748  flipw = FALSE;
6749 
6750  /* project refpoint into box not only for numerical reasons, but also due to preliminary bound tightening above */
6751  x0 = MIN(xu, MAX(x0, xl));
6752  y0_ = MIN(yu, MAX(y0_, yl));
6753  w0 = MIN(wu, MAX(w0, wl));
6754 
6755  SCIPdebugMsg(scip, "reduced points:\n");
6756  SCIPdebugMsg(scip, "x: %9g\t[%9g\t%9g]\n", x0, xl, xu);
6757  SCIPdebugMsg(scip, "y: %9g\t[%9g\t%9g]\n", y0_, yl, yu);
6758  SCIPdebugMsg(scip, "w: %9g\t[%9g\t%9g]\n", w0, wl, wu);
6759 
6760  if( SCIPisGE(scip, xl * yl, wl) && SCIPisLE(scip, xu * yu, wu) )
6761  {
6762  SCIPdebugMsg(scip, "box for x and y inside feasible region -> nothing to separate\n");
6763  return;
6764  }
6765  if( SCIPisGE(scip, x0 * y0_, w0) )
6766  {
6767  SCIPdebugMsg(scip, "point to separate not below curve -> cannot separate\n");
6768  return;
6769  }
6770 
6771  /* find intersections of halfline from origin
6772  * return if no proper point could be found
6773  */
6774  if( generateCutLTIfindIntersection(scip, 0.0, 0.0, x0, y0_, wl, wu, &xlow, &ylow, &xupp, &yupp) )
6775  return;
6776 
6777  SCIPdebugMsg(scip, "intersections:\n");
6778  SCIPdebugMsg(scip, "lower: %9g\t%9g\tprod %9g\n", xlow, ylow, xlow*ylow);
6779  SCIPdebugMsg(scip, "upper: %9g\t%9g\tprod %9g\n", xupp, yupp, xupp*yupp);
6780 
6781  /* Case 1: If both are outside of bounding box, either NW or SE, then McCormick is sufficient, so return */
6782  if( (xlow <= xl && yupp >= yu) || (ylow <= yl && xupp >= xu) )
6783  return;
6784 
6785  /* There will be at least one cut. Define coefficients and rhs ---will have to change them back if (flipX || flipY) */
6786  if( xlow >= xl && xupp <= xu && ylow >= yl && yupp <= yu )
6787  {
6788  /* Case 2: both are inside. Easy lifting... */
6789  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, FALSE, cx, cy, cw) )
6790  return;
6791 
6792  c0x = *cx * xlow;
6793  c0y = *cy * ylow;
6794  c0w = *cw * wl;
6795  }
6796  else if( xlow >= xl && ylow >= yl && (xupp > xu || yupp > yu) )
6797  {
6798  /* Case 3a and 3b: through lower curve, but not upper. */
6799  if( yupp > yu )
6800  {
6801  /* upper intersect is North; place it within box */
6802  assert(!SCIPisInfinity(scip, yu));
6803  yupp = yu;
6804  xupp = wu / yu;
6805  }
6806  else
6807  {
6808  /* upper intersect is East; place it within box */
6809  assert(!SCIPisInfinity(scip, xu));
6810  xupp = xu;
6811  yupp = wu / xu;
6812  }
6813 
6814  /* find intersection on low curve on half line through new point and (x0,y0_) */
6815  if( generateCutLTIfindIntersection(scip, xupp, yupp, x0, y0_, wl, SCIP_INVALID, &xlow, &ylow, NULL, NULL) )
6816  return;
6817 
6818  /* check whether McCormick is sufficient */
6819  if( xlow < xl || ylow < yl )
6820  return;
6821 
6822  /* lift inequality on lower point */
6823  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, FALSE, cx, cy, cw) )
6824  return;
6825 
6826  c0x = *cx * xlow;
6827  c0y = *cy * ylow;
6828  c0w = *cw * wl;
6829  }
6830  else if( xupp <= xu && yupp <= yu && (xlow < xl || ylow < yl) )
6831  {
6832  /* Case 4a and 4b: viceversa (lift for validity) */
6833  if( ylow < yl )
6834  {
6835  /* upper intersect is South; place it within box */
6836  assert(!SCIPisZero(scip, yl));
6837  ylow = yl;
6838  xlow = wl / yl;
6839  }
6840  else
6841  {
6842  /* upper intersect is West; place it within box */
6843  assert(!SCIPisZero(scip, xl));
6844  xlow = xl;
6845  ylow = wl / xl;
6846  }
6847 
6848  /* find intersection on low curve on half line through new point and (x0,y0) */
6849  if( generateCutLTIfindIntersection(scip, xlow, ylow, x0, y0_, SCIP_INVALID, wu, NULL, NULL, &xupp, &yupp) )
6850  return;
6851 
6852  /* check whether McCormick is sufficient */
6853  if( xupp > xu || yupp > yu )
6854  return;
6855 
6856  /* lift inequality on UPPER point */
6857  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, TRUE, cx, cy, cw) )
6858  return;
6859 
6860  c0x = *cx * xupp;
6861  c0y = *cy * yupp;
6862  c0w = *cw * wu;
6863  }
6864  else if( (xlow < xl && xupp > xu) || (ylow < yl && yupp > yu) )
6865  {
6866  /* Case 5: both outside of bounding box, N and S or W and E. */
6867 #if 0
6868  SCIP_Real xlow2;
6869  SCIP_Real ylow2;
6870  SCIP_Real xupp2;
6871  SCIP_Real yupp2;
6872 #endif
6873 
6874  if( ylow < yl )
6875  {
6876  /* upper intersect is South; place it within box */
6877  assert(!SCIPisZero(scip, yl));
6878  assert(!SCIPisZero(scip, yu));
6879  ylow = yl;
6880  yupp = yu;
6881  xlow = wl / yl;
6882  xupp = wu / yu;
6883  }
6884  else
6885  {
6886  /* upper intersect is West; place it within box */
6887  assert(!SCIPisZero(scip, xl));
6888  assert(!SCIPisZero(scip, xu));
6889  xlow = xl;
6890  xupp = xu;
6891  ylow = wl / xl;
6892  yupp = wu / xu;
6893  }
6894 
6895  SCIPdebugMsg(scip, "New intersections:\n");
6896  SCIPdebugMsg(scip, "lower: %9g\t%9g\tprod %9g\n", xlow, ylow, xlow*ylow);
6897  SCIPdebugMsg(scip, "upper: %9g\t%9g\tprod %9g\n", xupp, yupp, xupp*yupp);
6898 
6899 #if 1
6900  /* Nothing to find. Just separate two inequalities at the same point, just using different support */
6901  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, FALSE, cx, cy, cw) )
6902  {
6903  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, TRUE, cx, cy, cw) )
6904  return;
6905 
6906  c0x = *cx * xupp;
6907  c0y = *cy * yupp;
6908  c0w = *cw * wu;
6909  }
6910  else
6911  {
6912  c0x = *cx * xlow;
6913  c0y = *cy * ylow;
6914  c0w = *cw * wl;
6915  }
6916 
6917 #else
6918  /* find the intersection on the lower (upper) curve on the line through xLP and the upper (lower) point
6919  * this does not seem to work (cuts off solution at nous2), so it is disabled for now
6920  */
6921  if( generateCutLTIfindIntersection(scip, xlow, ylow, x0, y0_, SCIP_INVALID, wu, NULL, NULL, &xupp2, &yupp2) ||
6922  generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp2, yupp2, FALSE, cx, cx, cw) )
6923  {
6924  if( generateCutLTIfindIntersection(scip, xupp, yupp, x0, y0_, wl, SCIP_INVALID, &xlow2, &ylow2, NULL, NULL) ||
6925  generateCutLTIgenMulCoeff(scip, xlow2, ylow2, xupp, yupp, TRUE, cx, cy, cw) )
6926  return;
6927 
6928  c0x = *cx * xupp;
6929  c0y = *cy * yupp;
6930  c0w = *cw * wu;
6931  }
6932  else
6933  {
6934  c0x = *cx * xlow;
6935  c0y = *cy * ylow;
6936  c0w = *cw * wl;
6937  }
6938 #endif
6939  }
6940  else
6941  {
6942  SCIPdebugMsg(scip, "points are in a weird position:\n");
6943  SCIPdebugMsg(scip, "lower: %9g\t%9g\tprod %9g\n", xlow, ylow, xlow*ylow);
6944  SCIPdebugMsg(scip, "upper: %9g\t%9g\tprod %9g\n", xupp, yupp, xupp*yupp);
6945 
6946  return;
6947  }
6948 
6949  SCIPdebugMsg(scip, "cut w.r.t. reduced points: %gx-%g %+gy-%g %+gw-%g >= 0\n",
6950  *cx, c0x, *cy, c0y, *cw, c0w);
6951 
6952  /* re-transform back into original variables */
6953  if( flipx )
6954  *cx = -*cx;
6955  if( flipy )
6956  *cy = -*cy;
6957  if( flipw )
6958  *cw = -*cw;
6959 
6960  *c0 = c0x + c0y + c0w;
6961 
6962  *success = TRUE;
6963 }
6964 
6965 /** tries to generate a cut if constraint quadratic function is factorable and there are linear variables
6966  *
6967  * Computes what is called a lifted tangent inequality described in@n
6968  * Belotti, Miller, Namazifar, Lifted inequalities for bounded products of variables, SIAG/OPT Views-and-News 22:1, 2011
6969  */
6970 static
6972  SCIP* scip, /**< SCIP data structure */
6973  SCIP_CONS* cons, /**< constraint */
6974  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
6975  SCIP_Real* ref, /**< reference solution where to generate the cut */
6976  SCIP_SOL* sol, /**< solution that shall be cutoff, NULL for LP solution */
6977  SCIP_ROWPREP* rowprep, /**< rowprep to store cut data */
6978  SCIP_Bool* success /**< buffer to indicate whether a cut was successfully computed */
6979  )
6980 {
6981  SCIP_CONSDATA* consdata;
6982  SCIP_Real leftminactivity;
6983  SCIP_Real leftmaxactivity;
6984  SCIP_Real leftrefactivity;
6985  SCIP_Real rightminactivity;
6986  SCIP_Real rightmaxactivity;
6987  SCIP_Real rightrefactivity;
6988  SCIP_Real rhsminactivity;
6989  SCIP_Real rhsmaxactivity;
6990  SCIP_Real rhsrefactivity;
6991  SCIP_Real coefleft;
6992  SCIP_Real coefright;
6993  SCIP_Real coefrhs;
6994  SCIP_Real cutlhs;
6995  int i;
6996 
6997  assert(scip != NULL);
6998  assert(cons != NULL);
6999  assert(ref != NULL);
7000  assert(rowprep != NULL);
7001  assert(success != NULL);
7002  /* currently only separate LP solution or solutions given as SCIP_SOL, i.e., no cutgeneration during initlp */
7003  assert(sol != NULL || SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL);
7004 
7005  consdata = SCIPconsGetData(cons);
7006  assert(consdata != NULL);
7007  assert(consdata->nlinvars > 0);
7008  assert(consdata->factorleft != NULL);
7009  assert(consdata->factorright != NULL);
7010 
7011  *success = FALSE;
7012  rowprep->sidetype = SCIP_SIDETYPE_LEFT;
7013 
7014  /* write violated constraints as factorleft * factorright '==' rhs
7015  * where rhs are constraint sides - activity bound of linear part
7016  */
7017  rhsminactivity = consdata->lhs;
7018  rhsmaxactivity = consdata->rhs;
7019  rhsrefactivity = (violside == SCIP_SIDETYPE_LEFT ? consdata->lhs : consdata->rhs);
7020 
7021  for( i = 0; i < consdata->nlinvars; ++i )
7022  {
7023  if( !SCIPisInfinity(scip, -rhsminactivity) )
7024  {
7025  if( consdata->lincoefs[i] < 0.0 )
7026  {
7027  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i])) )
7028  rhsminactivity = -SCIPinfinity(scip);
7029  else
7030  rhsminactivity -= consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
7031  }
7032  else
7033  {
7034  assert(consdata->lincoefs[i] > 0.0);
7035  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i])) )
7036  rhsminactivity = -SCIPinfinity(scip);
7037  else
7038  rhsminactivity -= consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
7039  }
7040  }
7041  if( !SCIPisInfinity(scip, rhsmaxactivity) )
7042  {
7043  if( consdata->lincoefs[i] < 0.0 )
7044  {
7045  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i])) )
7046  rhsmaxactivity = SCIPinfinity(scip);
7047  else
7048  rhsmaxactivity -= consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
7049  }
7050  else
7051  {
7052  assert(consdata->lincoefs[i] > 0.0);
7053  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i])) )
7054  rhsmaxactivity = SCIPinfinity(scip);
7055  else
7056  rhsmaxactivity -= consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
7057  }
7058  }
7059  rhsrefactivity -= consdata->lincoefs[i] * SCIPgetSolVal(scip, sol, consdata->linvars[i]);
7060  }
7061 
7062  if( SCIPisInfinity(scip, -rhsminactivity) || SCIPisInfinity(scip, rhsmaxactivity) )
7063  {
7064  /* if right hand side is unbounded, then cannot do LTI */
7065  return SCIP_OKAY;
7066  }
7067 
7068  if( !SCIPisFeasPositive(scip, rhsminactivity) && !SCIPisFeasNegative(scip, rhsmaxactivity) )
7069  {
7070  /* if right hand side has 0 inside activity, then cannot do anything
7071  * if it has 0.0 as min or max activity, then a usual McCormick should be sufficient, too
7072  */
7073  return SCIP_OKAY;
7074  }
7075 
7076  leftminactivity = consdata->factorleft[consdata->nquadvars];
7077  leftmaxactivity = consdata->factorleft[consdata->nquadvars];
7078  leftrefactivity = consdata->factorleft[consdata->nquadvars];
7079  rightminactivity = consdata->factorright[consdata->nquadvars];
7080  rightmaxactivity = consdata->factorright[consdata->nquadvars];
7081  rightrefactivity = consdata->factorright[consdata->nquadvars];
7082  for( i = 0; i < consdata->nquadvars; ++i )
7083  {
7084  if( !SCIPisInfinity(scip, -leftminactivity) )
7085  {
7086  if( consdata->factorleft[i] > 0.0 )
7087  {
7088  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
7089  leftminactivity = -SCIPinfinity(scip);
7090  else
7091  leftminactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
7092  }
7093  else if( consdata->factorleft[i] < 0.0 )
7094  {
7095  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
7096  leftminactivity = -SCIPinfinity(scip);
7097  else
7098  leftminactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
7099  }
7100  }
7101  if( !SCIPisInfinity(scip, leftmaxactivity) )
7102  {
7103  if( consdata->factorleft[i] > 0.0 )
7104  {
7105  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
7106  leftmaxactivity = SCIPinfinity(scip);
7107  else
7108  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
7109  }
7110  else if( consdata->factorleft[i] < 0.0 )
7111  {
7112  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
7113  leftmaxactivity = SCIPinfinity(scip);
7114  else
7115  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
7116  }
7117  }
7118  leftrefactivity += consdata->factorleft[i] * ref[i];
7119 
7120  if( !SCIPisInfinity(scip, -rightminactivity) )
7121  {
7122  if( consdata->factorright[i] > 0.0 )
7123  {
7124  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
7125  rightminactivity = -SCIPinfinity(scip);
7126  else
7127  rightminactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
7128  }
7129  else if( consdata->factorright[i] < 0.0 )
7130  {
7131  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
7132  rightminactivity = -SCIPinfinity(scip);
7133  else
7134  rightminactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
7135  }
7136  }
7137  if( !SCIPisInfinity(scip, rightmaxactivity) )
7138  {
7139  if( consdata->factorright[i] > 0.0 )
7140  {
7141  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
7142  rightmaxactivity = SCIPinfinity(scip);
7143  else
7144  rightmaxactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
7145  }
7146  else if( consdata->factorright[i] < 0.0 )
7147  {
7148  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
7149  rightmaxactivity = SCIPinfinity(scip);
7150  else
7151  rightmaxactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
7152  }
7153  }
7154  rightrefactivity += consdata->factorright[i] * ref[i];
7155  }
7156 
7157  /* if activities exceed "opposite" infinity, huge bounds seem to be involved, for which the below method is not prepared */
7158  if( SCIPisInfinity(scip, leftminactivity) || SCIPisInfinity(scip, -leftmaxactivity) ||
7159  SCIPisInfinity(scip, rightminactivity) || SCIPisInfinity(scip, -rightmaxactivity) )
7160  return SCIP_OKAY;
7161 
7162  /* if activity in reference point exceeds value for infinity, then the below method will also not work properly */
7163  if( SCIPisInfinity(scip, REALABS(leftrefactivity)) || SCIPisInfinity(scip, REALABS(rightrefactivity)) )
7164  return SCIP_OKAY;
7165 
7166  /* if any of the factors is essentially fixed, give up and do usual method (numerically less sensitive, I hope) */
7167  if( SCIPisRelEQ(scip, leftminactivity, leftmaxactivity) || SCIPisRelEQ(scip, rightminactivity, rightmaxactivity) )
7168  return SCIP_OKAY;
7169 
7170  /* success can only be expected for separation of violated x*y <= w, assuming x>=0, y>=0
7171  * @todo we should check this early? */
7172 
7173  /* call Couenne magic */
7175  leftminactivity, leftmaxactivity, leftrefactivity,
7176  rightminactivity, rightmaxactivity, rightrefactivity,
7177  rhsminactivity, rhsmaxactivity, rhsrefactivity,
7178  &coefleft, &coefright, &coefrhs, &cutlhs,
7179  success);
7180 
7181  if( !*success )
7182  return SCIP_OKAY;
7183 
7184  SCIPdebugMsg(scip, "LTI for x[%g,%g] * y[%g,%g] = w[%g,%g]: %gx %+gy %+gw >= %g; feas: %g\n",
7185  leftminactivity, leftmaxactivity, rightminactivity, rightmaxactivity, rhsminactivity, rhsmaxactivity,
7186  coefleft, coefright, coefrhs, cutlhs,
7187  coefleft * leftrefactivity + coefright * rightrefactivity + coefrhs * rhsrefactivity - cutlhs
7188  );
7189 
7190  if( coefleft * leftrefactivity + coefright * rightrefactivity + coefrhs * rhsrefactivity >= cutlhs )
7191  {
7192  SCIPdebugMsg(scip, "does not cutoff point? :-(\n");
7193  *success = FALSE;
7194  return SCIP_OKAY;
7195  }
7196 
7197  /* setup cut coefs for
7198  * coefleft * leftfactor + coefright * rightfactor + coefrhs * w >= cutlhs, where conslhs - lincoefs <= w <= consrhs - lincoefs
7199  */
7200  for( i = 0; i < consdata->nquadvars; ++i )
7201  {
7202  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, consdata->quadvarterms[i].var, coefleft * consdata->factorleft[i] + coefright * consdata->factorright[i]) );
7203  }
7204  SCIPaddRowprepConstant(rowprep, coefleft * consdata->factorleft[i] + coefright * consdata->factorright[i]);
7205 
7206  for( i = 0; i < consdata->nlinvars; ++i )
7207  {
7208  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, consdata->linvars[i], -coefrhs * consdata->lincoefs[i]) );
7209  }
7210  if( coefrhs > 0.0 )
7211  {
7212  /* use coefrhs * w <= coefrhs * (consrhs - lincoefs) */
7213  assert(!SCIPisInfinity(scip, consdata->rhs));
7214  SCIPaddRowprepConstant(rowprep, coefrhs * consdata->rhs);
7215  }
7216  else
7217  {
7218  /* use coefrhs * w <= coeflhs * (conslhs - lincoefs) */
7219  assert(!SCIPisInfinity(scip, -consdata->lhs));
7220  SCIPaddRowprepConstant(rowprep, coefrhs * consdata->lhs);
7221  }
7222  SCIPaddRowprepSide(rowprep, cutlhs);
7223 
7224  rowprep->local = TRUE;
7225 
7226  (void) SCIPsnprintf(rowprep->name, SCIP_MAXSTRLEN, "%s_lti_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
7227 
7228  *success = TRUE;
7229 
7230  return SCIP_OKAY;
7231 }
7232 
7233 /** computes cut coefficients by linearizing a quadratic function */
7234 static
7236  SCIP* scip, /**< SCIP data structure */
7237  SCIP_CONS* cons, /**< constraint */
7238  SCIP_SIDETYPE violside, /**< side for which to generate cut */
7239  SCIP_Real* ref, /**< reference solution where to generate the cut */
7240  SCIP_ROWPREP* rowprep, /**< rowprep to store cut data */
7241  SCIP_Bool* success /**< buffer to indicate whether a cut was successfully computed */
7242  )
7243 {
7244  SCIP_CONSDATA* consdata;
7245  SCIP_BILINTERM* bilinterm;
7246  SCIP_Real constant;
7247  SCIP_Real coef;
7248  SCIP_Real coef2;
7249  SCIP_VAR* var;
7250  int var2pos;
7251  int j;
7252  int k;
7253 
7254  assert(scip != NULL);
7255  assert(cons != NULL);
7256  assert(ref != NULL);
7257  assert(success != NULL);
7258 
7259  consdata = SCIPconsGetData(cons);
7260  assert(consdata != NULL);
7261 
7262  *success = TRUE;
7263 
7264  /* do first-order Taylor for each term */
7265  for( j = 0; j < consdata->nquadvars && *success; ++j )
7266  {
7267  var = consdata->quadvarterms[j].var;
7268 
7269  /* initialize coefficients to linear coefficients of quadratic variables */
7270  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, consdata->quadvarterms[j].lincoef) );
7271 
7272  /* add linearization of square term */
7273  coef = 0.0;
7274  constant = 0.0;
7275  SCIPaddSquareLinearization(scip, consdata->quadvarterms[j].sqrcoef, ref[j],
7276  consdata->quadvarterms[j].nadjbilin == 0 && SCIPvarGetType(var) < SCIP_VARTYPE_CONTINUOUS, &coef, &constant, success);
7277  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, coef) );
7278  SCIPaddRowprepConstant(rowprep, constant);
7279 
7280  /* add linearization of bilinear terms that have var as first variable */
7281  for( k = 0; k < consdata->quadvarterms[j].nadjbilin && *success; ++k )
7282  {
7283  bilinterm = &consdata->bilinterms[consdata->quadvarterms[j].adjbilin[k]];
7284  if( bilinterm->var1 != var )
7285  continue;
7286  assert(bilinterm->var2 != var);
7287  assert(consdata->sepabilinvar2pos != NULL);
7288 
7289  var2pos = consdata->sepabilinvar2pos[consdata->quadvarterms[j].adjbilin[k]];
7290  assert(var2pos >= 0);
7291  assert(var2pos < consdata->nquadvars);
7292  assert(consdata->quadvarterms[var2pos].var == bilinterm->var2);
7293 
7294  coef = 0.0;
7295  coef2 = 0.0;
7296  constant = 0.0;
7297  SCIPaddBilinLinearization(scip, bilinterm->coef, ref[j], ref[var2pos], &coef, &coef2, &constant, success);
7298  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, coef) );
7299  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, bilinterm->var2, coef2) );
7300  SCIPaddRowprepConstant(rowprep, constant);
7301  }
7302  }
7303 
7304  if( !*success )
7305  {
7306  SCIPdebugMsg(scip, "no success in linearization of <%s> in reference point\n", SCIPconsGetName(cons));
7307  return SCIP_OKAY;
7308  }
7309 
7310  rowprep->sidetype = violside;
7311  SCIPaddRowprepSide(rowprep, violside == SCIP_SIDETYPE_LEFT ? consdata->lhs : consdata->rhs);
7312 
7313  (void) SCIPsnprintf(rowprep->name, SCIP_MAXSTRLEN, "%s_side%d_linearization_%d", SCIPconsGetName(cons), violside, SCIPgetNLPs(scip));
7314 
7315  return SCIP_OKAY;
7316 }
7317 
7318 /** helper function to update the best relaxation for a bilinear term when using valid linear inequalities */
7319 static
7321  SCIP* scip, /**< SCIP data structure */
7322  SCIP_VAR* RESTRICT x, /**< first variable */
7323  SCIP_VAR* RESTRICT y, /**< second variable */
7324  SCIP_Real bilincoef, /**< coefficient of the bilinear term */
7325  SCIP_SIDETYPE violside, /**< side of quadratic constraint that is violated */
7326  SCIP_Real refx, /**< reference point for the x variable */
7327  SCIP_Real refy, /**< reference point for the y variable */
7328  SCIP_Real* RESTRICT ineqs, /**< coefficients of each linear inequality; stored as triple (xcoef,ycoef,constant) */
7329  int nineqs, /**< total number of inequalities */
7330  SCIP_Real mccormickval, /**< value of the McCormick relaxation at the reference point */
7331  SCIP_Real* RESTRICT bestcoefx, /**< pointer to update the x coefficient */
7332  SCIP_Real* RESTRICT bestcoefy, /**< pointer to update the y coefficient */
7333  SCIP_Real* RESTRICT bestconst, /**< pointer to update the constant */
7334  SCIP_Real* RESTRICT bestval, /**< value of the best relaxation that have been found so far */
7335  SCIP_Bool* success /**< buffer to store whether we found a better relaxation */
7336  )
7337 {
7338  SCIP_Real constshift[2] = {0.0, 0.0};
7339  SCIP_Real constant;
7340  SCIP_Real xcoef;
7341  SCIP_Real ycoef;
7342  SCIP_Real lbx;
7343  SCIP_Real ubx;
7344  SCIP_Real lby;
7345  SCIP_Real uby;
7346  SCIP_Bool update;
7347  SCIP_Bool overestimate;
7348  int i;
7349 
7350  assert(x != y);
7351  assert(!SCIPisZero(scip, bilincoef));
7352  assert(nineqs >= 0 && nineqs <= 2);
7353  assert(bestcoefx != NULL);
7354  assert(bestcoefy != NULL);
7355  assert(bestconst != NULL);
7356  assert(bestval != NULL);
7357 
7358  /* no inequalities available */
7359  if( nineqs == 0 )
7360  return;
7361  assert(ineqs != NULL);
7362 
7363  lbx = SCIPvarGetLbLocal(x);
7364  ubx = SCIPvarGetUbLocal(x);
7365  lby = SCIPvarGetLbLocal(y);
7366  uby = SCIPvarGetUbLocal(y);
7367  overestimate = (violside == SCIP_SIDETYPE_LEFT);
7368 
7369  /* check cases for which we can't compute a tighter relaxation */
7370  if( SCIPisFeasLE(scip, refx, lbx) || SCIPisFeasGE(scip, refx, ubx)
7371  || SCIPisFeasLE(scip, refy, lby) || SCIPisFeasGE(scip, refy, uby) )
7372  return;
7373 
7374  /* due to the feasibility tolerances of the LP and NLP solver, it might possible that the reference point is
7375  * violating the linear inequalities; to ensure that we compute a valid underestimate, we relax the linear
7376  * inequality by changing its constant part
7377  */
7378  for( i = 0; i < nineqs; ++i )
7379  {
7380  constshift[i] = MAX(0.0, ineqs[3*i] * refx - ineqs[3*i+1] * refy - ineqs[3*i+2]);
7381  SCIPdebugMsg(scip, "constant shift of inequality %d = %.16f\n", constshift[i]);
7382  }
7383 
7384  /* try to use both inequalities */
7385  if( nineqs == 2 )
7386  {
7387  SCIPcomputeBilinEnvelope2(scip, bilincoef, lbx, ubx, refx, lby, uby, refy, overestimate, ineqs[0], ineqs[1],
7388  ineqs[2] + constshift[0], ineqs[3], ineqs[4], ineqs[5] + constshift[1], &xcoef, &ycoef, &constant, &update);
7389 
7390  if( update )
7391  {
7392  SCIP_Real val = xcoef * refx + ycoef * refy + constant;
7393  SCIP_Real relimpr = 1.0 - (REALABS(val - bilincoef * refx * refy) + 1e-4) / (REALABS(*bestval - bilincoef * refx * refy) + 1e-4);
7394  SCIP_Real absimpr = REALABS(val - (*bestval));
7395 
7396  /* update relaxation if possible */
7397  if( relimpr > 0.05 && absimpr > 1e-3 && ((overestimate && SCIPisRelLT(scip, val, *bestval)) || (!overestimate && SCIPisRelGT(scip, val, *bestval))) )
7398  {
7399  *bestcoefx = xcoef;
7400  *bestcoefy = ycoef;
7401  *bestconst = constant;
7402  *bestval = val;
7403  *success = TRUE;
7404  }
7405  }
7406  }
7407 
7408  /* use inequalities individually */
7409  for( i = 0; i < nineqs; ++i )
7410  {
7411  SCIPcomputeBilinEnvelope1(scip, bilincoef, lbx, ubx, refx, lby, uby, refy, overestimate, ineqs[3*i], ineqs[3*i+1],
7412  ineqs[3*i+2] + constshift[i], &xcoef, &ycoef, &constant, &update);
7413 
7414  if( update )
7415  {
7416  SCIP_Real val = xcoef * refx + ycoef * refy + constant;
7417  SCIP_Real relimpr = 1.0 - (REALABS(val - bilincoef * refx * refy) + 1e-4) / (REALABS(mccormickval - bilincoef * refx * refy) + 1e-4);
7418  SCIP_Real absimpr = REALABS(val - (*bestval));
7419 
7420  /* update relaxation if possible */
7421  if( relimpr > 0.05 && absimpr > 1e-3 && ((overestimate && SCIPisRelLT(scip, val, *bestval)) || (!overestimate && SCIPisRelGT(scip, val, *bestval))) )
7422  {
7423  *bestcoefx = xcoef;
7424  *bestcoefy = ycoef;
7425  *bestconst = constant;
7426  *bestval = val;
7427  *success = TRUE;
7428  }
7429  }
7430  }
7431 }
7432 
7433 /* returns the interiority of a reference point w.r.t. given bounds */
7434 static
7436  SCIP* scip, /**< SCIP data structure */
7437  SCIP_Real lbx, /**< lower bound of the first variable */
7438  SCIP_Real ubx, /**< upper bound of the first variable */
7439  SCIP_Real refx, /**< reference point of the first variable */
7440  SCIP_Real lby, /**< lower bound of the second variable */
7441  SCIP_Real uby, /**< upper bound of the second variable */
7442  SCIP_Real refy /**< reference point of the second variable */
7443  )
7444 {
7445  SCIP_Real interiorityx;
7446  SCIP_Real interiorityy;
7447 
7448  interiorityx = MIN(refx-lbx, ubx-refx) / MAX(ubx-lbx, SCIPepsilon(scip)); /*lint !e666*/
7449  interiorityy = MIN(refy-lby, uby-refy) / MAX(uby-lby, SCIPepsilon(scip)); /*lint !e666*/
7450 
7451  return 2.0*MIN(interiorityx, interiorityy);
7452 }
7453 
7454 /** computes cut coefficients for a nonconvex quadratic function */
7455 static
7457  SCIP* scip, /**< SCIP data structure */
7458  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7459  SCIP_CONS* cons, /**< constraint */
7460  SCIP_SIDETYPE violside, /**< side for which to generate cut */
7461  SCIP_Real* ref, /**< reference solution where to generate the cut */
7462  SCIP_ROWPREP* rowprep, /**< rowprep to store cut data */
7463  SCIP_Bool* success /**< buffer to indicate whether a cut was successfully computed */
7464  )
7465 {
7466  SCIP_CONSDATA* consdata;
7467  SCIP_BILINTERM* bilinterm;
7468  SCIP_Real sqrcoef;
7469  SCIP_Real coef;
7470  SCIP_Real coef2;
7471  SCIP_Real constant;
7472  SCIP_VAR* var;
7473  int var2pos;
7474  int j;
7475  int k;
7476 
7477  assert(scip != NULL);
7478  assert(conshdlrdata != NULL);
7479  assert(cons != NULL);
7480  assert(ref != NULL);
7481  assert(success != NULL);
7482 
7483  consdata = SCIPconsGetData(cons);
7484  assert(consdata != NULL);
7485 
7486  rowprep->local = TRUE;
7487  *success = TRUE;
7488 
7489  /* underestimate (secant, McCormick) or linearize each term separately */
7490  for( j = 0; j < consdata->nquadvars && *success; ++j )
7491  {
7492  var = consdata->quadvarterms[j].var;
7493 
7494  /* initialize coefficients to linear coefficients of quadratic variables */
7495  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, consdata->quadvarterms[j].lincoef) );
7496 
7497  sqrcoef = consdata->quadvarterms[j].sqrcoef;
7498  if( sqrcoef != 0.0 )
7499  {
7500  coef = 0.0;
7501  constant = 0.0;
7502  if( (violside == SCIP_SIDETYPE_LEFT && sqrcoef <= 0.0) || (violside == SCIP_SIDETYPE_RIGHT && sqrcoef > 0.0) )
7503  {
7504  /* convex -> linearize */
7505  SCIPaddSquareLinearization(scip, sqrcoef, ref[j], SCIPvarGetType(var) < SCIP_VARTYPE_CONTINUOUS, &coef,
7506  &constant, success);
7507  }
7508  else
7509  {
7510  /* not convex -> secant approximation */
7511  SCIPaddSquareSecant(scip, sqrcoef, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), ref[j], &coef,
7512  &constant, success);
7513  }
7514  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, coef) );
7515  SCIPaddRowprepConstant(rowprep, constant);
7516  }
7517 
7518  /* relax each bilinear term */
7519  for( k = 0; k < consdata->quadvarterms[j].nadjbilin && (*success); ++k )
7520  {
7521  SCIP_VAR* x;
7522  SCIP_VAR* y;
7523  SCIP_Real refx;
7524  SCIP_Real refy;
7525  SCIP_Real lbx;
7526  SCIP_Real ubx;
7527  SCIP_Real lby;
7528  SCIP_Real uby;
7529  int idx;
7530 
7531  idx = consdata->quadvarterms[j].adjbilin[k];
7532  bilinterm = &consdata->bilinterms[idx];
7533  if( bilinterm->var1 != var )
7534  continue;
7535  assert(bilinterm->var2 != var);
7536  assert(consdata->sepabilinvar2pos != NULL);
7537 
7538  var2pos = consdata->sepabilinvar2pos[consdata->quadvarterms[j].adjbilin[k]];
7539  assert(var2pos >= 0);
7540  assert(var2pos < consdata->nquadvars);
7541  assert(consdata->quadvarterms[var2pos].var == bilinterm->var2);
7542 
7543  /* get data of the variables in the bilinear term */
7544  x = var;
7545  y = bilinterm->var2;
7546  refx = ref[j];
7547  refy = ref[var2pos];
7548  lbx = SCIPvarGetLbLocal(x);
7549  ubx = SCIPvarGetUbLocal(x);
7550  lby = SCIPvarGetLbLocal(y);
7551  uby = SCIPvarGetUbLocal(y);
7552  SCIPdebugMsg(scip, "bilinear term %g %s %s with (%g,%g) in [%g,%g]x[%g,%g] overestimate=%u\n", bilinterm->coef,
7553  SCIPvarGetName(x), SCIPvarGetName(y), refx, refy, lbx, ubx, lby, uby, violside == SCIP_SIDETYPE_LEFT);
7554 
7555  /* use the McCormick relaxation for under- or overestimating the bilinear term */
7556  coef = 0.0;
7557  coef2 = 0.0;
7558  constant = 0.0;
7559  SCIPaddBilinMcCormick(scip, bilinterm->coef, lbx, ubx, refx, lby, uby, refy,
7560  violside == SCIP_SIDETYPE_LEFT, &coef, &coef2, &constant, success);
7561  SCIPdebugMsg(scip, "McCormick = %g (%u)\n", refx * coef + refy * coef2 + constant, *success);
7562 
7563  /* tries to compute a tighter relaxation for xy by using valid linear inequalities */
7564  if( conshdlrdata->bilinestimators != NULL && ubx - lbx >= 0.1 && uby - lby >= 0.1
7565  && (SCIPgetNSepaRounds(scip) <= conshdlrdata->bilinineqmaxseparounds || SCIPgetDepth(scip) == 0) )
7566  {
7567  BILINESTIMATOR* bilinestimator;
7568  SCIP_Real mccormick;
7569  SCIP_Real score;
7570  int bilintermidx;
7571 
7572  mccormick = refx * coef + refy * coef2 + constant;
7573  score = getInteriority(scip, lbx, ubx, refx, lby, uby, refy);
7574 
7575  /* get data for bilinear term */
7576  bilintermidx = consdata->bilintermsidx[idx];
7577  assert(conshdlrdata->bilinestimators != NULL);
7578  bilinestimator = &(conshdlrdata->bilinestimators[bilintermidx]);
7579  assert(bilinestimator->x == x);
7580  assert(bilinestimator->y == y);
7581 
7582  /* reset the last improvement factor (used for getting better branching decisions) */
7583  bilinestimator->lastimprfac = 0.0;
7584 
7585  /* compute tighter relaxation for xy if the current score is large enough */
7586  if( SCIPisGE(scip, score, conshdlrdata->minscorebilinterms)
7587  && bilinestimator->nineqoverest + bilinestimator->ninequnderest > 0 )
7588  {
7589  SCIP_Real bestval = mccormick;
7590  SCIP_Bool updaterelax = FALSE;
7591 
7592  /*
7593  * note that we check the sign of the bilinear coefficient together with violside in
7594  * updateBilinearRelaxation in order to decide whether a valid under- or overestimate can be computed
7595  */
7596 
7597  /* use overestimates */
7598  updateBilinearRelaxation(scip, x, y, bilinterm->coef, violside, refx, refy, bilinestimator->ineqoverest,
7599  bilinestimator->nineqoverest, mccormick, &coef, &coef2, &constant, &bestval, &updaterelax);
7600 
7601  /* use underestimates */
7602  updateBilinearRelaxation(scip, x, y, bilinterm->coef, violside, refx, refy, bilinestimator->inequnderest,
7603  bilinestimator->ninequnderest, mccormick, &coef, &coef2, &constant, &bestval, &updaterelax);
7604 
7605  SCIPdebugMsg(scip, "found better relaxation value: %u (%g)\n", updaterelax, bestval);
7606 
7607  /* check whether the new relaxation is under- or overestimating xy properly */
7608  if( updaterelax )
7609  {
7610  /* update improvement factor */
7611  bilinestimator->lastimprfac = 1.0 - REALABS(bestval - bilinterm->coef * refx * refy) / REALABS(mccormick - bilinterm->coef * refx * refy);
7612 
7613 #ifndef NDEBUG
7614  assert(SCIPisEQ(scip, bestval, coef * refx + coef2 * refy + constant));
7615  if( violside == SCIP_SIDETYPE_LEFT )
7616  {
7617  assert(SCIPisRelGE(scip, bestval, bilinterm->coef * refx * refy));
7618  assert(SCIPisRelLE(scip, bestval, mccormick));
7619  }
7620  else
7621  {
7622  assert(SCIPisRelLE(scip, bestval, bilinterm->coef * refx * refy));
7623  assert(SCIPisRelGE(scip, bestval, mccormick));
7624  }
7625 #endif
7626  }
7627  }
7628  }
7629 
7630  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, coef) );
7631  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, bilinterm->var2, coef2) );
7632  SCIPaddRowprepConstant(rowprep, constant);
7633  }
7634  }
7635 
7636  if( !*success )
7637  {
7638  SCIPdebugMsg(scip, "no success to find estimator for nonconvex <%s>\n", SCIPconsGetName(cons));
7639  return SCIP_OKAY;
7640  }
7641 
7642  rowprep->sidetype = violside;
7643  SCIPaddRowprepSide(rowprep, violside == SCIP_SIDETYPE_LEFT ? consdata->lhs : consdata->rhs);
7644 
7645  (void) SCIPsnprintf(rowprep->name, SCIP_MAXSTRLEN, "%s_side%d_estimation_%d", SCIPconsGetName(cons), violside, SCIPgetNLPs(scip));
7646 
7647  return SCIP_OKAY;
7648 }
7649 
7650 /** generates a cut based on linearization (if convex) or McCormick (if nonconvex) in a given reference point */
7651 static
7653  SCIP* scip, /**< SCIP data structure */
7654  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7655  SCIP_CONS* cons, /**< constraint */
7656  SCIP_Real* ref, /**< reference solution where to generate the cut */
7657  SCIP_SOL* sol, /**< point that we aim to separate, or NULL for LP solution */
7658  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
7659  SCIP_ROW** row, /**< storage for cut */
7660  SCIP_Real* efficacy, /**< buffer to store efficacy of row in reference solution, or NULL if not of interest */
7661  SCIP_Bool checkcurvmultivar, /**< are we allowed to check the curvature of a multivariate quadratic function, if not done yet */
7662  SCIP_Real minefficacy /**< minimal required efficacy */
7663  )
7664 {
7665  SCIP_CONSHDLRDATA* conshdlrdata;
7666  SCIP_CONSDATA* consdata;
7667  SCIP_ROWPREP* rowprep;
7668  SCIP_Bool success;
7669  SCIP_Real viol = 0.0;
7670 
7671  assert(scip != NULL);
7672  assert(conshdlr != NULL);
7673  assert(cons != NULL);
7674  assert(ref != NULL);
7675  assert(row != NULL);
7676 
7677  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7678  assert(conshdlrdata != NULL);
7679 
7680  consdata = SCIPconsGetData(cons);
7681  assert(consdata != NULL);
7682  assert(violside != SCIP_SIDETYPE_LEFT || !SCIPisInfinity(scip, -consdata->lhs));
7683  assert(violside != SCIP_SIDETYPE_RIGHT || !SCIPisInfinity(scip, consdata->rhs));
7684 
7685  *row = NULL;
7686 
7688  success = FALSE;
7689 
7690  /* if constraint function is factorable, then try to use factorable form to generate cut */
7691  if( consdata->factorleft != NULL )
7692  {
7693  if( consdata->nlinvars == 0 )
7694  {
7695  SCIP_CALL( generateCutFactorable(scip, cons, violside, ref, rowprep, &success) );
7696  }
7697  else if( sol != NULL || SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
7698  {
7699  /* generateCutLTI needs reference values also for the linear variables, which we only have if sol is given or LP has been solved */
7700  SCIP_CALL( generateCutLTI(scip, cons, violside, ref, sol, rowprep, &success) );
7701  }
7702  }
7703 
7704  /* if constraint is not factorable or failed to generate cut, try default method */
7705  if( !success )
7706  {
7707  SCIP_CALL( checkCurvature(scip, cons, checkcurvmultivar) );
7708 
7709  if( (violside == SCIP_SIDETYPE_LEFT && consdata->isconcave) || (violside == SCIP_SIDETYPE_RIGHT && consdata->isconvex) )
7710  {
7711  SCIP_CALL( generateCutConvex(scip, cons, violside, ref, rowprep, &success) );
7712  }
7713  else
7714  {
7715  SCIP_CALL( generateCutNonConvex(scip, conshdlrdata, cons, violside, ref, rowprep, &success) );
7716  }
7717 
7718  SCIP_CALL( SCIPaddRowprepTerms(scip, rowprep, consdata->nlinvars, consdata->linvars, consdata->lincoefs) );
7719  }
7720 
7721  /* check if reference point violates cut at least a little bit */
7722  if( success && !SCIPisInfinity(scip, -minefficacy) )
7723  {
7724  viol = SCIPgetRowprepViolation(scip, rowprep, sol);
7725  if( viol <= 0.0 ) /*lint !e644*/
7726  {
7727  SCIPdebugMsg(scip, "skip cut for constraint <%s> because efficacy %g too low (< %g)\n", SCIPconsGetName(cons), viol, minefficacy);
7728  success = FALSE;
7729  }
7730  }
7731 
7732  /* cleanup and improve cut */
7733  if( success )
7734  {
7735  SCIP_Real coefrange;
7736 
7737  /* merge terms */
7738  SCIPmergeRowprepTerms(scip, rowprep);
7739 
7740  /* improve coefficients */
7741  SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, conshdlrdata->cutmaxrange, minefficacy, &coefrange, &viol) );
7742  success = coefrange <= conshdlrdata->cutmaxrange;
7743  }
7744 
7745  /* check that side is finite */ /*lint --e{514} */
7746  success &= !SCIPisInfinity(scip, REALABS(rowprep->side)); /*lint !e514*/
7747 
7748  /* check whether maximal coef is finite, if any */ /*lint --e{514} */
7749  success &= (rowprep->nvars == 0) || !SCIPisInfinity(scip, REALABS(rowprep->coefs[0])); /*lint !e514*/
7750 
7751  /* check if reference point violates cut sufficiently */
7752  if( success && !SCIPisInfinity(scip, -minefficacy) && viol < minefficacy ) /*lint !e644*/
7753  {
7754  SCIPdebugMsg(scip, "skip cut for constraint <%s> because efficacy %g too low (< %g)\n", SCIPconsGetName(cons), viol, minefficacy);
7755  success = FALSE;
7756  }
7757 
7758  /* generate row */
7759  if( success )
7760  {
7761  SCIP_CALL( SCIPgetRowprepRowCons(scip, row, rowprep, SCIPconsGetHdlr(cons)) );
7762 
7763  SCIPdebugMsg(scip, "found cut <%s>, lhs=%g, rhs=%g, mincoef=%g, maxcoef=%g, range=%g, nnz=%d, efficacy=%g\n",
7764  SCIProwGetName(*row), SCIProwGetLhs(*row), SCIProwGetRhs(*row),
7765  rowprep->nvars > 0 ? rowprep->coefs[rowprep->nvars-1] : 0.0, rowprep->nvars > 0 ? rowprep->coefs[0] : 0.0,
7766  rowprep->nvars > 0 ? rowprep->coefs[0]/rowprep->coefs[rowprep->nvars-1] : 1.0,
7767  SCIProwGetNNonz(*row), viol); /*lint !e414 */
7768 
7769  if( efficacy != NULL )
7770  *efficacy = viol;
7771  }
7772 
7773  SCIPfreeRowprep(scip, &rowprep);
7774 
7775  return SCIP_OKAY;
7776 }
7777 
7778 /** computes eigen decomposition of A, where \f$ f(x) = x^T A x + b^T x \f$.
7779  *
7780  * The eigen decomposition is given by A = P D P^T, where D is diagonal formed by the eigenvalues and P is orthonormal
7781  * whose columns are the eigenvectors; we also compute b^T * P, in case one needs the change of variables P^T x = y <=>
7782  * 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
7783  * of P^T is stored in eigenvector[0..n-1], the second row is stored in eigenvectors[n..2n-1], etc; equivalently, the
7784  * first eigenvector is eigenvector[0..n-1], the second one is eigenvectors[n..2n-1], etc.
7785  *
7786  * @todo: - at the moment of writing, checkCurvature computes the eigenvalues (and vectors) for determining curvature
7787  * when it can't to it via other considerations. so one could try to merge both methods together.
7788  * - it seems that if A is of the form [I 0; 0 A'], one only needs to compute the decomposition for A' so one
7789  * could do better in terms of memory and speed. For instance, when the matrix is diagonal, the eigenvectors
7790  * are the identity matrix and the eigenvalues are readily available from the constraint, so one could adapt
7791  * the functions that uses the eigenvectors in this particular case. One could also think about storing the
7792  * eigenvectors in a sparse fashion, though eigenvectors are seldom sparse.
7793  */
7794 static
7796  SCIP* scip, /**< SCIP data structure */
7797  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7798  SCIP_CONS* cons /**< constraint */
7799  )
7800 {
7801  SCIP_CONSDATA* consdata;
7802  int n;
7803  int nn;
7804  int row;
7805  int col;
7806  int i;
7807  int j;
7808  double* matrix;
7809  SCIP_HASHMAP* var2index;
7810 
7811  SCIPdebugMsg(scip, "computing ED for cons %s\n", SCIPconsGetName(cons));
7812 
7813  assert(scip != NULL);
7814  assert(conshdlr != NULL);
7815  assert(cons != NULL);
7816 
7817  consdata = SCIPconsGetData(cons);
7818  assert(consdata != NULL);
7819 
7820  /* function has to be convex with finite rhs or concave with finite lhs */
7821  assert((consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
7822  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)));
7823 
7824  /* can't compute eigenvectors without IPOPT */
7825  if( !SCIPisIpoptAvailableIpopt() )
7826  {
7827  consdata->isedavailable = FALSE;
7828  return SCIP_OKAY;
7829  }
7830 
7831  /* @todo: - it seems that if A is of the form [I 0; 0 A'], one only needs to compute the decomposition for A'
7832  * so one could do better in terms of memory and speed
7833  * - if n too big don't compute SVD
7834  */
7835  n = consdata->nquadvars;
7836 
7837  /* do not compute eigendecomposition if n is too large */
7838  nn = n * n;
7839  if( nn < 0 || (unsigned) (int) nn > UINT_MAX / sizeof(SCIP_Real) )
7840  {
7841  SCIPdebugMsg(scip, "n is too large to compute eigendecomposition\n");
7842  consdata->isedavailable = FALSE;
7843  return SCIP_OKAY;
7844  }
7845 
7846  /* we just need to pass the upper triangle of A since it is symmetric; build it here */
7847  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->eigenvectors, nn) );
7848  matrix = consdata->eigenvectors;
7849  BMSclearMemoryArray(matrix, nn);
7850 
7851  /* @todo if we are called in solving stage (or late from initsol), we can avoid the hashmap by using sepabilinvar2pos */
7852  SCIP_CALL( SCIPhashmapCreate(&var2index, SCIPblkmem(scip), n) );
7853 
7854  for( i = 0; i < n; ++i )
7855  {
7856  SCIP_CALL( SCIPhashmapInsert(var2index, consdata->quadvarterms[i].var, (void*)(size_t)i) );
7857  matrix[i*n + i] = consdata->quadvarterms[i].sqrcoef;
7858 #ifdef DEBUG_PROJ
7859  printf("inserting in position %d, value %g\n", i*n + i, consdata->quadvarterms[i].sqrcoef);
7860 #endif
7861  }
7862 
7863  for( i = 0; i < consdata->nbilinterms; ++i )
7864  {
7865  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var1));
7866  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var2));
7867  row = (int)(size_t)SCIPhashmapGetImage(var2index, consdata->bilinterms[i].var1);
7868  col = (int)(size_t)SCIPhashmapGetImage(var2index, consdata->bilinterms[i].var2);
7869  if( row < col )
7870  {
7871  matrix[row * n + col] = consdata->bilinterms[i].coef/2;
7872 #ifdef DEBUG_PROJ
7873  printf("inserting in position %d, value %g\n", row*n + col, consdata->bilinterms[i].coef/2);
7874 #endif
7875  }
7876  else
7877  {
7878  matrix[col * n + row] = consdata->bilinterms[i].coef/2;
7879 #ifdef DEBUG_PROJ
7880  printf("inserting in position %d, value %g\n", col*n + row, consdata->bilinterms[i].coef/2);
7881 #endif
7882  }
7883  }
7884 
7885 #ifdef DEBUG_PROJ
7886  printf("matrix built:\n");
7887  for( i = 0; i < n; i++ )
7888  {
7889  for( j = 0; j < n; j++ )
7890  printf("%g ", matrix[i*n + j]);
7891  printf("\n");
7892  }
7893 #endif
7894 
7895  /* compute eigenvalues and eigenvectors */
7896  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->eigenvalues, n) );
7897 
7898  if( LapackDsyev(TRUE, n, matrix, consdata->eigenvalues) != SCIP_OKAY )
7899  {
7900  SCIPdebugMsg(scip, "couldn't compute ED for cons %s\n", SCIPconsGetName(cons));
7901  consdata->isedavailable = FALSE;
7902  }
7903  else
7904  {
7905  consdata->isedavailable = TRUE;
7906 
7907  /* compute b^T*P */
7908  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &consdata->bp, n) );
7909  for( i = 0; i < n; i++ )
7910  for( j = 0; j < n; j++ )
7911  consdata->bp[i] += consdata->quadvarterms[j].lincoef * matrix[i*n + j];
7912 
7913 #ifdef DEBUG_PROJ
7914  printf("eigenvalues:\n");
7915  for( j = 0; j < n; j++ )
7916  printf("%g ", consdata->eigenvalues[j]);
7917 
7918  printf("\neigenvectors (P^T):\n");
7919  for( i = 0; i < n; i++ )
7920  {
7921  for( j = 0; j < n; j++ )
7922  printf("%g ", matrix[i*n + j]);
7923  printf("\n");
7924  }
7925 
7926  printf("b*P^T:\n");
7927  for( j = 0; j < n; j++ )
7928  printf("%g ", consdata->bp[j]);
7929  printf("svd computed successfully\n");
7930 #endif
7931  }
7932 
7933  SCIPhashmapFree(&var2index);
7934 
7935  return SCIP_OKAY;
7936 }
7937 
7938 /** computes an interior point for the quadratic part of the convex constraint
7939  *
7940  * There are different methods for computing the interior point
7941  * - 'a'ny: solves min 0, f(x) <= rhs, x in bounds
7942  * - 'm'ost interior: solves min f(x), x in bounds
7943  *
7944  * @todo: other methods for computing an interior point?
7945  */
7946 static
7948  SCIP* scip, /**< SCIP data structure */
7949  SCIP_CONS* cons, /**< constraint */
7950  char method, /**< method for computing interior point ('a' any point, 'm'ost interior) */
7951  SCIP_Bool* success /**< buffer to store if an interior point was found */
7952  )
7953 {
7954  SCIP_CONSDATA* consdata;
7955  SCIP_QUADELEM* nlrowquadelems;
7956  SCIP_NLPIPROBLEM* prob;
7957  SCIP_NLPI* nlpi;
7958  SCIP_Real* interiorpoint;
7959  SCIP_Real* lbs;
7960  SCIP_Real* ubs;
7961  SCIP_Real* lincoefs;
7962  SCIP_Real nlpiside;
7963  char probname[SCIP_MAXSTRLEN];
7964  int* lininds;
7965  int nlrownquadelems;
7966  int nquadvars;
7967  int i;
7968 
7969  assert(scip != NULL);
7970  assert(cons != NULL);
7971 
7972  assert(success != NULL);
7973  *success = FALSE;
7974 
7975  consdata = SCIPconsGetData(cons);
7976  assert(consdata != NULL);
7977 
7978  assert((consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
7979  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)));
7980 
7981  /* need an NLP solver */
7982  if( SCIPgetNNlpis(scip) == 0 )
7983  return SCIP_OKAY;
7984 
7985  nlpi = NULL;
7986  prob = NULL;
7987  lbs = NULL;
7988  ubs = NULL;
7989  lincoefs = NULL;
7990  lininds = NULL;
7991 
7992 #ifdef SCIP_DEBUG_INT
7993  SCIPinfoMessage(scip, NULL, "Computing interior point for\n");
7994  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
7995  SCIPinfoMessage(scip, NULL, ";\n");
7996 #endif
7997 
7998  /* in the convex case, we try to find an interior point of x^T A x + b^T x <= rhs - maximum activity linear part
7999  * in the concave case: lhs - minimum activity linear part <= x^T A x + b^T x; we compute activities ourselves,
8000  * since consdata->max(min)linactivity are only computed when lhs (rhs) is finite and this not always holds
8001  */
8002  if( consdata->isconvex )
8003  {
8004  /* compute maximum activity */
8005  nlpiside = 0;
8006  for( i = 0; i < consdata->nlinvars; ++i )
8007  {
8008  if( consdata->lincoefs[i] >= 0.0 )
8009  {
8010  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i]) ) )
8011  nlpiside = SCIPinfinity(scip);
8012  else
8013  nlpiside += consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
8014  }
8015  else
8016  {
8017  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i]) ) )
8018  nlpiside = SCIPinfinity(scip);
8019  else
8020  nlpiside += consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
8021  }
8022 
8023  if( SCIPisInfinity(scip, nlpiside) )
8024  {
8025  SCIPdebugMsg(scip, "maximum activity is infinity: there is no interior point for fun <= rhs - maxlinactivity!\n");
8026  return SCIP_OKAY;
8027  }
8028  }
8029 
8030  if( consdata->nlinvars == 0 )
8031  nlpiside = INTERIOR_EPS;
8032 
8033  nlpiside = consdata->rhs - nlpiside;
8034  }
8035  else
8036  {
8037  /* compute minimum activity */
8038  nlpiside = 0;
8039  for( i = 0; i < consdata->nlinvars; ++i )
8040  {
8041  if( consdata->lincoefs[i] >= 0.0 )
8042  {
8043  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i])) )
8044  nlpiside = -SCIPinfinity(scip);
8045  else
8046  nlpiside += consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
8047  }
8048  else
8049  {
8050  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i])) )
8051  nlpiside = -SCIPinfinity(scip);
8052  else
8053  nlpiside += consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
8054  }
8055 
8056  if( SCIPisInfinity(scip, -nlpiside) )
8057  {
8058  SCIPdebugMsg(scip, "minimum activity is -infinity: there is no interior point for fun >= lhs - minlinactivity!\n");
8059  return SCIP_OKAY;
8060  }
8061  }
8062 
8063  if( consdata->nlinvars == 0 )
8064  nlpiside = INTERIOR_EPS;
8065 
8066  nlpiside = consdata->lhs - nlpiside;
8067  }
8068 
8069  nquadvars = consdata->nquadvars;
8070 
8071  /* if we are looking for any interior point and the 0 is one, then use it */
8072  if( method == 'a' && ((consdata->isconvex && SCIPisGE(scip, nlpiside, 0.0))
8073  || (consdata->isconcave && SCIPisLE(scip, nlpiside, 0.0))) )
8074  {
8075  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &(consdata->interiorpoint), nquadvars) );
8076 
8077  *success = TRUE;
8078  goto TERMINATE;
8079  }
8080 
8081  /* build nlrow */
8082  if( consdata->nlrow == NULL )
8083  {
8084  SCIP_CALL( createNlRow(scip, cons) );
8085  assert(consdata->nlrow != NULL);
8086  }
8087 
8088  nlpi = SCIPgetNlpis(scip)[0];
8089  assert(nlpi != NULL);
8090 
8091  /* initializing the subproblem */
8092  (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "%s_subquad", SCIPgetProbName(scip));
8093  SCIP_CALL( SCIPnlpiCreateProblem(nlpi, &prob, probname) );
8094  assert(prob != NULL);
8095 
8096 #ifdef SCIP_DEBUG_INT
8098 #endif
8099  /* TODO: maybe one should set some generous iteration limit and/or a timelimit (remaining scip solve time)? */
8100 
8101  /* ask for memory to store data needed to create vars and linear coefficients */
8102  SCIP_CALL( SCIPallocBufferArray(scip, &lbs, nquadvars) );
8103  SCIP_CALL( SCIPallocBufferArray(scip, &ubs, nquadvars) );
8104  SCIP_CALL( SCIPallocBufferArray(scip, &lininds, nquadvars) );
8105  SCIP_CALL( SCIPallocBufferArray(scip, &lincoefs, nquadvars) );
8106 
8107  /* get bounds and linear coefficients */
8108  for( i = 0; i < nquadvars; i++ )
8109  {
8110  lbs[i] = SCIPvarGetLbGlobal(consdata->quadvarterms[i].var);
8111  ubs[i] = SCIPvarGetUbGlobal(consdata->quadvarterms[i].var);
8112 
8113  lincoefs[i] = consdata->quadvarterms[i].lincoef;
8114  lininds[i] = i;
8115  }
8116 
8117  /* add vars */
8118  SCIP_CALL( SCIPnlpiAddVars(nlpi, prob, nquadvars, lbs, ubs, NULL) );
8119 
8120  /* get nlrow info */
8121  nlrownquadelems = SCIPnlrowGetNQuadElems(consdata->nlrow);
8122  nlrowquadelems = SCIPnlrowGetQuadElems(consdata->nlrow);
8123 
8124 #ifndef NDEBUG
8125  {
8126  SCIP_VAR** nlrowquadvars;
8127 
8128  nlrowquadvars = SCIPnlrowGetQuadVars(consdata->nlrow);
8129  for( i = 0; i < nlrownquadelems; i++ )
8130  {
8131  assert(nlrowquadvars[nlrowquadelems[i].idx1] == consdata->quadvarterms[nlrowquadelems[i].idx1].var);
8132  assert(nlrowquadvars[nlrowquadelems[i].idx2] == consdata->quadvarterms[nlrowquadelems[i].idx2].var);
8133  }
8134  }
8135 #endif
8136 
8137  (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "%s", SCIPconsGetName(cons));
8138 
8139  switch( method )
8140  {
8141  case 'a':
8142  /* add constraint */
8143  if( consdata->isconvex )
8144  {
8145  SCIP_CALL( SCIPnlpiAddConstraints(nlpi, prob, 1, NULL, &nlpiside, &nquadvars, &lininds, &lincoefs,
8146  &nlrownquadelems, &nlrowquadelems, NULL, NULL, NULL) );
8147  }
8148  else
8149  {
8150  SCIP_CALL( SCIPnlpiAddConstraints(nlpi, prob, 1, &nlpiside, NULL, &nquadvars, &lininds, &lincoefs,
8151  &nlrownquadelems, &nlrowquadelems, NULL, NULL, NULL) );
8152  }
8153  break;
8154 
8155  case 'm':
8156  /* add objective */
8157  if( consdata->isconvex )
8158  {
8159  SCIP_CALL( SCIPnlpiSetObjective(nlpi, prob, nquadvars, lininds, lincoefs,
8160  nlrownquadelems, nlrowquadelems, NULL, NULL, 0.0) );
8161  }
8162  else
8163  {
8164  /* NLPI assumes minimization: change signs */
8165  for( i = 0; i < nquadvars; i++ )
8166  lincoefs[i] *= -1;
8167 
8168  /* WARNING: this pointer is not ours, information should be restored! */
8169  for( i = 0; i < nlrownquadelems; i++ )
8170  nlrowquadelems->coef *= -1;
8171 
8172  SCIP_CALL( SCIPnlpiSetObjective(nlpi, prob, nquadvars, lininds, lincoefs,
8173  nlrownquadelems, nlrowquadelems, NULL, NULL, 0.0) );
8174 
8175  /* WARNING: restore information! */
8176  for( i = 0; i < nlrownquadelems; i++ )
8177  nlrowquadelems->coef *= -1;
8178  }
8179  break;
8180 
8181  default:
8182  SCIPerrorMessage("undefined method for computing interior point: %c\n", method);
8183  return SCIP_INVALIDDATA;
8184  }
8185 
8186  /* set NLP tolerances; we don't really need an optimal solution to this NLP */
8187  SCIP_CALL( SCIPnlpiSetRealPar(nlpi, prob, SCIP_NLPPAR_FEASTOL, SCIPfeastol(scip)) ); /*lint !e666*/
8188  SCIP_CALL( SCIPnlpiSetRealPar(nlpi, prob, SCIP_NLPPAR_RELOBJTOL, MAX(SCIPfeastol(scip), SCIPdualfeastol(scip))) ); /*lint !e666*/
8189 
8190  /* solve NLP problem */
8191  SCIP_CALL( SCIPnlpiSolve(nlpi, prob) );
8192 
8193  /* check termination status */
8194  if( SCIPnlpiGetTermstat(nlpi, prob) != SCIP_NLPTERMSTAT_OKAY )
8195  {
8196  SCIPdebugMsg(scip, "cons <%s>: NLP Solver termination status not okay: %d\n",
8197  SCIPconsGetName(cons), SCIPnlpiGetTermstat(nlpi, prob));
8198  *success = FALSE;
8199  goto TERMINATE;
8200  }
8201 
8202  /* check solution status */
8203  switch( SCIPnlpiGetSolstat(nlpi, prob) )
8204  {
8208  /* fallthrough */
8209  SCIPdebugMsg(scip, "cons <%s>: found an interior point. solution status: %d, termination status: %d\n",
8210  SCIPconsGetName(cons), SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
8211  break;
8212 
8216  /* fallthrough */
8217  /* TODO: we could still use the point, and let evaluateGauge decide whether the point is interior or not */
8218  SCIPdebugMsg(scip, "cons <%s>: failed to find an interior point. solution status: %d, termination status: %d\n",
8219  SCIPconsGetName(cons), SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
8220  goto TERMINATE;
8221 
8223  default:
8224  /* fallthrough */
8225  SCIPerrorMessage("cons <%s>: undefined behaviour of NLP Solver. solution status: %d, termination status: %d\n",
8226  SCIPconsGetName(cons), SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
8227  SCIPABORT();
8228  goto TERMINATE; /*lint !e527*/
8229  }
8230 
8231  /* fetch solution
8232  * note: nlpiGetSolution (at least for IPOPT) makes interiorpoint point to the internal solution stored in the
8233  * nlpi problem data structure; we need to copy it here because it will be destroyed once the problem is free'd
8234  */
8235  SCIP_CALL( SCIPnlpiGetSolution(nlpi, prob, &interiorpoint, NULL, NULL, NULL, NULL) );
8236 
8237  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(consdata->interiorpoint), nquadvars) );
8238 
8239  for( i = 0; i < nquadvars; i++ )
8240  {
8241  if( SCIPisFeasZero(scip, interiorpoint[i]) )
8242  consdata->interiorpoint[i] = 0.0;
8243  else
8244  consdata->interiorpoint[i] = interiorpoint[i];
8245  }
8246 
8247  *success = TRUE;
8248 
8249 TERMINATE:
8250 
8251 #ifdef SCIP_DEBUG_INT
8252  printf("Computation of interior point for cons <%s>:\n", SCIPconsGetName(cons));
8253  printf(" - has %d linear variables\n", consdata->nlinvars);
8254  if( consdata->isconvex )
8255  {
8256  printf(" - is convex. rhs: %g maximum activity of linear variables: %g\n", consdata->rhs, consdata->rhs - nlpiside);
8257  printf(" - searched for point whose quadratic part is <= %g\n", nlpiside);
8258  }
8259  else
8260  {
8261  printf(" - is concave. lhs: %g minimum activity of linear variables: %g\n", consdata->lhs, consdata->lhs - nlpiside);
8262  printf(" - searched for point whose quadratic part is >= %g\n", nlpiside);
8263  }
8264 
8265  if( *success )
8266  {
8267  if( prob == NULL )
8268  {
8269  printf("Computation successful, 0 is interior point.\n");
8270  for( i = 0; i < nquadvars; i++ )
8271  {
8272  assert(consdata->interiorpoint[i] == 0.0);
8273  }
8274  }
8275  else
8276  {
8277  printf("Computation successful, NLP soltat: %d, termstat: %d\nPoint found:\n",
8278  SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
8279  for( i = 0; i < nquadvars; i++ )
8280  {
8281  printf("%s = %g\n", SCIPvarGetName(consdata->quadvarterms[i].var), consdata->interiorpoint[i]);
8282  }
8283  }
8284  }
8285  else
8286  {
8287  printf("Computation failed. NLP soltat: %d, termstat: %d\n",
8288  SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
8289  printf("run with SCIP_DEBUG for more info\n");
8290  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
8291  SCIPinfoMessage(scip, NULL, ";\n");
8292  /* FIXME: instance camshape100 says that there is no interior point (interior empty)
8293  * is there something intelligent that can be said?
8294  */
8295  }
8296 #endif
8297 
8298  /* free memory */
8299  SCIPfreeBufferArrayNull(scip, &lbs);
8300  SCIPfreeBufferArrayNull(scip, &ubs);
8301  SCIPfreeBufferArrayNull(scip, &lininds);
8302  SCIPfreeBufferArrayNull(scip, &lincoefs);
8303 
8304  if( prob != NULL )
8305  {
8306  SCIP_CALL( SCIPnlpiFreeProblem(nlpi, &prob) );
8307  }
8308 
8309  return SCIP_OKAY;
8310 }
8311 
8312 /** 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$.
8313  *
8314  * Here, \f$ f(x) \f$ is a purely quadratic (i.e, all \f$x\f$ variables appear in a bilinear or quadratic term).
8315  * Explicitly, \f$ f(x) = \pm x^T A x \pm b^T x \f$ depending whether \f$A\f$
8316  * is positive semidefinite (+) or negative semidefinite (-).
8317  * The constant \f$c\f$ is rhs - maximum activity of the purely linear part of the constraint
8318  * if \f$A \succeq 0\f$ and minimum activity - lhs if \f$A \preceq 0\f$.
8319  * This is computed only at INITSOL.
8320  *
8321  * The method does:
8322  * 1. compute interior point
8323  * 2. compute gauge function
8324  */
8325 static
8327  SCIP* scip, /**< SCIP data structure */
8328  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8329  SCIP_CONS* cons /**< constraint */
8330  )
8331 {
8332  SCIP_CONSHDLRDATA* conshdlrdata;
8333  SCIP_CONSDATA* consdata;
8334  SCIP_QUADVARTERM* quadvarterm;
8335  SCIP_BILINTERM* bilinterm;
8336  SCIP_Bool success;
8337  SCIP_Bool convex;
8338  int i;
8339  int j;
8340 
8341  assert(scip != NULL);
8342  assert(conshdlr != NULL);
8343  assert(cons != NULL);
8344 
8345  consdata = SCIPconsGetData(cons);
8346  assert(consdata != NULL);
8347 
8348  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8349  assert(conshdlrdata != NULL);
8350  assert(conshdlrdata->gaugecuts);
8351 
8352  /* function has to be convex with finite rhs or concave with finite lhs */
8353  convex = consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs);
8354  assert(convex || (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)));
8355 
8356  SCIPdebugMsg(scip, "cons %s: is %s\n", SCIPconsGetName(cons), convex ? "convex" : "concave");
8357 
8358  /* 1. */
8359  SCIP_CALL( computeInteriorPoint(scip, cons, conshdlrdata->interiorcomputation, &success) );
8360 
8361  /* if success, compute gaugecoefs (b_gauge) and gaugeconst (c_gauge) */
8362  if( !success )
8363  {
8364  SCIPdebugMsg(scip, "failed to compute gauge function\n");
8365  consdata->isgaugeavailable = FALSE;
8366  return SCIP_OKAY;
8367  }
8368 
8369  /* 2.
8370  * we are going to evaluate the function at interiorpoint; so, we need to compute interiorpoint^T A interiorpoint;
8371  * therefore, we need a mechanism that for a given variable, it returns its interior point value
8372  * fortunately, sepabilinvar2pos in consdata gives us all the information that we need
8373  */
8374 
8375  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &(consdata->gaugecoefs), consdata->nquadvars) );
8376 
8377  /* compute value of quadratic part at interior point, build map and compute gaugeconst (c_gauge) */
8378  consdata->interiorpointval = 0;
8379  consdata->gaugeconst = 0;
8380  for( i = 0; i < consdata->nquadvars; i++ )
8381  {
8382  SCIP_Real val;
8383  SCIP_Real val2;
8384 
8385  val = consdata->interiorpoint[i];
8386  quadvarterm = &consdata->quadvarterms[i];
8387 
8388  consdata->interiorpointval += (quadvarterm->lincoef + quadvarterm->sqrcoef * val) * val;
8389  consdata->gaugeconst += quadvarterm->sqrcoef * val * val;
8390 
8391  for( j = 0; j < quadvarterm->nadjbilin; ++j )
8392  {
8393  int bilintermidx;
8394 
8395  bilintermidx = quadvarterm->adjbilin[j];
8396  bilinterm = &consdata->bilinterms[bilintermidx];
8397 
8398  if( bilinterm->var1 != quadvarterm->var )
8399  continue;
8400 
8401  /* the index of the variable associated with var2 in bilinterm should be given by sepabilinvar2pos */
8402  assert(consdata->sepabilinvar2pos != NULL); /* this should have been computed in INITSOL */
8403  assert(consdata->quadvarterms[consdata->sepabilinvar2pos[bilintermidx]].var == bilinterm->var2);
8404 
8405  val2 = consdata->interiorpoint[consdata->sepabilinvar2pos[bilintermidx]];
8406 
8407  consdata->interiorpointval += bilinterm->coef * val * val2;
8408  consdata->gaugeconst += bilinterm->coef * val * val2;
8409  }
8410  }
8411 
8412  /* compute gaugecoefs (b_gauge = b + 2 * A * interiorpoint) */
8413  for( i = 0; i < consdata->nquadvars; i++ )
8414  {
8415  quadvarterm = &consdata->quadvarterms[i];
8416  consdata->gaugecoefs[i] += quadvarterm->lincoef + 2.0 * quadvarterm->sqrcoef * consdata->interiorpoint[i];
8417 
8418  for( j = 0; j < quadvarterm->nadjbilin; j++ )
8419  {
8420  int varpos;
8421  int bilintermidx;
8422 
8423  bilintermidx = quadvarterm->adjbilin[j];
8424  bilinterm = &consdata->bilinterms[bilintermidx];
8425 
8426  if( bilinterm->var1 == quadvarterm->var )
8427  {
8428  varpos = consdata->sepabilinvar2pos[bilintermidx];
8429 
8430  /* the index of the variable associated with var2 in bilinterm should be given by sepabilinvar2pos */
8431  assert(consdata->quadvarterms[varpos].var == bilinterm->var2);
8432 
8433  consdata->gaugecoefs[i] += bilinterm->coef * consdata->interiorpoint[varpos];
8434  consdata->gaugecoefs[varpos] += bilinterm->coef * consdata->interiorpoint[i];
8435  }
8436  }
8437  }
8438 
8439 #ifdef SCIP_DEBUG_INT
8440  printf("quadratic part at interior point: %g\n", consdata->interiorpointval);
8441 
8442  for( j = 0; j < consdata->nquadvars; j++ )
8443  {
8444  printf("b_gauge[%s] = %g\n", SCIPvarGetName(consdata->quadvarterms[j].var), consdata->gaugecoefs[j]);
8445  }
8446  printf("c_gauge = %g\n", consdata->gaugeconst);
8447 #endif
8448 
8449  SCIPdebugMsg(scip, "gauge function computed successfully\n");
8450  consdata->isgaugeavailable = TRUE;
8451 
8452  return SCIP_OKAY;
8453 }
8454 
8455 /** 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$.
8456  *
8457  * \f$ S = \{ x : f(x) \le c \}\f$ at \f$sol - s_0\f$;
8458  * see computeGauge() for more details
8459  *
8460  * @todo Think about if user should tell that function is convex or ...
8461  */
8462 static
8464  SCIP* scip, /**< SCIP data structure */
8465  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8466  SCIP_CONS* cons, /**< constraint */
8467  SCIP_SOL* refsol, /**< reference point where to generate cut, or NULL if sol should be used */
8468  SCIP_Real* gaugeval, /**< buffer to store the value of the gauge function */
8469  SCIP_Bool* success /**< buffer to store if evaluation was successful */
8470  )
8471 {
8472  SCIP_CONSDATA* consdata;
8473  SCIP_Real side;
8474  SCIP_Real aterm;
8475  SCIP_Real bterm;
8476  SCIP_Real cterm;
8477  SCIP_Bool convex;
8478  int i;
8479 
8480  assert(scip != NULL);
8481  assert(conshdlr != NULL);
8482  assert(cons != NULL);
8483 
8484  consdata = SCIPconsGetData(cons);
8485  assert(consdata != NULL);
8486  assert(consdata->isgaugeavailable);
8487 
8488  *success = FALSE;
8489 
8490  convex = consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs);
8491 
8492  SCIPdebugMsg(scip, "cons %s: is %s\n", SCIPconsGetName(cons), convex ? "convex" : "concave");
8493 
8494  /* evaluate gauge function at x0 = (refsol - interior point)
8495  *
8496  * compute aterm = side - function(interior point)
8497  */
8498  if( convex )
8499  {
8500  side = consdata->rhs;
8501  for( i = 0; i < consdata->nlinvars; i++ )
8502  side -= SCIPgetSolVal(scip, refsol, consdata->linvars[i]) * consdata->lincoefs[i];
8503 
8504  aterm = side - consdata->interiorpointval;
8505 
8506  /* it can happen that the interior point is not really interior, since we are not so strict at the moment of
8507  * computing the interior point, which makes sense in the case that the constraint is quadratic <= linear expr,
8508  * since we compute a point in quadratic <= min linear expr and it might be that this set consists of a single
8509  * point which will not be interior. furthermore, if this set is empty, we could just take any point and it could
8510  * happen that for some value of linear expr, the point is actually interior, but for many it could not be.
8511  * also, if min linear expr = -infinity, we might have computed an interior point using some finite value.
8512  * the point will not be an interior point, if and only if aterm is negative.
8513  */
8514 #ifdef SCIP_DEBUG_GAUGE
8515  if( SCIPisLE(scip, aterm, 0.0) )
8516  {
8517  printf("For current level, there is no interior point. ");
8518  printf("rhs: %g level: %15.20g interiorpointval: %15.20g\n", consdata->rhs, side, consdata->interiorpointval);
8519  if( consdata->nlinvars == 1 )
8520  {
8521  SCIP_VAR* var;
8522 
8523  var = consdata->linvars[0];
8524  printf("var <%s> = %g in [%15.20g, %15.20g] is linpart\n", SCIPvarGetName(var),
8525  SCIPgetSolVal(scip, refsol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
8526  }
8527  }
8528  else
8529  {
8530  printf("For current level, there is interior point. ");
8531  printf("rhs: %g level: %15.20g interiorpointval: %15.20g\n", consdata->rhs, side, consdata->interiorpointval);
8532  }
8533 #endif
8534  if( !SCIPisPositive(scip, aterm) )
8535  {
8536  *gaugeval = -1.0;
8537  return SCIP_OKAY;
8538  }
8539  }
8540  else
8541  {
8542  side = consdata->lhs;
8543  for( i = 0; i < consdata->nlinvars; i++ )
8544  side -= SCIPgetSolVal(scip, refsol, consdata->linvars[i]) * consdata->lincoefs[i];
8545 
8546  aterm = side - consdata->interiorpointval;
8547 
8548 #ifdef SCIP_DEBUG_GAUGE
8549  if( SCIPisGE(scip, aterm, 0.0) )
8550  {
8551  printf("For current level, there is no interior point. ");
8552  printf("lhs: %g level: %15.20g interiorpointval: %15.20g\n", consdata->lhs, side, consdata->interiorpointval);
8553  if( consdata->nlinvars == 1 )
8554  {
8555  SCIP_VAR* var;
8556 
8557  var = consdata->linvars[0];
8558  printf("var <%s> = %g in [%15.20g, %15.20g] is linpart\n", SCIPvarGetName(var),
8559  SCIPgetSolVal(scip, refsol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
8560  }
8561  }
8562  else
8563  {
8564  printf("For current level, there is interior point. ");
8565  printf("lhs: %g level: %15.20g interiorpointval: %15.20g\n", consdata->lhs, side, consdata->interiorpointval);
8566  }
8567 #endif
8568  if( !SCIPisNegative(scip, aterm) )
8569  {
8570  *gaugeval = -1.0;
8571  return SCIP_OKAY;
8572  }
8573  }
8574 
8575  /* compute bterm = b_gauge^T * refsol - f(interiorpoint) - c_gauge
8576  * compute cterm = f(refsol) - b_gauge^T * refsol + c_gauge */
8577  bterm = -consdata->interiorpointval - consdata->gaugeconst;
8578  cterm = consdata->gaugeconst;
8579  for( i = 0; i < consdata->nquadvars; i++ )
8580  {
8581  SCIP_Real val;
8582 
8583  val = SCIPgetSolVal(scip, refsol, consdata->quadvarterms[i].var);
8584  bterm += consdata->gaugecoefs[i] * val;
8585  cterm -= consdata->gaugecoefs[i] * val;
8586  cterm += (consdata->quadvarterms[i].lincoef + consdata->quadvarterms[i].sqrcoef * val) * val;
8587  }
8588 
8589  for( i = 0; i < consdata->nbilinterms; i++ )
8590  {
8591  SCIP_VAR* var1;
8592  SCIP_VAR* var2;
8593 
8594  var1 = consdata->bilinterms[i].var1;
8595  var2 = consdata->bilinterms[i].var2;
8596  cterm += consdata->bilinterms[i].coef * SCIPgetSolVal(scip, refsol, var1) * SCIPgetSolVal(scip, refsol, var2);
8597  }
8598 
8599  /* now compute gauge */
8600  if( convex && cterm < 0.0 )
8601  {
8602  assert(SCIPisZero(scip, cterm));
8603  cterm = 0.0;
8604  }
8605  else if( !convex && cterm > 0.0 )
8606  {
8607  assert(SCIPisZero(scip, cterm));
8608  cterm = 0.0;
8609  }
8610  assert(bterm*bterm + 4*aterm*cterm >= 0);
8611 
8612  if( convex )
8613  {
8614  *gaugeval = bterm + sqrt(bterm*bterm + 4 * aterm * cterm);
8615  *gaugeval = *gaugeval / (2 * aterm);
8616  }
8617  else
8618  {
8619  *gaugeval = bterm - sqrt(bterm*bterm + 4 * aterm * cterm);
8620  *gaugeval = *gaugeval / (2 * aterm);
8621  }
8622  assert(!SCIPisNegative(scip, *gaugeval));
8623  *success = TRUE;
8624 
8625 #ifdef SCIP_DEBUG_GAUGE
8626  printf("Gauge's aterm = %g, bterm = %g, cterm = %g\n", aterm, bterm, cterm);
8627 #endif
8628  return SCIP_OKAY;
8629 }
8630 
8631 /** compute projection of refsol onto feasible region of cons; stores the projection in ref
8632  *
8633  * This method solves
8634  * \f[
8635  * \min \{ ||x - \bar x||^2 : x^T A x + 2 b^T x \le c \}
8636  * \f]
8637  * where \f$ \bar x \f$ is refsol.
8638  * Note that \f$ \bar x \f$ is not feasible, so the optimal solution actually satisfies
8639  * \f[
8640  * \min \{ ||x - \bar x||^2 : x^T A x + 2 b^T x = c \}
8641  * \f]
8642  * Using the eigendecomposition \f$ A = P D P^T \f$, the change of variables \f$ y = P^T x
8643  * \f$ and the optimality conditions, this reduces to finding \f$ \rho \f$ such that
8644  * \f[
8645  * y(\rho) = (I + \rho D)^{-1} (\bar y - \rho \bar b)
8646  * \f]
8647  * 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$
8648  * D \neq 0 \f$, the function
8649  * \f[
8650  * \varphi(\rho) := y(\rho)^T D y(\rho) + 2 \bar b^T y(\rho) - c
8651  * \f]
8652  * is strictly convex. So this method actually computes the unique 0 of this function using Newton's method.
8653  */
8654 static
8656  SCIP* scip, /**< SCIP data structure */
8657  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8658  SCIP_CONS* cons, /**< constraint */
8659  SCIP_SOL* refsol, /**< the given point to project, or NULL if LP solution should be used */
8660  SCIP_Real* ref /**< array to store reference point */
8661  )
8662 {
8663  SCIP_CONSDATA* consdata;
8664  SCIP_Real* pt; /* stores P^T */
8665  SCIP_Real* bp;
8666  SCIP_Real* D;
8667  SCIP_Real* y0_;
8668  SCIP_Real* yrho;
8669  SCIP_Real* yrhoprime;
8670  SCIP_Real c;
8671  SCIP_Real c1;
8672  SCIP_Real c2;
8673  SCIP_Real rho;
8674  SCIP_Real phirho;
8675  SCIP_Real phirhoprime;
8676  SCIP_Bool isconcave;
8677  int iter;
8678  int i;
8679  int j;
8680  int n;
8681 
8682  assert(scip != NULL);
8683  assert(conshdlr != NULL);
8684  assert(cons != NULL);
8685 
8686  consdata = SCIPconsGetData(cons);
8687  assert(consdata != NULL);
8688  assert(consdata->isedavailable);
8689 
8690  SCIPdebugMessage("computing projection\n");
8691 
8692  /* get the data we need */
8693  pt = consdata->eigenvectors;
8694  D = consdata->eigenvalues;
8695  n = consdata->nquadvars;
8696  bp = consdata->bp;
8697  c = consdata->rhs;
8698  c1 = 0;
8699  c2 = 0;
8700  for( i = 0; i < consdata->nlinvars; i++ )
8701  {
8702  c1 += consdata->lincoefs[i] * SCIPgetSolVal(scip, refsol, consdata->linvars[i]);
8703  c2 -= consdata->lincoefs[i] * consdata->lincoefs[i];
8704  }
8705  c2 /= 2.0;
8706 
8707  /* determine if convex or concave */
8708  isconcave = consdata->isconcave;
8709  assert((isconcave && !SCIPisInfinity(scip, -consdata->lhs)) || !SCIPisInfinity(scip, consdata->rhs));
8710 
8711  SCIP_CALL( SCIPallocClearBufferArray(scip, &y0_, n) );
8712  SCIP_CALL( SCIPallocBufferArray(scip, &yrho, n) );
8713  SCIP_CALL( SCIPallocBufferArray(scip, &yrhoprime, n) );
8714 
8715  /* change data if function is concave */
8716  if( isconcave )
8717  {
8718  c = -consdata->lhs;
8719  c1 = - c1;
8720  for( i = 0; i < n; i++ )
8721  {
8722  D[i] = -D[i];
8723  bp[i] = -bp[i];
8724  }
8725  }
8726 
8727  /* change coordinates: compute y(0) = x_0' * P */
8728  for( i = 0; i < n; i++ )
8729  for( j = 0; j < n; j++ )
8730  y0_[i] += SCIPgetSolVal(scip, refsol, consdata->quadvarterms[j].var) * pt[i*n + j];
8731 
8732 #ifdef DEBUG_PROJ
8733  /* debug output */
8734  printf("\nP^T:\n");
8735  for( i = 0; i < n; i++ )
8736  {
8737  for( j = 0; j < n; j++ )
8738  printf("%g ", pt[i*n + j]);
8739  printf("\n");
8740  }
8741  printf("x_0: ");
8742  for( i = 0; i < n; i++ )
8743  printf("%g ", SCIPgetSolVal(scip, refsol, consdata->quadvarterms[i].var));
8744  printf("\n");
8745  printf("P^T x_0: ");
8746  for( i = 0; i < n; i++ )
8747  printf("%g ", y0_[i]);
8748  printf("\n");
8749  printf("P^T b: ");
8750  for( i = 0; i < n; i++ )
8751  printf("%g ", bp[i]);
8752  printf("\n");
8753  printf("<d,linvars> = %g\n", c1);
8754  printf("-norm(d)^2/2 = %g\n", c2);
8755 #endif
8756 
8757  /* perform newton's method: rho^+ = rho - phi(rho)/phi'(rho) */
8758  rho = 0.0;
8759  phirho = c;
8760  phirhoprime = 1.0;
8761  for( iter = 0; iter < 9; iter++ )
8762  {
8763  assert(phirhoprime != 0.0);
8764  rho = rho - (phirho - c)/ phirhoprime;
8765 
8766  /* compute phi(rho) and phi'(rho):
8767  * note that formulas were deduced for constraints of the form x' A x + 2 b x, so we use b/2 in the formulas:
8768  * c1 = <lin_coefs, sol_lin_vars>
8769  * c2 = - norm(lin_coefs)^2/2
8770  * y(rho) = (I + rho * D)^-1 * (y(0) - rho * bp/2)
8771  * y'(rho) = -(I + rho * D)^-2 * (D y(0) + bp/2)
8772  * phi(rho) = <y(rho), D * y(rho) + pb> + c1 + c2*rho
8773  * phi'(rho) = <y'(rho), 2 * D * y(rho) + pb> + c2
8774  */
8775  phirho = 0.0;
8776  phirhoprime = 0.0;
8777  for( i = 0; i < n; i++ )
8778  {
8779  assert(1.0 + rho * D[i] != 0.0);
8780  yrho[i] = (y0_[i] - rho * bp[i]/2.0) / (1.0 + rho * D[i]);
8781  yrhoprime[i] = -(D[i] * y0_[i] + bp[i]/2.0) / ( (1.0 + rho * D[i])*(1.0 + rho * D[i]) );
8782  phirho += yrho[i] * (yrho[i] * D[i] + bp[i]);
8783  phirhoprime += yrhoprime[i] * (2 * D[i] * yrho[i] + bp[i]);
8784  }
8785  phirho += c2 * rho + c1;
8786  phirhoprime += c2;
8787 #ifdef DEBUG_PROJ
8788  printf("iteration %d: rho = %g, phirho = %g, phirho' = %g\n", iter, rho, phirho, phirhoprime);
8789 #endif
8790  }
8791 
8792  /* come back to the original coordinates: new ref point is P*yrho */
8793  for( i = 0; i < n; i++ )
8794  {
8795  ref[i] = 0.0;
8796 
8797  for( j = 0; j < n; j++ )
8798  ref[i] += pt[j*n + i] * yrho[j];
8799  }
8800 
8801  /* change data back if function is concave */
8802  if( isconcave )
8803  {
8804  for( i = 0; i < n; i++ )
8805  {
8806  D[i] = -D[i];
8807  bp[i] = -bp[i];
8808  }
8809  }
8810 
8811 #ifdef SCIP_DISABLED_CODE
8812  /* project onto bounds; this is important for some cut generation methods such as generateCutLTI */
8813  for( j = 0; j < consdata->nquadvars; ++j )
8814  {
8815  SCIP_Real lb;
8816  SCIP_Real ub;
8817  SCIP_VAR* var;
8818 
8819  var = consdata->quadvarterms[j].var;
8820  lb = SCIPvarGetLbLocal(var);
8821  ub = SCIPvarGetUbLocal(var);
8822  /* do not like variables at infinity */
8823  assert(!SCIPisInfinity(scip, lb));
8824  assert(!SCIPisInfinity(scip, -ub));
8825 
8826  ref[j] = MIN(ub, MAX(lb, ref[j])); /* project value into bounds */
8827  }
8828 #endif
8829 
8830 #ifdef DEBUG_PROJ
8831  printf("modified reference point by a projection:\n");
8832  for( j = 0; j < consdata->nquadvars; ++j )
8833  {
8834  printf("%s = %g\n", SCIPvarGetName(consdata->quadvarterms[j].var), ref[j]);
8835  }
8836 #endif
8837 
8838  SCIPfreeBufferArray(scip, &y0_);
8839  SCIPfreeBufferArray(scip, &yrho);
8840  SCIPfreeBufferArray(scip, &yrhoprime);
8841 
8842  return SCIP_OKAY;
8843 }
8844 
8845 /** compute reference point suggested by gauge function */
8846 static
8848  SCIP* scip, /**< SCIP data structure */
8849  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8850  SCIP_CONS* cons, /**< constraint */
8851  SCIP_SOL* refsol, /**< reference point where to compute gauge, or NULL if LP solution should be used */
8852  SCIP_Real* ref, /**< array to store reference point */
8853  SCIP_Bool* success /**< buffer to store whether we succeeded computing reference point */
8854  )
8855 {
8856  SCIP_CONSDATA* consdata;
8857  SCIP_Real gaugeval;
8858  SCIP_Real intpoint;
8859  SCIP_Real lb;
8860  SCIP_Real ub;
8861  SCIP_VAR* var;
8862  int j;
8863 
8864  assert(scip != NULL);
8865  assert(conshdlr != NULL);
8866  assert(cons != NULL);
8867 
8868  consdata = SCIPconsGetData(cons);
8869  assert(consdata != NULL);
8870  assert(consdata->isgaugeavailable);
8871 
8872  SCIPdebugMsg(scip, "evaluating gauge\n");
8873  SCIP_CALL( evaluateGauge(scip, conshdlr, cons, refsol, &gaugeval, success) );
8874 
8875  if( !(*success) )
8876  {
8877 #ifdef SCIP_DEBUG_GAUGE
8878  printf("Couldn't evaluate gauge!\n");
8879 #endif
8880  return SCIP_OKAY;
8881  }
8882 
8883 #ifdef SCIP_DEBUG_GAUGE
8884  {
8885  SCIP_Real level;
8886 
8887  level = consdata->rhs;
8888  for( j = 0; j < consdata->nlinvars; j++ )
8889  level -= SCIPgetSolVal(scip, refsol, consdata->linvars[j]) * consdata->lincoefs[j];
8890 
8891  printf("Summary:\n");
8892  printf("For cons <%s>: gauge at level %g evaluated at (refsol - intpoint) is %.10f\n",
8893  SCIPconsGetName(cons), level, gaugeval);
8894  printf("refsol - intpoint:\n");
8895 
8896  for( j = 0; j < consdata->nquadvars; ++j )
8897  {
8898  SCIP_VAR* vvar;
8899  vvar = consdata->quadvarterms[j].var;
8900  printf("%s: % 20.15g - %g = %g\n", SCIPvarGetName(vvar), SCIPgetSolVal(scip, refsol, vvar),
8901  consdata->interiorpoint[j], SCIPgetSolVal(scip, refsol, vvar) - consdata->interiorpoint[j]);
8902  }
8903  if( SCIPisFeasLE(scip, gaugeval, 1.0) )
8904  printf("refsol is in the closure of the region (gaugeval <= 1), don't modify reference point\n");
8905  }
8906 #endif
8907 
8908  /* scale gauge value so that final point is close to the boundary, but not on the boundary (weakens the cut) */
8909  gaugeval *= GAUGESCALE;
8910 
8911  /* if the point is not sufficiently violated, we don't modify it */
8912  if( SCIPisFeasLE(scip, gaugeval, 1.0) )
8913  {
8914  *success = FALSE;
8915  return SCIP_OKAY;
8916  }
8917 
8918  /* set reference to (refsol - interior point)/gaugeval + interior point and project onto bounds this is important for
8919  * some cut generation methods such as generateCutLTI
8920  * @todo remove the projection onto the bounds; generateCutLTI shouldn't be called for convex constraints
8921  */
8922  for( j = 0; j < consdata->nquadvars; ++j )
8923  {
8924  var = consdata->quadvarterms[j].var;
8925  lb = SCIPvarGetLbLocal(var);
8926  ub = SCIPvarGetUbLocal(var);
8927  /* do not like variables at infinity */
8928  assert(!SCIPisInfinity(scip, lb));
8929  assert(!SCIPisInfinity(scip, -ub));
8930 
8931  intpoint = consdata->interiorpoint[j];
8932  ref[j] = (SCIPgetSolVal(scip, refsol, var) - intpoint) / gaugeval + intpoint;
8933  ref[j] = MIN(ub, MAX(lb, ref[j])); /* project value into bounds */
8934  }
8935 
8936 #ifdef SCIP_DEBUG_GAUGE
8937  printf("successful application of guage: %g\n", gaugeval);
8938  printf("modified reference point:\n");
8939  for( j = 0; j < consdata->nquadvars; ++j )
8940  {
8941  printf("%s = % 20.15g\n", SCIPvarGetName(consdata->quadvarterms[j].var), ref[j]);
8942  }
8943 #endif
8944 
8945  return SCIP_OKAY;
8946 }
8947 
8948 /** generates a cut based on linearization (if convex) or McCormick (if nonconvex) in a solution
8949  * @note mode indicates whether we should modify the point we want to cutoff (sol) via gauge or projection,
8950  * or if just normal linearization should be use, or the default way (whatever is specified via settings)
8951  */
8952 static
8954  SCIP* scip, /**< SCIP data structure */
8955  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8956  SCIP_CONS* cons, /**< constraint */
8957  SCIP_SOL* sol, /**< solution where to generate cut, or NULL if LP solution should be used */
8958  SCIP_SOL* refsol, /**< reference point where to generate cut, or NULL if sol should be used */
8959  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
8960  SCIP_ROW** row, /**< storage for cut */
8961  SCIP_Real* efficacy, /**< buffer to store efficacy of row in reference solution, or NULL if not of interest */
8962  SCIP_Bool checkcurvmultivar, /**< are we allowed to check the curvature of a multivariate quadratic function, if not done yet */
8963  SCIP_Real minefficacy, /**< minimal required efficacy */
8964  char mode /**< mode of execution 'g'auge, 'p'rojection, 'l'inearization gradient, 'd'efault */
8965  )
8966 {
8967  SCIP_CONSHDLRDATA* conshdlrdata;
8968  SCIP_CONSDATA* consdata;
8969  SCIP_VAR* var;
8970  SCIP_Real lb;
8971  SCIP_Real ub;
8972  SCIP_Real* ref;
8973  SCIP_Bool success;
8974  int j;
8975 
8976  assert(scip != NULL);
8977  assert(conshdlr != NULL);
8978  assert(cons != NULL);
8979 
8980  consdata = SCIPconsGetData(cons);
8981  assert(consdata != NULL);
8982 
8983  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8984  assert(conshdlrdata != NULL);
8985 
8986  if( refsol == NULL )
8987  refsol = sol;
8988 
8989  /* get reference point */
8990  SCIP_CALL( SCIPallocBufferArray(scip, &ref, consdata->nquadvars) );
8991  success = FALSE;
8992 
8993  if( mode == 'd')
8994  {
8995  if( (consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) ||
8996  (consdata->isconcave && violside == SCIP_SIDETYPE_LEFT) )
8997  {
8998  if( conshdlrdata->gaugecuts && consdata->isgaugeavailable )
8999  {
9000  SCIP_CALL( computeReferencePointGauge(scip, conshdlr, cons, refsol, ref, &success) );
9001  }
9002  else if( conshdlrdata->projectedcuts && consdata->isedavailable )
9003  {
9004  SCIPdebugMessage("use the projection of refsol onto the region defined by the constraint as reference point\n");
9005  SCIP_CALL( computeReferencePointProjection(scip, conshdlr, cons, refsol, ref) );
9006  success = TRUE;
9007  }
9008  }
9009 
9010  if( success )
9011  {
9012  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
9013 
9014  /* if cut fails, try again without modifying reference point */
9015  if( *row == NULL || (efficacy != NULL && !SCIPisGT(scip, *efficacy, minefficacy)) || !SCIPisCutApplicable(scip, *row) ) /*lint !e644 */
9016  {
9017  SCIPdebugMsg(scip, "%s cut fail, try without modifying\n", conshdlrdata->gaugecuts ? "gauge" : "projected");
9018  success = FALSE;
9019  }
9020  }
9021 
9022  /* note that this is not the same as calling this method with mode 'l', 'l' assume convex/concave function */
9023  if( !success )
9024  {
9025  for( j = 0; j < consdata->nquadvars; ++j )
9026  {
9027  var = consdata->quadvarterms[j].var;
9028  lb = SCIPvarGetLbLocal(var);
9029  ub = SCIPvarGetUbLocal(var);
9030  /* do not like variables at infinity */
9031  assert(!SCIPisInfinity(scip, lb));
9032  assert(!SCIPisInfinity(scip, -ub));
9033 
9034  ref[j] = SCIPgetSolVal(scip, refsol, var);
9035  ref[j] = MIN(ub, MAX(lb, ref[j])); /* project value into bounds */
9036  }
9037 
9038  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
9039  }
9040  }
9041  /* gauge cut */
9042  if( mode == 'g' )
9043  {
9044  assert((consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) || (consdata->isconcave && violside == SCIP_SIDETYPE_LEFT));
9045  if( conshdlrdata->gaugecuts && consdata->isgaugeavailable )
9046  {
9047  SCIP_CALL( computeReferencePointGauge(scip, conshdlr, cons, refsol, ref, &success) );
9048  }
9049  if( success )
9050  {
9051  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
9052  }
9053  }
9054  /* projection cut */
9055  if( mode == 'p' )
9056  {
9057  assert((consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) || (consdata->isconcave && violside == SCIP_SIDETYPE_LEFT));
9058  if( conshdlrdata->projectedcuts && consdata->isedavailable )
9059  {
9060  SCIP_CALL( computeReferencePointProjection(scip, conshdlr, cons, refsol, ref) );
9061  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
9062  }
9063  }
9064  /* gradient linearization cut at refsol */
9065  if( mode == 'l' )
9066  {
9067  assert((consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) || (consdata->isconcave && violside == SCIP_SIDETYPE_LEFT));
9068  for( j = 0; j < consdata->nquadvars; ++j )
9069  {
9070  var = consdata->quadvarterms[j].var;
9071  lb = SCIPvarGetLbLocal(var);
9072  ub = SCIPvarGetUbLocal(var);
9073  /* do not like variables at infinity */
9074  assert(!SCIPisInfinity(scip, lb));
9075  assert(!SCIPisInfinity(scip, -ub));
9076 
9077  ref[j] = SCIPgetSolVal(scip, refsol, var);
9078  ref[j] = MIN(ub, MAX(lb, ref[j])); /* project value into bounds */
9079  }
9080  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
9081  }
9082 
9083  SCIPfreeBufferArray(scip, &ref);
9084 
9085  return SCIP_OKAY;
9086 }
9087 
9088 /** tries to find a cut that intersects with an unbounded ray of the LP
9089  *
9090  * For convex functions, we do this by linearizing in the feasible solution of the LPI.
9091  * For nonconvex functions, we just call generateCutSol with the unbounded solution as reference point.
9092  */
9093 static
9095  SCIP* scip, /**< SCIP data structure */
9096  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9097  SCIP_CONS* cons, /**< constraint */
9098  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
9099  SCIP_ROW** row, /**< storage for cut */
9100  SCIP_Real* rowrayprod, /**< buffer to store product of ray with row coefficients, or NULL if not of interest */
9101  SCIP_Bool checkcurvmultivar /**< are we allowed to check the curvature of a multivariate quadratic function, if not done yet */
9102  )
9103 {
9104  SCIP_CONSDATA* consdata;
9105  SCIP_BILINTERM* bilinterm;
9106  SCIP_VAR* var;
9107  SCIP_Real* ref;
9108  SCIP_Real matrixrayprod;
9109  SCIP_Real linrayprod;
9110  SCIP_Real quadrayprod;
9111  SCIP_Real rayval;
9112  int i;
9113  int j;
9114 
9115  assert(scip != NULL);
9116  assert(conshdlr != NULL);
9117  assert(cons != NULL);
9118  assert(row != NULL);
9120 
9121  consdata = SCIPconsGetData(cons);
9122  assert(consdata != NULL);
9123 
9124  *row = NULL;
9125 
9126  if( !SCIPhasPrimalRay(scip) )
9127  {
9128  SCIPdebugMsg(scip, "do not have primal ray, thus cannot resolve unboundedness\n");
9129  return SCIP_OKAY;
9130  }
9131 
9132  SCIP_CALL( checkCurvature(scip, cons, checkcurvmultivar) );
9133  if( (!consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) ||
9134  (!consdata->isconcave && violside == SCIP_SIDETYPE_LEFT) )
9135  {
9136  /* if not convex, just call generateCut and hope it's getting something useful */
9137  SCIP_CALL( generateCutSol(scip, conshdlr, cons, NULL, NULL, violside, row, NULL, FALSE, -SCIPinfinity(scip), 'd') );
9138 
9139  /* compute product of cut coefficients with ray, if required */
9140  if( *row != NULL && rowrayprod != NULL )
9141  {
9142  *rowrayprod = 0.0;
9143  for( i = 0; i < SCIProwGetNNonz(*row); ++i )
9144  {
9145  assert(SCIProwGetCols(*row)[i] != NULL);
9146  var = SCIPcolGetVar(SCIProwGetCols(*row)[i]);
9147  assert(var != NULL);
9148 
9149  *rowrayprod += SCIProwGetVals(*row)[i] * SCIPgetPrimalRayVal(scip, var);
9150  }
9151  }
9152 
9153  return SCIP_OKAY;
9154  }
9155 
9156  /* we seek for a linearization of the quadratic function such that it intersects with the unbounded ray
9157  * that is, we need a reference point ref such that for the gradient g of xAx+bx in ref, we have
9158  * <g, ray> > 0.0 if rhs is finite and <g, ray> < 0.0 if lhs is finite
9159  * Since g = 2*A*ref + b, we have <g, ray> = <2*A*ref + b, ray> = <ref, 2*A*ray> + <b,ray>
9160  * 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)
9161  * <ref, 2*A*ray> + <b,ray> is sufficiently larger 0.0, we call generateCut for this point, otherwise, we scale up ref
9162  */
9163 
9164  quadrayprod = 0.0; /* <ref, 2*A*ray> */
9165  linrayprod = 0.0; /* <b, ray> */
9166  SCIP_CALL( SCIPallocBufferArray(scip, &ref, consdata->nquadvars) );
9167  for( i = 0; i < consdata->nquadvars; ++i )
9168  {
9169  var = consdata->quadvarterms[i].var;
9170  rayval = SCIPgetPrimalRayVal(scip, var);
9171 
9172  /* compute i-th entry of (2*A*ray) */
9173  matrixrayprod = 2.0 * consdata->quadvarterms[i].sqrcoef * rayval;
9174  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
9175  {
9176  bilinterm = &consdata->bilinterms[consdata->quadvarterms[i].adjbilin[j]];
9177  matrixrayprod += bilinterm->coef * SCIPgetPrimalRayVal(scip, bilinterm->var1 == var ? bilinterm->var2 : bilinterm->var1);
9178  }
9179 
9180  if( SCIPisPositive(scip, matrixrayprod) )
9181  ref[i] = (violside == SCIP_SIDETYPE_RIGHT ? 1.0 : -1.0);
9182  else if( SCIPisNegative(scip, matrixrayprod) )
9183  ref[i] = (violside == SCIP_SIDETYPE_RIGHT ? -1.0 : 1.0);
9184  else
9185  ref[i] = 0.0;
9186 
9187  quadrayprod += matrixrayprod * ref[i];
9188  linrayprod += consdata->quadvarterms[i].lincoef * rayval;
9189  }
9190  assert((violside == SCIP_SIDETYPE_RIGHT && quadrayprod >= 0.0) || (violside == SCIP_SIDETYPE_LEFT && quadrayprod <= 0.0));
9191 
9192  if( SCIPisZero(scip, quadrayprod) )
9193  {
9194  SCIPdebugMsg(scip, "ray is zero along cons <%s>\n", SCIPconsGetName(cons));
9195  SCIPfreeBufferArray(scip, &ref);
9196  return SCIP_OKAY;
9197  }
9198 
9199  /* add linear part to linrayprod */
9200  for( i = 0; i < consdata->nlinvars; ++i )
9201  linrayprod += consdata->lincoefs[i] * SCIPgetPrimalRayVal(scip, consdata->linvars[i]);
9202 
9203  SCIPdebugMsg(scip, "initially have <b,ray> = %g and <ref, 2*A*ref> = %g\n", linrayprod, quadrayprod);
9204 
9205  /* 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
9206  * if <b,ray> is zero, then we scale refpoint up if |<ref, 2*A*ray>| < 1.0
9207  */
9208  if( (!SCIPisZero(scip, linrayprod) && violside == SCIP_SIDETYPE_RIGHT && quadrayprod < -2*linrayprod) ||
9209  ( !SCIPisZero(scip, linrayprod) && violside == SCIP_SIDETYPE_LEFT && quadrayprod > -2*linrayprod) ||
9210  (SCIPisZero(scip, linrayprod) && REALABS(quadrayprod) < 1.0) )
9211  {
9212  SCIP_Real scale;
9213 
9214  if( !SCIPisZero(scip, linrayprod) )
9215  scale = 2*REALABS(linrayprod/quadrayprod); /*lint !e795 */
9216  else
9217  scale = 1.0/REALABS(quadrayprod);
9218 
9219  SCIPdebugMsg(scip, "scale refpoint by %g\n", scale);
9220  for( i = 0; i < consdata->nquadvars; ++i )
9221  ref[i] *= scale;
9222  quadrayprod *= scale;
9223  }
9224 
9225  if( rowrayprod != NULL )
9226  *rowrayprod = quadrayprod + linrayprod;
9227 
9228  SCIPdebugMsg(scip, "calling generateCut, expecting ray product %g\n", quadrayprod + linrayprod);
9229  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, NULL, violside, row, NULL, FALSE, -SCIPinfinity(scip)) );
9230 
9231  SCIPfreeBufferArray(scip, &ref);
9232 
9233  return SCIP_OKAY;
9234 }
9235 
9236 /** processes a cut for constraint cons, i.e., checks numerics and possibly adds cut to sepastore */
9237 static
9239  SCIP* scip, /**< SCIP data structure */
9240  SCIP_ROW** row, /**< cut to process */
9241  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
9242  SCIP_CONS* cons, /**< constraint */
9243  SCIP_Real efficacy, /**< efficacy of row in reference solution */
9244  SCIP_Real minefficacy, /**< minimal efficacy */
9245  SCIP_Bool inenforcement, /**< whether we are in constraint enforcement */
9246  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 */
9247  SCIP_RESULT* result /**< result of separation */
9248  )
9249 {
9250  SCIP_CONSDATA* consdata;
9251  SCIP_CONSHDLRDATA* conshdlrdata;
9252 
9253  assert(scip != NULL);
9254  assert(row != NULL);
9255  assert(conshdlr != NULL);
9256  assert(result != NULL);
9257  assert(cons != NULL);
9258 
9259  /* no cut to process */
9260  if( *row == NULL )
9261  return SCIP_OKAY;
9262 
9263  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9264  assert(conshdlrdata != NULL);
9265 
9266  consdata = SCIPconsGetData(cons);
9267  assert(consdata != NULL);
9268 
9269  if( SCIPisGT(scip, efficacy, minefficacy) && SCIPisCutApplicable(scip, *row) ) /*lint !e644 */
9270  {
9271  SCIP_Bool infeasible;
9272 
9273  /* cut cuts off solution */
9274  SCIP_CALL( SCIPaddRow(scip, *row, FALSE /* forcecut */, &infeasible) );
9275  if( infeasible )
9276  {
9277  SCIPdebugMessage("cut for constraint <%s> is infeasible -> cutoff.\n", SCIPconsGetName(cons));
9278  *result = SCIP_CUTOFF;
9279  }
9280  else
9281  {
9282  SCIPdebugMessage("add cut with efficacy %g for constraint <%s> violated by %g\n", efficacy,
9283  SCIPconsGetName(cons), consdata->lhsviol+consdata->rhsviol);
9284  *result = SCIP_SEPARATED;
9285  }
9286  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9287 
9288  /* mark row as not removable from LP for current node, if in enforcement */
9289  if( inenforcement && !conshdlrdata->enfocutsremovable )
9290  SCIPmarkRowNotRemovableLocal(scip, *row);
9291  }
9292  if( bestefficacy != NULL && efficacy > *bestefficacy )
9293  *bestefficacy = efficacy;
9294 
9295  SCIP_CALL( SCIPreleaseRow (scip, row) );
9296  return SCIP_OKAY;
9297 }
9298 
9299 /** tries to separate solution or LP solution by a linear cut
9300  *
9301  * assumes that constraint violations have been computed
9302  */
9303 static
9305  SCIP* scip, /**< SCIP data structure */
9306  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
9307  SCIP_CONS** conss, /**< constraints */
9308  int nconss, /**< number of constraints */
9309  int nusefulconss, /**< number of constraints that seem to be useful */
9310  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
9311  SCIP_Real minefficacy, /**< minimal efficacy of a cut if it should be added to the LP */
9312  SCIP_Bool inenforcement, /**< whether we are in constraint enforcement */
9313  SCIP_RESULT* result, /**< result of separation */
9314  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 */
9315  )
9316 {
9317  SCIP_CONSHDLRDATA* conshdlrdata;
9318  SCIP_CONSDATA* consdata;
9319  SCIP_Real efficacy;
9320  SCIP_SIDETYPE violside;
9321  int c;
9322  SCIP_ROW* row;
9323 
9324  assert(scip != NULL);
9325  assert(conshdlr != NULL);
9326  assert(conss != NULL || nconss == 0);
9327  assert(nusefulconss <= nconss);
9328  assert(result != NULL);
9329 
9330  *result = SCIP_FEASIBLE;
9331 
9332  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9333  assert(conshdlrdata != NULL);
9334 
9335  if( bestefficacy != NULL )
9336  *bestefficacy = 0.0;
9337 
9338  row = NULL;
9339  /* loop over both sides of each constraint */
9340  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) )
9341  {
9342  assert(conss != NULL);
9343  consdata = SCIPconsGetData(conss[c]);
9344  assert(consdata != NULL);
9345 
9346  /* if side not violated, then go on */
9347  if( !SCIPisGT(scip, violside == SCIP_SIDETYPE_LEFT ? consdata->lhsviol : consdata->rhsviol, SCIPfeastol(scip)) )
9348  continue;
9349 
9350  /* we are not feasible anymore */
9351  if( *result == SCIP_FEASIBLE )
9352  *result = SCIP_DIDNOTFIND;
9353 
9354  /* generate cut */
9355  if( sol == NULL && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY )
9356  {
9357  /* if the LP is unbounded, then we need a cut that cuts into the direction of a hopefully existing primal ray
9358  * 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
9359  * given a cut lhs <= <c,x> <= rhs, we check whether it imposes an upper bound on t and thus bounds the ray
9360  * 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>
9361  * similar, lhs > -infinity and <c,r> < 0 is good
9362  */
9363  SCIP_Real rayprod;
9364 
9365  rayprod = 0.0; /* for compiler */
9366  SCIP_CALL( generateCutUnboundedLP(scip, conshdlr, conss[c], violside, &row, &rayprod, conshdlrdata->checkcurvature) );
9367 
9368  if( row != NULL )
9369  {
9370  if( !SCIPisInfinity(scip, SCIProwGetRhs(row)) && SCIPisPositive(scip, rayprod) )
9371  efficacy = rayprod;
9372  else if( !SCIPisInfinity(scip, -SCIProwGetLhs(row)) && SCIPisNegative(scip, rayprod) )
9373  efficacy = -rayprod;
9374  else
9375  efficacy = 0.0;
9376 
9377  SCIP_CALL( processCut(scip, &row, conshdlr, conss[c], efficacy, minefficacy, inenforcement, bestefficacy, result) );
9378  }
9379  continue;
9380  }
9381  else
9382  {
9383  SCIP_CALL( generateCutSol(scip, conshdlr, conss[c], sol, NULL, violside, &row, &efficacy,
9384  conshdlrdata->checkcurvature, minefficacy, 'd') );
9385 
9386  SCIP_CALL( processCut(scip, &row, conshdlr, conss[c], efficacy, minefficacy, inenforcement, bestefficacy, result) );
9387  }
9388 
9389  if( *result == SCIP_CUTOFF )
9390  break;
9391 
9392  /* enforce only useful constraints
9393  * others are only checked and enforced if we are still feasible or have not found a separating cut yet
9394  */
9395  if( c >= nusefulconss && *result == SCIP_SEPARATED )
9396  break;
9397  }
9398 
9399  return SCIP_OKAY;
9400 }
9401 
9402 /** adds linearizations cuts for convex constraints w.r.t. a given reference point to cutpool and sepastore
9403  *
9404  * - 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.
9405  * - If separatedlpsol is not NULL, but cut does not separate the LP solution, then it is added to the cutpool only.
9406  * - If separatedlpsol is NULL, then cut is added to cutpool only.
9407  */
9408 static
9410  SCIP* scip, /**< SCIP data structure */
9411  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
9412  SCIP_CONS** conss, /**< constraints */
9413  int nconss, /**< number of constraints */
9414  SCIP_SOL* ref, /**< reference point where to linearize, or NULL for LP solution */
9415  SCIP_Bool* separatedlpsol, /**< buffer to store whether a cut that separates the current LP solution was found and added to LP,
9416  * or NULL if adding to cutpool only */
9417  SCIP_Real minefficacy /**< minimal efficacy of a cut when checking for separation of LP solution */
9418  )
9419 {
9420  SCIP_CONSHDLRDATA* conshdlrdata;
9421  SCIP_CONSDATA* consdata;
9422  SCIP_Bool addedtolp;
9423  SCIP_ROW* row;
9424  int c;
9425 
9426  assert(scip != NULL);
9427  assert(conshdlr != NULL);
9428  assert(conss != NULL || nconss == 0);
9429 
9430  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9431  assert(conshdlrdata != NULL);
9432 
9433  if( separatedlpsol != NULL )
9434  *separatedlpsol = FALSE;
9435 
9436  for( c = 0; c < nconss; ++c )
9437  {
9438  assert(conss[c] != NULL); /*lint !e613 */
9439 
9440  if( SCIPconsIsLocal(conss[c]) || !SCIPconsIsEnabled(conss[c]) ) /*lint !e613 */
9441  continue;
9442 
9443  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
9444 
9445  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
9446  assert(consdata != NULL);
9447 
9448  if( consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs) )
9449  {
9450  SCIP_CALL( generateCutSol(scip, conshdlr, conss[c], NULL, ref, SCIP_SIDETYPE_RIGHT, &row, NULL,
9451  conshdlrdata->checkcurvature, -SCIPinfinity(scip), 'l') ); /*lint !e613 */
9452  }
9453  else if( consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs) )
9454  {
9455  SCIP_CALL( generateCutSol(scip, conshdlr, conss[c], NULL, ref, SCIP_SIDETYPE_LEFT, &row, NULL,
9456  conshdlrdata->checkcurvature, -SCIPinfinity(scip), 'l') ); /*lint !e613 */
9457  }
9458  else
9459  continue;
9460 
9461  if( row == NULL )
9462  continue;
9463 
9464  addedtolp = FALSE;
9465 
9466  /* if caller wants, then check if cut separates LP solution and add to sepastore if so */
9467  if( separatedlpsol != NULL )
9468  {
9469  SCIP_Real efficacy;
9470 
9471  efficacy = -SCIPgetRowLPFeasibility(scip, row);
9472  if( efficacy >= minefficacy )
9473  {
9474  SCIP_Bool infeasible;
9475 
9476  *separatedlpsol = TRUE;
9477  addedtolp = TRUE;
9478  SCIP_CALL( SCIPaddRow(scip, row, TRUE, &infeasible) );
9479  assert( ! infeasible );
9480  SCIPdebugMsg(scip, "added linearization cut <%s> to LP, efficacy = %g\n", SCIProwGetName(row), efficacy);
9481  }
9482  }
9483 
9484  if( !SCIProwIsLocal(row) && !addedtolp )
9485  {
9486  SCIP_CALL( SCIPaddPoolCut(scip, row) );
9487  SCIPdebugMsg(scip, "added linearization cut <%s> to cutpool\n", SCIProwGetName(row));
9488  }
9489 
9490  SCIP_CALL( SCIPreleaseRow(scip, &row) );
9491  }
9492 
9493  return SCIP_OKAY;
9494 }
9495 
9496 /** processes the event that a new primal solution has been found */
9497 static
9498 SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
9500  SCIP_CONSHDLRDATA* conshdlrdata;
9501  SCIP_CONSHDLR* conshdlr;
9502  SCIP_CONS** conss;
9503  int nconss;
9504  SCIP_SOL* sol;
9505 
9506  assert(scip != NULL);
9507  assert(event != NULL);
9508  assert(eventdata != NULL);
9509  assert(eventhdlr != NULL);
9510 
9511  assert((SCIPeventGetType(event) & SCIP_EVENTTYPE_SOLFOUND) != 0);
9512 
9513  conshdlr = (SCIP_CONSHDLR*)eventdata;
9514 
9515  nconss = SCIPconshdlrGetNConss(conshdlr);
9516 
9517  if( nconss == 0 )
9518  return SCIP_OKAY;
9519 
9520  sol = SCIPeventGetSol(event);
9521  assert(sol != NULL);
9522 
9523  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9524  assert(conshdlrdata != NULL);
9525 
9526  /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
9527  * the reason for ignoring trysol solutions is that they may come from an NLP solve in sepalp, where we already added linearizations,
9528  * or are from the tree, but postprocessed via proposeFeasibleSolution
9529  */
9530  if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
9531  return SCIP_OKAY;
9532 
9533  conss = SCIPconshdlrGetConss(conshdlr);
9534  assert(conss != NULL);
9535 
9536  SCIPdebugMsg(scip, "caught new sol event %" SCIP_EVENTTYPE_FORMAT " from heur <%s>; have %d conss\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)), nconss);
9537 
9538  SCIP_CALL( addLinearizationCuts(scip, conshdlr, conss, nconss, sol, NULL, 0.0) );
9539 
9540  return SCIP_OKAY;
9541 }
9542 
9543 /** registers branching candidates according to convexification gap rule
9544  *
9545  * That is, computes for every nonconvex term the gap between the terms value in the LP solution and the value of the underestimator
9546  * as it would be (and maybe has been) constructed by the separation routines of this constraint handler. Then it registers all
9547  * variables occurring in each term with the computed gap. If variables appear in more than one term, they are registered several times.
9548  */
9549 static
9551  SCIP* scip, /**< SCIP data structure */
9552  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9553  SCIP_CONS** conss, /**< constraints to check */
9554  int nconss, /**< number of constraints to check */
9555  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
9556  int* nnotify /**< counter for number of notifications performed */
9557  )
9558 {
9559  SCIP_CONSHDLRDATA* conshdlrdata;
9560  SCIP_CONSDATA* consdata;
9561  int c;
9562  int j;
9563  SCIP_Bool xbinary;
9564  SCIP_Bool ybinary;
9565  SCIP_Bool xunbounded;
9566  SCIP_Bool yunbounded;
9567  SCIP_VAR* x;
9568  SCIP_VAR* y;
9569  SCIP_Real xlb;
9570  SCIP_Real xub;
9571  SCIP_Real xval;
9572  SCIP_Real ylb;
9573  SCIP_Real yub;
9574  SCIP_Real yval;
9575  SCIP_Real gap;
9576  SCIP_Real coef_;
9577 
9578  assert(scip != NULL);
9579  assert(conshdlr != NULL);
9580  assert(conss != NULL || nconss == 0);
9581 
9582  *nnotify = 0;
9583  yval = SCIP_INVALID;
9584  xval = SCIP_INVALID;
9585 
9586  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9587  assert(conshdlr != NULL);
9588 
9589  for( c = 0; c < nconss; ++c )
9590  {
9591  assert(conss != NULL);
9592  consdata = SCIPconsGetData(conss[c]);
9593  assert(consdata != NULL);
9594 
9595  if( !consdata->nquadvars )
9596  continue;
9597 
9598  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || consdata->isconcave) &&
9599  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || consdata->isconvex ) )
9600  continue;
9601  SCIPdebugMsg(scip, "cons <%s> violation: %g %g convex: %u %u\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->isconvex, consdata->isconcave);
9602 
9603  /* square terms */
9604  for( j = 0; j < consdata->nquadvars; ++j )
9605  {
9606  x = consdata->quadvarterms[j].var;
9607  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && consdata->quadvarterms[j].sqrcoef < 0) ||
9608  ( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && consdata->quadvarterms[j].sqrcoef > 0) )
9609  {
9610  xlb = SCIPvarGetLbLocal(x);
9611  xub = SCIPvarGetUbLocal(x);
9612  if( SCIPisRelEQ(scip, xlb, xub) )
9613  {
9614  SCIPdebugMsg(scip, "ignore fixed variable <%s>[%g, %g], diff %g\n", SCIPvarGetName(x), xlb, xub, xub-xlb);
9615  continue;
9616  }
9617 
9618  xval = SCIPgetSolVal(scip, sol, x);
9619 
9620  /* if variable is at bounds, then no need to branch, since secant is exact there */
9621  if( SCIPisLE(scip, xval, xlb) || SCIPisGE(scip, xval, xub) )
9622  continue;
9623 
9624  if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) )
9625  gap = SCIPinfinity(scip);
9626  else
9627  gap = (xval-xlb)*(xub-xval)/(1+2*ABS(xval));
9628  assert(!SCIPisFeasNegative(scip, gap));
9629  SCIP_CALL( SCIPaddExternBranchCand(scip, x, MAX(gap, 0.0), SCIP_INVALID) );
9630  ++*nnotify;
9631  }
9632  }
9633 
9634  /* bilinear terms */
9635  for( j = 0; j < consdata->nbilinterms; ++j )
9636  {
9637  /* if any of the variables if fixed, then it actually behaves like a linear term, so we don't need to branch on it */
9638  x = consdata->bilinterms[j].var1;
9639  xlb = SCIPvarGetLbLocal(x);
9640  xub = SCIPvarGetUbLocal(x);
9641  if( SCIPisRelEQ(scip, xlb, xub) )
9642  continue;
9643 
9644  y = consdata->bilinterms[j].var2;
9645  ylb = SCIPvarGetLbLocal(y);
9646  yub = SCIPvarGetUbLocal(y);
9647  if( SCIPisRelEQ(scip, ylb, yub) )
9648  continue;
9649 
9650  xunbounded = SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub);
9651  yunbounded = SCIPisInfinity(scip, -ylb) || SCIPisInfinity(scip, yub);
9652 
9653  /* compute gap, if both variable are bounded */
9654  gap = SCIPinfinity(scip);
9655  if( !xunbounded && !yunbounded )
9656  {
9657  xval = SCIPgetSolVal(scip, sol, x);
9658  yval = SCIPgetSolVal(scip, sol, y);
9659 
9660  /* if both variables are at one of its bounds, then no need to branch, since McCormick is exact there */
9661  if( (SCIPisLE(scip, xval, xlb) || SCIPisGE(scip, xval, xub)) &&
9662  ( SCIPisLE(scip, yval, ylb) || SCIPisGE(scip, yval, yub)) )
9663  continue;
9664 
9665  xval = MAX(xlb, MIN(xval, xub));
9666  yval = MAX(ylb, MIN(yval, yub));
9667 
9668  coef_ = SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) ? -consdata->bilinterms[j].coef : consdata->bilinterms[j].coef;
9669  if( coef_ > 0.0 )
9670  {
9671  if( (xub-xlb)*yval + (yub-ylb)*xval <= xub*yub - xlb*ylb )
9672  gap = (xval*yval - xlb*yval - ylb*xval + xlb*ylb) / (1+sqrt(xval*xval + yval*yval));
9673  else
9674  gap = (xval*yval - xval*yub - yval*xub + xub*yub) / (1+sqrt(xval*xval + yval*yval));
9675  }
9676  else
9677  { /* coef_ < 0 */
9678  if( (xub-xlb)*yval - (yub-ylb)*xval <= xub*ylb - xlb*yub )
9679  gap = -(xval*yval - xval*ylb - yval*xub + xub*ylb) / (1+sqrt(xval*xval + yval*yval));
9680  else
9681  gap = -(xval*yval - xval*yub - yval*xlb + xlb*yub) / (1+sqrt(xval*xval + yval*yval));
9682  }
9683 
9684  assert(!SCIPisNegative(scip, gap / MAX3(MAX(REALABS(xlb), REALABS(xub)), MAX(REALABS(ylb), REALABS(yub)), 1.0))); /*lint !e666*/
9685  if( gap < 0.0 )
9686  gap = 0.0;
9687 
9688  /* use tighter relaxation when using linear inequalities to adjust the branching scores for bilinear terms */
9689  if( consdata->bilintermsidx != NULL && conshdlrdata->usebilinineqbranch )
9690  {
9691  BILINESTIMATOR* bilinestimator;
9692  int bilinidx;
9693 
9694  assert(conshdlrdata->bilinestimators != NULL);
9695 
9696  bilinidx = consdata->bilintermsidx[j];
9697  assert(bilinidx >= 0 && bilinidx < conshdlrdata->nbilinterms);
9698 
9699  bilinestimator = &conshdlrdata->bilinestimators[bilinidx];
9700  assert(bilinestimator != NULL);
9701  assert(bilinestimator->x == x);
9702  assert(bilinestimator->y == y);
9703 
9704  if( SCIPisGT(scip, bilinestimator->lastimprfac, 0.0) )
9705  gap *= MAX(0.0, 1.0 - bilinestimator->lastimprfac);
9706  }
9707  }
9708 
9709  /* if one of the variables is binary or integral with domain width 1, then branching on this makes the term linear, so prefer this */
9710  xbinary = SCIPvarIsBinary(x) || (SCIPvarIsIntegral(x) && xub - xlb < 1.5);
9711  ybinary = SCIPvarIsBinary(y) || (SCIPvarIsIntegral(y) && yub - ylb < 1.5);
9712  if( xbinary )
9713  {
9715  ++*nnotify;
9716  }
9717  if( ybinary )
9718  {
9720  ++*nnotify;
9721  }
9722  if( xbinary || ybinary )
9723  continue;
9724 
9725  /* if one of the variables is unbounded, then branch on it first */
9726  if( xunbounded )
9727  {
9729  ++*nnotify;
9730  }
9731  if( yunbounded )
9732  {
9734  ++*nnotify;
9735  }
9736  if( xunbounded || yunbounded )
9737  continue;
9738 
9739  /* if both variables are integral, prefer the one with the smaller domain, so variable gets fixed soon
9740  * does not seem to work well on tln instances, so disable for now and may look at it later again
9741  */
9742 #ifdef BRANCHTOLINEARITY
9743  if( SCIPvarIsIntegral(x) && SCIPvarIsIntegral(y) )
9744  {
9745  if( SCIPisLT(scip, xub-xlb, yub-ylb) )
9746  {
9748  ++*nnotify;
9749  continue;
9750  }
9751  if( SCIPisGT(scip, xub-xlb, yub-ylb) )
9752  {
9754  ++*nnotify;
9755  continue;
9756  }
9757  }
9758 #endif
9759 
9760  /* in the regular case, suggest those variables which are not at its bounds for branching
9761  * this is, because after branching both variables will be one the bounds, and McCormick will be exact then */
9762  if( !SCIPisLE(scip, xval, xlb) && !SCIPisGE(scip, xval, xub) )
9763  {
9765  ++*nnotify;
9766  }
9767  if( !SCIPisLE(scip, yval, ylb) && !SCIPisGE(scip, yval, yub) )
9768  {
9770  ++*nnotify;
9771  }
9772  }
9773  }
9774 
9775  SCIPdebugMsg(scip, "registered %d branching candidates\n", *nnotify);
9776 
9777  return SCIP_OKAY;
9778 }
9779 
9780 /** registers branching candidates according to constraint violation rule
9781  *
9782  * That is, registers all variables appearing in nonconvex terms^1 with a score that is the violation of the constraint.
9783  * This is the same rule as is applied in cons_nonlinear and other nonlinear constraint handlers.
9784  *
9785  * 1) We mean all quadratic variables that appear either in a nonconvex square term or in a bilinear term, if the constraint
9786  * itself is nonconvex. (and this under the assumption that the rhs is violated; for violated lhs, swap terms)
9787  */
9788 static
9790  SCIP* scip, /**< SCIP data structure */
9791  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9792  SCIP_CONS** conss, /**< constraints to check */
9793  int nconss, /**< number of constraints to check */
9794  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
9795  int* nnotify /**< counter for number of notifications performed */
9796  )
9797 {
9798  SCIP_CONSDATA* consdata;
9799  SCIP_QUADVARTERM* quadvarterm;
9800  int c;
9801  int j;
9802  SCIP_VAR* x;
9803  SCIP_Real xlb;
9804  SCIP_Real xub;
9805  SCIP_Real xval;
9806 
9807  assert(scip != NULL);
9808  assert(conshdlr != NULL);
9809  assert(conss != NULL || nconss == 0);
9810 
9811  *nnotify = 0;
9812 
9813  for( c = 0; c < nconss; ++c )
9814  {
9815  assert(conss != NULL);
9816  consdata = SCIPconsGetData(conss[c]);
9817  assert(consdata != NULL);
9818 
9819  if( !consdata->nquadvars )
9820  continue;
9821 
9822  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || consdata->isconcave) &&
9823  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || consdata->isconvex ) )
9824  continue;
9825  SCIPdebugMsg(scip, "cons %s violation: %g %g convex: %u %u\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->isconvex, consdata->isconcave);
9826 
9827  for( j = 0; j < consdata->nquadvars; ++j )
9828  {
9829  quadvarterm = &consdata->quadvarterms[j];
9830  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef < 0) ||
9831  (SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef > 0) ||
9832  quadvarterm->nadjbilin > 0 )
9833  {
9834  x = quadvarterm->var;
9835  xlb = SCIPvarGetLbLocal(x);
9836  xub = SCIPvarGetUbLocal(x);
9837 
9838  if( quadvarterm->nadjbilin == 0 )
9839  {
9840  xval = SCIPgetSolVal(scip, sol, x);
9841 
9842  /* if variable is at bounds and only in a nonconvex square term, then no need to branch, since secant is exact there */
9843  if( SCIPisLE(scip, xval, xlb) || SCIPisGE(scip, xval, xub) )
9844  continue;
9845  }
9846 
9847  if( SCIPisRelEQ(scip, xlb, xub) )
9848  {
9849  SCIPdebugMsg(scip, "ignore fixed variable <%s>[%g, %g], diff %g\n", SCIPvarGetName(x), xlb, xub, xub-xlb);
9850  continue;
9851  }
9852 
9853  SCIP_CALL( SCIPaddExternBranchCand(scip, x, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
9854  ++*nnotify;
9855  }
9856  }
9857  }
9858 
9859  SCIPdebugMsg(scip, "registered %d branching candidates\n", *nnotify);
9860 
9861  return SCIP_OKAY;
9862 }
9863 
9864 /** registers branching candidates according to centrality rule
9865  *
9866  * That is, registers all variables appearing in nonconvex terms^1 with a score that is given by the distance of the
9867  * variable value from its bounds. This rule should not make sense, as the distance to the bounds is also (often) considered
9868  * by the branching rule later on.
9869  *
9870  * 1) We mean all quadratic variables that appear either in a nonconvex square term or in a bilinear term, if the constraint
9871  * itself is nonconvex. (and this under the assumption that the rhs is violated; for violated lhs, swap terms)
9872  */
9873 static
9875  SCIP* scip, /**< SCIP data structure */
9876  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9877  SCIP_CONS** conss, /**< constraints to check */
9878  int nconss, /**< number of constraints to check */
9879  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
9880  int* nnotify /**< counter for number of notifications performed */
9881  )
9882 {
9883  SCIP_CONSDATA* consdata;
9884  SCIP_QUADVARTERM* quadvarterm;
9885  int c;
9886  int j;
9887  SCIP_VAR* x;
9888  SCIP_Real xlb;
9889  SCIP_Real xub;
9890  SCIP_Real xval;
9891  SCIP_Real score;
9892 
9893  assert(scip != NULL);
9894  assert(conshdlr != NULL);
9895  assert(conss != NULL || nconss == 0);
9896 
9897  *nnotify = 0;
9898 
9899  for( c = 0; c < nconss; ++c )
9900  {
9901  assert(conss != NULL);
9902  consdata = SCIPconsGetData(conss[c]);
9903  assert(consdata != NULL);
9904 
9905  if( !consdata->nquadvars )
9906  continue;
9907 
9908  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || consdata->isconcave) &&
9909  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || consdata->isconvex ) )
9910  continue;
9911  SCIPdebugMsg(scip, "cons %s violation: %g %g convex: %u %u\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->isconvex, consdata->isconcave);
9912 
9913  for( j = 0; j < consdata->nquadvars; ++j )
9914  {
9915  quadvarterm = &consdata->quadvarterms[j];
9916  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef < 0) ||
9917  (SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef > 0) ||
9918  quadvarterm->nadjbilin > 0 )
9919  {
9920  x = quadvarterm->var;
9921  xlb = SCIPvarGetLbLocal(x);
9922  xub = SCIPvarGetUbLocal(x);
9923 
9924  if( SCIPisRelEQ(scip, xlb, xub) )
9925  {
9926  SCIPdebugMsg(scip, "ignore fixed variable <%s>[%g, %g], diff %g\n", SCIPvarGetName(x), xlb, xub, xub-xlb);
9927  continue;
9928  }
9929 
9930  xval = SCIPgetSolVal(scip, sol, x);
9931  xval = MAX(xlb, MIN(xub, xval));
9932 
9933  /* compute relative difference of xval to each of its bounds
9934  * and scale such that if xval were in the middle, we get a score of 1
9935  * and if xval is on one its bounds, the score is 0
9936  */
9937  if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) )
9938  {
9939  if( (!SCIPisInfinity(scip, -xlb) && SCIPisEQ(scip, xval, xlb)) || (!SCIPisInfinity(scip, xub) && SCIPisEQ(scip, xval, xub)) )
9940  score = 0.0;
9941  else
9942  score = 1.0;
9943  }
9944  else
9945  {
9946  score = 4.0 * (xval - xlb) * (xub - xval) / ((xub - xlb) * (xub - xlb));
9947  }
9948 
9949  SCIP_CALL( SCIPaddExternBranchCand(scip, x, score, SCIP_INVALID) );
9950  ++*nnotify;
9951  }
9952  }
9953  }
9954 
9955  SCIPdebugMsg(scip, "registered %d branching candidates\n", *nnotify);
9956 
9957  return SCIP_OKAY;
9958 }
9959 
9960 /** registers branching candidates */
9961 static
9963  SCIP* scip, /**< SCIP data structure */
9964  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9965  SCIP_CONS** conss, /**< constraints to check */
9966  int nconss, /**< number of constraints to check */
9967  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
9968  int* nnotify /**< counter for number of notifications performed */
9969  )
9970 {
9971  SCIP_CONSHDLRDATA* conshdlrdata;
9972 
9973  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9974  assert(conshdlrdata != NULL);
9975 
9976  switch( conshdlrdata->branchscoring )
9977  {
9978  case 'g' :
9979  SCIP_CALL( registerBranchingCandidatesGap(scip, conshdlr, conss, nconss, sol, nnotify) );
9980  break;
9981 
9982  case 'v' :
9983  SCIP_CALL( registerBranchingCandidatesViolation(scip, conshdlr, conss, nconss, sol, nnotify) );
9984  break;
9985 
9986  case 'c' :
9987  SCIP_CALL( registerBranchingCandidatesCentrality(scip, conshdlr, conss, nconss, sol, nnotify) );
9988  break;
9989 
9990  default :
9991  SCIPerrorMessage("invalid branchscoring selection");
9992  SCIPABORT();
9993  return SCIP_ERROR; /*lint !e527*/
9994  }
9995 
9996  return SCIP_OKAY;
9997 }
9998 
9999 
10000 /** registers a quadratic variable from a violated constraint as branching candidate that has a large absolute value in the (LP) relaxation */
10001 static
10003  SCIP* scip, /**< SCIP data structure */
10004  SCIP_CONS** conss, /**< constraints */
10005  int nconss, /**< number of constraints */
10006  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
10007  SCIP_VAR** brvar /**< buffer to store branching variable */
10008  )
10009 {
10010  SCIP_CONSDATA* consdata;
10011  SCIP_Real val;
10012  SCIP_Real brvarval;
10013  int i;
10014  int c;
10015 
10016  assert(scip != NULL);
10017  assert(conss != NULL || nconss == 0);
10018 
10019  *brvar = NULL;
10020  brvarval = -1.0;
10021 
10022  for( c = 0; c < nconss; ++c )
10023  {
10024  assert(conss != NULL);
10025  consdata = SCIPconsGetData(conss[c]);
10026  assert(consdata != NULL);
10027 
10028  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
10029  continue;
10030 
10031  for( i = 0; i < consdata->nquadvars; ++i )
10032  {
10033  /* do not propose fixed variables */
10034  if( SCIPisRelEQ(scip, SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
10035  continue;
10036  val = SCIPgetSolVal(scip, sol, consdata->quadvarterms[i].var);
10037  if( ABS(val) > brvarval )
10038  {
10039  brvarval = ABS(val);
10040  *brvar = consdata->quadvarterms[i].var;
10041  }
10042  }
10043  }
10044 
10045  if( *brvar != NULL )
10046  {
10047  SCIP_CALL( SCIPaddExternBranchCand(scip, *brvar, brvarval, SCIP_INVALID) );
10048  }
10049 
10050  return SCIP_OKAY;
10051 }
10052 
10053 /** replaces violated quadratic constraints where all quadratic variables are fixed by linear constraints */
10054 static
10056  SCIP* scip, /**< SCIP data structure */
10057  SCIP_CONS** conss, /**< constraints */
10058  int nconss, /**< number of constraints */
10059  SCIP_Bool* addedcons, /**< buffer to store whether a linear constraint was added */
10060  SCIP_Bool* reduceddom, /**< whether a domain has been reduced */
10061  SCIP_Bool* infeasible /**< whether we detected infeasibility */
10062  )
10063 {
10064  SCIP_CONS* cons;
10065  SCIP_CONSDATA* consdata;
10066  SCIP_RESULT checkresult;
10067  SCIP_VAR* var;
10068  SCIP_Bool tightened;
10069  SCIP_Real constant;
10070  SCIP_Real val1;
10071  SCIP_Real val2;
10072  int i;
10073  int c;
10074 
10075  assert(scip != NULL);
10076  assert(conss != NULL || nconss == 0);
10077  assert(addedcons != NULL);
10078  assert(reduceddom != NULL);
10079  assert(infeasible != NULL);
10080 
10081  *addedcons = FALSE;
10082  *reduceddom = FALSE;
10083  *infeasible = FALSE;
10084 
10085  for( c = 0; c < nconss; ++c )
10086  {
10087  assert(conss != NULL);
10088  consdata = SCIPconsGetData(conss[c]);
10089  assert(consdata != NULL);
10090 
10091  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
10092  continue;
10093 
10094  constant = 0.0;
10095 
10096  for( i = 0; i < consdata->nquadvars; ++i )
10097  {
10098  var = consdata->quadvarterms[i].var;
10099 
10100  /* variables should be fixed if constraint is violated */
10101  assert(SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)));
10102 
10103  val1 = (SCIPvarGetUbLocal(var) + SCIPvarGetLbLocal(var)) / 2.0;
10104  constant += (consdata->quadvarterms[i].lincoef + consdata->quadvarterms[i].sqrcoef * val1) * val1;
10105 
10106  SCIPdebugMessage("<%s>: [%.20g, %.20g]\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
10107 
10108  /* if variable is not fixed w.r.t. absolute eps yet, then try to fix it
10109  * (SCIPfixVar() doesn't allow for small tightenings, so tighten lower and upper bound separately)
10110  */
10111  if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
10112  {
10113  SCIP_CALL( SCIPtightenVarLb(scip, var, val1, TRUE, infeasible, &tightened) );
10114  if( *infeasible )
10115  {
10116  SCIPdebugMsg(scip, "Fixing almost fixed variable <%s> lead to infeasibility.\n", SCIPvarGetName(var));
10117  return SCIP_OKAY;
10118  }
10119  if( tightened )
10120  {
10121  SCIPdebugMsg(scip, "Tightened lower bound of almost fixed variable <%s>.\n", SCIPvarGetName(var));
10122  *reduceddom = TRUE;
10123  }
10124 
10125  SCIP_CALL( SCIPtightenVarUb(scip, var, val1, TRUE, infeasible, &tightened) );
10126  if( *infeasible )
10127  {
10128  SCIPdebugMsg(scip, "Fixing almost fixed variable <%s> lead to infeasibility.\n", SCIPvarGetName(var));
10129  return SCIP_OKAY;
10130  }
10131  if( tightened )
10132  {
10133  SCIPdebugMsg(scip, "Tightened upper bound of almost fixed variable <%s>.\n", SCIPvarGetName(var));
10134  *reduceddom = TRUE;
10135  }
10136  }
10137  }
10138 
10139  /* if some quadratic variable was fixed now, then restart node (next enfo round) */
10140  if( *reduceddom )
10141  return SCIP_OKAY;
10142 
10143  for( i = 0; i < consdata->nbilinterms; ++i )
10144  {
10145  val1 = (SCIPvarGetUbLocal(consdata->bilinterms[i].var1) + SCIPvarGetLbLocal(consdata->bilinterms[i].var1)) / 2.0;
10146  val2 = (SCIPvarGetUbLocal(consdata->bilinterms[i].var2) + SCIPvarGetLbLocal(consdata->bilinterms[i].var2)) / 2.0;
10147  constant += consdata->bilinterms[i].coef * val1 * val2;
10148  }
10149 
10150  /* check if we have a bound change */
10151  if ( consdata->nlinvars == 1 )
10152  {
10153  SCIP_Real coef;
10154  SCIP_Real lhs;
10155  SCIP_Real rhs;
10156 
10157  coef = *consdata->lincoefs;
10158  var = *consdata->linvars;
10159 
10160  assert( ! SCIPisZero(scip, coef) );
10161 
10162  /* compute lhs/rhs, divide already by |coef| */
10163  if ( SCIPisInfinity(scip, -consdata->lhs) )
10164  lhs = -SCIPinfinity(scip);
10165  else
10166  lhs = (consdata->lhs - constant) / REALABS(coef);
10167 
10168  if ( SCIPisInfinity(scip, consdata->rhs) )
10169  rhs = SCIPinfinity(scip);
10170  else
10171  rhs = (consdata->rhs - constant) / REALABS(coef);
10172 
10173  SCIPdebugMsg(scip, "Linear constraint with one variable: %.20g <= %g <%s> <= %.20g\n", lhs, coef > 0.0 ? 1.0 : -1.0, SCIPvarGetName(var), rhs);
10174 
10175  SCIPdebugMessage("<%s>: [%.20g, %.20g]\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
10176 
10177  if ( coef < 0.0 )
10178  {
10179  /* swap lhs and rhs, with negated sign */
10180  SCIP_Real h;
10181  h = rhs;
10182  rhs = -lhs;
10183  lhs = -h;
10184  }
10185  SCIPdebugMsg(scip, "Linear constraint is a bound: %.20g <= <%s> <= %.20g\n", lhs, SCIPvarGetName(var), rhs);
10186 
10187  if( SCIPisInfinity(scip, -rhs) || SCIPisInfinity(scip, lhs) )
10188  {
10189  SCIPdebugMsg(scip, "node will marked as infeasible since lb/ub of %s is +/-infinity\n",
10190  SCIPvarGetName(var));
10191 
10192  *infeasible = TRUE;
10193  return SCIP_OKAY;
10194  }
10195 
10196  if ( ! SCIPisInfinity(scip, -lhs) )
10197  {
10198  SCIP_CALL( SCIPtightenVarLb(scip, var, lhs, TRUE, infeasible, &tightened) );
10199  if ( *infeasible )
10200  {
10201  SCIPdebugMsg(scip, "Lower bound leads to infeasibility.\n");
10202  return SCIP_OKAY;
10203  }
10204  if ( tightened )
10205  {
10206  SCIPdebugMsg(scip, "Lower bound changed.\n");
10207  *reduceddom = TRUE;
10208  return SCIP_OKAY;
10209  }
10210  }
10211 
10212  if ( ! SCIPisInfinity(scip, rhs) )
10213  {
10214  SCIP_CALL( SCIPtightenVarUb(scip, var, rhs, TRUE, infeasible, &tightened) );
10215  if ( *infeasible )
10216  {
10217  SCIPdebugMsg(scip, "Upper bound leads to infeasibility.\n");
10218  return SCIP_OKAY;
10219  }
10220  if ( tightened )
10221  {
10222  SCIPdebugMsg(scip, "Upper bound changed.\n");
10223  *reduceddom = TRUE;
10224  return SCIP_OKAY;
10225  }
10226  }
10227  }
10228  else
10229  {
10230  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, SCIPconsGetName(conss[c]),
10231  consdata->nlinvars, consdata->linvars, consdata->lincoefs,
10232  (SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : (consdata->lhs - constant)),
10233  (SCIPisInfinity(scip, consdata->rhs) ? SCIPinfinity(scip) : (consdata->rhs - constant)),
10234  SCIPconsIsInitial(conss[c]), SCIPconsIsSeparated(conss[c]), SCIPconsIsEnforced(conss[c]),
10235  SCIPconsIsChecked(conss[c]), SCIPconsIsPropagated(conss[c]), TRUE,
10236  SCIPconsIsModifiable(conss[c]), SCIPconsIsDynamic(conss[c]), SCIPconsIsRemovable(conss[c]),
10237  SCIPconsIsStickingAtNode(conss[c])) );
10238 
10239  SCIPdebugMsg(scip, "replace quadratic constraint <%s> by linear constraint after all quadratic vars have been fixed\n", SCIPconsGetName(conss[c]) );
10240  SCIPdebugPrintCons(scip, cons, NULL);
10241 
10242  SCIP_CALL( SCIPcheckCons(scip, cons, NULL, FALSE, FALSE, FALSE, &checkresult) );
10243 
10244  if( checkresult != SCIP_INFEASIBLE && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
10245  {
10246  SCIPdebugMsg(scip, "linear constraint is feasible and LP optimal, thus do not add\n");
10247  }
10248  else
10249  {
10250  SCIP_CALL( SCIPaddConsLocal(scip, cons, NULL) );
10251  *addedcons = TRUE;
10252  }
10253  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
10254  }
10255  SCIP_CALL( SCIPdelConsLocal(scip, conss[c]) );
10256  }
10257 
10258  return SCIP_OKAY;
10259 }
10260 
10261 /** tightens a lower bound on a variable and checks the result */
10262 static
10264  SCIP* scip, /**< SCIP data structure */
10265  SCIP_CONS* cons, /**< constraint where we currently propagate */
10266  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
10267  SCIP_VAR* var, /**< variable which domain we might reduce */
10268  SCIP_Real bnd, /**< new lower bound for variable */
10269  SCIP_RESULT* result, /**< result to update if there was a tightening or cutoff */
10270  int* nchgbds /**< counter to increase if a bound was tightened */
10271  )
10272 {
10273  SCIP_Bool infeas;
10274  SCIP_Bool tightened;
10275 
10276  assert(scip != NULL);
10277  assert(cons != NULL);
10278  assert(intervalinfty > 0.0);
10279  assert(bnd > -intervalinfty);
10280  assert(var != NULL);
10281  assert(result != NULL);
10282  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
10283  assert(nchgbds != NULL);
10284 
10285  /* new bound is no improvement */
10286  if( SCIPisHugeValue(scip, -bnd) || SCIPisLE(scip, bnd, SCIPvarGetLbLocal(var)) )
10287  return SCIP_OKAY;
10288 
10289  if( SCIPisInfinity(scip, bnd) )
10290  { /* domain will be outside [-infty, +infty] -> declare node infeasible */
10291  *result = SCIP_CUTOFF;
10292  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10293  return SCIP_OKAY;
10294  }
10295 
10296  /* new lower bound is very low (between -intervalinfty and -SCIPinfinity()) */
10297  if( SCIPisInfinity(scip, -bnd) )
10298  return SCIP_OKAY;
10299 
10300  bnd = SCIPadjustedVarLb(scip, var, bnd);
10301  SCIP_CALL( SCIPtightenVarLb(scip, var, bnd, FALSE, &infeas, &tightened) );
10302  if( infeas )
10303  {
10304  SCIPdebugMsg(scip, "%s found constraint <%s> infeasible due to tightened lower bound %g for variable <%s>\n",
10305  SCIPinProbing(scip) ? "in probing" : "", SCIPconsGetName(cons), bnd, SCIPvarGetName(var));
10306  *result = SCIP_CUTOFF;
10307  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10308  return SCIP_OKAY;
10309  }
10310  if( tightened )
10311  {
10312  SCIPdebugMsg(scip, "%s tightened lower bound of variable <%s> in constraint <%s> to %g\n",
10313  SCIPinProbing(scip) ? "in probing" : "", SCIPvarGetName(var), SCIPconsGetName(cons), bnd);
10314  ++*nchgbds;
10315  *result = SCIP_REDUCEDDOM;
10316  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10317  }
10318 
10319  return SCIP_OKAY;
10320 }
10321 
10322 /** tightens an upper bound on a variable and checks the result */
10323 static
10325  SCIP* scip, /**< SCIP data structure */
10326  SCIP_CONS* cons, /**< constraint where we currently propagate */
10327  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
10328  SCIP_VAR* var, /**< variable which domain we might reduce */
10329  SCIP_Real bnd, /**< new upper bound for variable */
10330  SCIP_RESULT* result, /**< result to update if there was a tightening or cutoff */
10331  int* nchgbds /**< counter to increase if a bound was tightened */
10332  )
10333 {
10334  SCIP_Bool infeas;
10335  SCIP_Bool tightened;
10336 
10337  assert(scip != NULL);
10338  assert(cons != NULL);
10339  assert(intervalinfty > 0.0);
10340  assert(bnd < intervalinfty);
10341  assert(var != NULL);
10342  assert(result != NULL);
10343  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
10344  assert(nchgbds != NULL);
10345 
10346  /* new bound is no improvement */
10347  if( SCIPisHugeValue(scip, bnd) || SCIPisGE(scip, bnd, SCIPvarGetUbLocal(var)) )
10348  return SCIP_OKAY;
10349 
10350  if( SCIPisInfinity(scip, -bnd) )
10351  { /* domain will be outside [-infty, +infty] -> declare node infeasible */
10352  *result = SCIP_CUTOFF;
10353  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10354  return SCIP_OKAY;
10355  }
10356 
10357  /* new upper bound is very high (between SCIPinfinity() and intervalinfty) */
10358  if( SCIPisInfinity(scip, bnd) )
10359  return SCIP_OKAY;
10360 
10361  bnd = SCIPadjustedVarUb(scip, var, bnd);
10362  SCIP_CALL( SCIPtightenVarUb(scip, var, bnd, FALSE, &infeas, &tightened) );
10363  if( infeas )
10364  {
10365  SCIPdebugMsg(scip, "%s found constraint <%s> infeasible due to tightened upper bound %g for variable <%s>\n",
10366  SCIPinProbing(scip) ? "in probing" : "", SCIPconsGetName(cons), bnd, SCIPvarGetName(var));
10367  *result = SCIP_CUTOFF;
10368  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10369  return SCIP_OKAY;
10370  }
10371  if( tightened )
10372  {
10373  SCIPdebugMsg(scip, "%s tightened upper bound of variable <%s> in constraint <%s> to %g\n",
10374  SCIPinProbing(scip) ? "in probing" : "", SCIPvarGetName(var), SCIPconsGetName(cons), bnd);
10375  ++*nchgbds;
10376  *result = SCIP_REDUCEDDOM;
10377  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10378  }
10379 
10380  return SCIP_OKAY;
10381 }
10382 
10383 /** 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 */
10384 static
10386  SCIP* scip, /**< SCIP data structure */
10387  SCIP_CONS* cons, /**< constraint where we currently propagate */
10388  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
10389  SCIP_VAR* var, /**< variable which bounds with might tighten */
10390  SCIP_Real a, /**< coefficient in square term */
10391  SCIP_INTERVAL b, /**< coefficient in linear term */
10392  SCIP_INTERVAL rhs, /**< right hand side of quadratic equation */
10393  SCIP_RESULT* result, /**< result of propagation */
10394  int* nchgbds /**< buffer where to add number of tightened bounds */
10395  )
10396 {
10397  SCIP_INTERVAL newrange;
10398 
10399  assert(scip != NULL);
10400  assert(cons != NULL);
10401  assert(var != NULL);
10402  assert(result != NULL);
10403  assert(nchgbds != NULL);
10404 
10405  /* compute solution of a*x^2 + b*x \in rhs */
10406  if( a == 0.0 && SCIPintervalGetInf(b) == 0.0 && SCIPintervalGetSup(b) == 0.0 )
10407  {
10408  /* relatively easy case: 0.0 \in rhs, thus check if infeasible or just redundant */
10409  if( SCIPintervalGetInf(rhs) > 0.0 || SCIPintervalGetSup(rhs) < 0.0 )
10410  {
10411  SCIPdebugMsg(scip, "found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(var));
10412  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10413  *result = SCIP_CUTOFF;
10414  }
10415  return SCIP_OKAY;
10416  }
10417  else
10418  {
10419  SCIP_INTERVAL a_;
10420  SCIP_INTERVAL xbnds;
10421 
10422  SCIPintervalSet(&a_, a);
10423  SCIPintervalSetBounds(&xbnds, -infty2infty(SCIPinfinity(scip), intervalinfty, -SCIPvarGetLbLocal(var)), infty2infty(SCIPinfinity(scip), intervalinfty, SCIPvarGetUbLocal(var))); /*lint !e666*/
10424  SCIPintervalSolveUnivariateQuadExpression(intervalinfty, &newrange, a_, b, rhs, xbnds);
10425  }
10426 
10427  /* 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); */
10428 
10429  if( SCIPisInfinity(scip, SCIPintervalGetInf(newrange)) || SCIPisInfinity(scip, -SCIPintervalGetSup(newrange)) )
10430  {
10431  /* domain outside [-infty, +infty] -> declare node infeasible */
10432  SCIPdebugMsg(scip, "found <%s> infeasible because propagated domain of quadratic variable <%s> is outside of (-infty, +infty)\n",
10433  SCIPconsGetName(cons), SCIPvarGetName(var));
10434  *result = SCIP_CUTOFF;
10435  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10436  return SCIP_OKAY;
10437  }
10438 
10439  if( SCIPintervalIsEmpty(intervalinfty, newrange) )
10440  {
10441  SCIPdebugMsg(scip, "found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(var));
10442  *result = SCIP_CUTOFF;
10443  return SCIP_OKAY;
10444  }
10445 
10446  if( !SCIPisInfinity(scip, -SCIPintervalGetInf(newrange)) )
10447  {
10448  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, SCIPintervalGetInf(newrange), result, nchgbds) );
10449  if( *result == SCIP_CUTOFF )
10450  return SCIP_OKAY;
10451  }
10452 
10453  if( !SCIPisInfinity(scip, SCIPintervalGetSup(newrange)) )
10454  {
10455  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, SCIPintervalGetSup(newrange), result, nchgbds) );
10456  if( *result == SCIP_CUTOFF )
10457  return SCIP_OKAY;
10458  }
10459 
10460  return SCIP_OKAY;
10461 }
10462 
10463 /* The new version below computes potentially tighter bounds, but also always adds a small safety area since it is not implemented roundingsafe.
10464  * This may be a reason why it gives worse results on one of two instances.
10465  * Further, I have only very few instances where one can expect a difference.
10466  */
10467 #ifndef PROPBILINNEW
10468 /** tries to deduce domain reductions for x in xsqrcoef x^2 + xlincoef x + ysqrcoef y^2 + ylincoef y + bilincoef x y \\in rhs
10469  *
10470  * @note Domain reductions for y are not deduced.
10471  */
10472 static
10474  SCIP* scip, /**< SCIP data structure */
10475  SCIP_CONS* cons, /**< the constraint, where the bilinear term belongs to */
10476  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
10477  SCIP_VAR* x, /**< first variable */
10478  SCIP_Real xsqrcoef, /**< square coefficient of x */
10479  SCIP_Real xlincoef, /**< linear coefficient of x */
10480  SCIP_VAR* y, /**< second variable */
10481  SCIP_Real ysqrcoef, /**< square coefficient of y */
10482  SCIP_Real ylincoef, /**< linear coefficient of y */
10483  SCIP_Real bilincoef, /**< bilinear coefficient of x*y */
10484  SCIP_INTERVAL rhs, /**< right hand side of quadratic equation */
10485  SCIP_RESULT* result, /**< pointer to store result of domain propagation */
10486  int* nchgbds /**< counter to increment if domain reductions are found */
10487  )
10488 {
10489  SCIP_INTERVAL myrhs;
10490  SCIP_INTERVAL varbnds;
10491  SCIP_INTERVAL lincoef;
10492 
10493  assert(scip != NULL);
10494  assert(cons != NULL);
10495  assert(x != NULL);
10496  assert(y != NULL);
10497  assert(x != y);
10498  assert(result != NULL);
10499  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
10500  assert(nchgbds != NULL);
10501  assert(bilincoef != 0.0);
10502 
10503  if( SCIPintervalIsEntire(intervalinfty, rhs) )
10504  return SCIP_OKAY;
10505 
10506  /* try to find domain reductions for x */
10508 
10509  /* put ysqrcoef*y^2 + ylincoef * y into rhs */
10510  if( SCIPintervalGetSup(rhs) >= intervalinfty )
10511  {
10512  /* if rhs is unbounded by above, it is sufficient to get an upper bound on ysqrcoef*y^2 + ylincoef * y */
10513  SCIP_ROUNDMODE roundmode;
10514  SCIP_Real tmp;
10515 
10516  SCIPintervalSet(&lincoef, ylincoef);
10517  tmp = SCIPintervalQuadUpperBound(intervalinfty, ysqrcoef, lincoef, varbnds);
10518  roundmode = SCIPintervalGetRoundingMode();
10520  SCIPintervalSetBounds(&myrhs, SCIPintervalGetInf(rhs) - tmp, intervalinfty);
10521  SCIPintervalSetRoundingMode(roundmode);
10522  }
10523  else if( SCIPintervalGetInf(rhs) <= -intervalinfty )
10524  {
10525  /* if rhs is unbounded by below, it is sufficient to get a lower bound on ysqrcoef*y^2 + ylincoef * y */
10526  SCIP_ROUNDMODE roundmode;
10527  SCIP_Real tmp;
10528 
10529  SCIPintervalSet(&lincoef, -ylincoef);
10530  tmp = -SCIPintervalQuadUpperBound(intervalinfty, -ysqrcoef, lincoef, varbnds);
10531  roundmode = SCIPintervalGetRoundingMode();
10533  SCIPintervalSetBounds(&myrhs, -intervalinfty, SCIPintervalGetSup(rhs) - tmp);
10534  SCIPintervalSetRoundingMode(roundmode);
10535  }
10536  else
10537  {
10538  /* if rhs is bounded, we need both bounds on ysqrcoef*y^2 + ylincoef * y */
10539  SCIP_INTERVAL tmp;
10540 
10541  SCIPintervalSet(&lincoef, ylincoef);
10542  SCIPintervalQuad(intervalinfty, &tmp, ysqrcoef, lincoef, varbnds);
10543  SCIPintervalSub(intervalinfty, &myrhs, rhs, tmp);
10544  }
10545 
10546  /* create equation xsqrcoef * x^2 + (xlincoef + bilincoef * [ylb, yub]) * x \in myrhs */
10547  SCIPintervalMulScalar(intervalinfty, &lincoef, varbnds, bilincoef);
10548  SCIPintervalAddScalar(intervalinfty, &lincoef, lincoef, xlincoef);
10549 
10550  /* propagate bounds on x */
10551  SCIP_CALL( propagateBoundsQuadVar(scip, cons, intervalinfty, x, xsqrcoef, lincoef, myrhs, result, nchgbds) );
10552 
10553  return SCIP_OKAY;
10554 }
10555 #else
10556 /** tries to deduce domain reductions for x in xsqrcoef x^2 + xlincoef x + ysqrcoef y^2 + ylincoef y + bilincoef x y \\in rhs
10557  *
10558  * @note Domain reductions for y are not deduced.
10559  */
10560 static
10562  SCIP* scip, /**< SCIP data structure */
10563  SCIP_CONS* cons, /**< the constraint, where the bilinear term belongs to */
10564  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
10565  SCIP_VAR* x, /**< first variable */
10566  SCIP_Real xsqrcoef, /**< square coefficient of x */
10567  SCIP_Real xlincoef, /**< linear coefficient of x */
10568  SCIP_VAR* y, /**< second variable */
10569  SCIP_Real ysqrcoef, /**< square coefficient of y */
10570  SCIP_Real ylincoef, /**< linear coefficient of y */
10571  SCIP_Real bilincoef, /**< bilinear coefficient of x*y */
10572  SCIP_INTERVAL rhs, /**< right hand side of quadratic equation */
10573  SCIP_RESULT* result, /**< pointer to store result of domain propagation */
10574  int* nchgbds /**< counter to increment if domain reductions are found */
10575  )
10576 {
10577  SCIP_INTERVAL xbnds;
10578  SCIP_INTERVAL ybnds;
10579 
10580  assert(scip != NULL);
10581  assert(cons != NULL);
10582  assert(x != NULL);
10583  assert(y != NULL);
10584  assert(x != y);
10585  assert(result != NULL);
10586  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
10587  assert(nchgbds != NULL);
10588  assert(bilincoef != 0.0);
10589 
10590  if( SCIPintervalIsEntire(intervalinfty, rhs) )
10591  return SCIP_OKAY;
10592 
10593  SCIPintervalSetBounds(&xbnds,
10594  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(x), SCIPvarGetUbLocal(x))), /*lint !e666*/
10595  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(x), SCIPvarGetUbLocal(x)))); /*lint !e666*/
10596  SCIPintervalSetBounds(&ybnds,
10597  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(y), SCIPvarGetUbLocal(y))), /*lint !e666*/
10598  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(y), SCIPvarGetUbLocal(y)))); /*lint !e666*/
10599 
10600  /* try to find domain reductions for x */
10601  SCIPintervalSolveBivariateQuadExpressionAllScalar(intervalinfty, &xbnds, xsqrcoef, ysqrcoef, bilincoef, xlincoef, ylincoef, rhs, xbnds, ybnds);
10602 
10603  if( SCIPintervalIsEmpty(intervalinfty, xbnds) )
10604  {
10605  SCIPdebugMsg(scip, "found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(x));
10606  *result = SCIP_CUTOFF;
10607  return SCIP_OKAY;
10608  }
10609 
10610  if( !SCIPisInfinity(scip, -SCIPintervalGetInf(xbnds)) )
10611  {
10612  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, x, SCIPintervalGetInf(xbnds), result, nchgbds) );
10613  if( *result == SCIP_CUTOFF )
10614  return SCIP_OKAY;
10615  }
10616 
10617  if( !SCIPisInfinity(scip, SCIPintervalGetSup(xbnds)) )
10618  {
10619  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, x, SCIPintervalGetSup(xbnds), result, nchgbds) );
10620  if( *result == SCIP_CUTOFF )
10621  return SCIP_OKAY;
10622  }
10623 
10624  return SCIP_OKAY;
10625 }
10626 #endif
10627 
10628 /** computes the minimal and maximal activity for the quadratic part in a constraint data
10629  *
10630  * Only sums up terms that contribute finite values.
10631  * Gives the number of terms that contribute infinite values.
10632  * Only computes those activities where the corresponding side of the constraint is finite.
10633  */
10634 static
10636  SCIP* scip, /**< SCIP data structure */
10637  SCIP_CONSDATA* consdata, /**< constraint data */
10638  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
10639  SCIP_Real* minquadactivity, /**< minimal activity of quadratic variable terms where only terms with finite minimal activity contribute */
10640  SCIP_Real* maxquadactivity, /**< maximal activity of quadratic variable terms where only terms with finite maximal activity contribute */
10641  int* minactivityinf, /**< number of quadratic variables that contribute -infinity to minimal activity */
10642  int* maxactivityinf, /**< number of quadratic variables that contribute +infinity to maximal activity */
10643  SCIP_INTERVAL* quadactcontr /**< contribution of each quadratic variables to quadactivity */
10644  )
10645 { /*lint --e{666}*/
10646  SCIP_ROUNDMODE prevroundmode;
10647  int i;
10648  int j;
10649  int k;
10650  SCIP_INTERVAL tmp;
10651  SCIP_Real bnd;
10652  SCIP_INTERVAL xrng;
10653  SCIP_INTERVAL lincoef;
10654 
10655  assert(scip != NULL);
10656  assert(consdata != NULL);
10657  assert(minquadactivity != NULL);
10658  assert(maxquadactivity != NULL);
10659  assert(minactivityinf != NULL);
10660  assert(maxactivityinf != NULL);
10661  assert(quadactcontr != NULL);
10662 
10663  /* if lhs is -infinite, then we do not compute a maximal activity, so we set it to infinity
10664  * if rhs is infinite, then we do not compute a minimal activity, so we set it to -infinity
10665  */
10666  *minquadactivity = SCIPisInfinity(scip, consdata->rhs) ? -intervalinfty : 0.0;
10667  *maxquadactivity = SCIPisInfinity(scip, -consdata->lhs) ? intervalinfty : 0.0;
10668 
10669  *minactivityinf = 0;
10670  *maxactivityinf = 0;
10671 
10672  if( consdata->nquadvars == 0 )
10673  {
10674  SCIPintervalSet(&consdata->quadactivitybounds, 0.0);
10675  return;
10676  }
10677 
10678  for( i = 0; i < consdata->nquadvars; ++i )
10679  {
10680  /* there should be no quadratic variables fixed at -/+ infinity due to our locks */
10681  assert(!SCIPisInfinity(scip, SCIPvarGetLbLocal(consdata->quadvarterms[i].var)));
10682  assert(!SCIPisInfinity(scip, -SCIPvarGetUbLocal(consdata->quadvarterms[i].var)));
10683 
10684  SCIPintervalSetBounds(&quadactcontr[i], -intervalinfty, intervalinfty);
10685 
10686  SCIPintervalSetBounds(&xrng,
10687  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var))),
10688  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var))));
10689 
10690  SCIPintervalSet(&lincoef, consdata->quadvarterms[i].lincoef);
10691  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
10692  {
10693  k = consdata->quadvarterms[i].adjbilin[j];
10694  if( consdata->bilinterms[k].var1 != consdata->quadvarterms[i].var )
10695  continue; /* handle this term later */
10696 
10697  SCIPintervalSetBounds(&tmp,
10698  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
10699  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
10700  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
10701  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
10702  }
10703 
10704  if( !SCIPisInfinity(scip, -consdata->lhs) )
10705  {
10706  /* compute maximal activity only if there is a finite left hand side */
10707  bnd = SCIPintervalQuadUpperBound(intervalinfty, consdata->quadvarterms[i].sqrcoef, lincoef, xrng);
10708  if( bnd >= intervalinfty )
10709  {
10710  ++*maxactivityinf;
10711  }
10712  else if( SCIPisInfinity(scip, -bnd) )
10713  {
10714  /* if maximal activity is below value for -infinity, let's take -1e10 as upper bound on maximal activity
10715  * @todo Something better?
10716  */
10717  bnd = -sqrt(SCIPinfinity(scip));
10718  *maxquadactivity += bnd;
10719  quadactcontr[i].sup = bnd;
10720  }
10721  else
10722  {
10723  prevroundmode = SCIPintervalGetRoundingMode();
10725  *maxquadactivity += bnd;
10726  SCIPintervalSetRoundingMode(prevroundmode);
10727  quadactcontr[i].sup = bnd;
10728  }
10729  }
10730 
10731  if( !SCIPisInfinity(scip, consdata->rhs) )
10732  {
10733  /* compute minimal activity only if there is a finite right hand side */
10734  SCIPintervalSetBounds(&lincoef, -SCIPintervalGetSup(lincoef), -SCIPintervalGetInf(lincoef));
10735  bnd = -SCIPintervalQuadUpperBound(intervalinfty, -consdata->quadvarterms[i].sqrcoef, lincoef, xrng);
10736 
10737  if( bnd <= -intervalinfty )
10738  {
10739  ++*minactivityinf;
10740  }
10741  else if( SCIPisInfinity(scip, bnd) )
10742  {
10743  /* if minimal activity is above value for infinity, let's take 1e10 as lower bound on minimal activity
10744  * @todo Something better?
10745  */
10746  bnd = sqrt(SCIPinfinity(scip));
10747  *minquadactivity += bnd;
10748  quadactcontr[i].inf = bnd;
10749  }
10750  else
10751  {
10752  prevroundmode = SCIPintervalGetRoundingMode();
10754  *minquadactivity += bnd;
10755  SCIPintervalSetRoundingMode(prevroundmode);
10756  quadactcontr[i].inf = bnd;
10757  }
10758  }
10759  }
10760 
10761  SCIPintervalSetBounds(&consdata->quadactivitybounds,
10762  (*minactivityinf > 0 ? -intervalinfty : *minquadactivity),
10763  (*maxactivityinf > 0 ? intervalinfty : *maxquadactivity));
10764  assert(!SCIPintervalIsEmpty(intervalinfty, consdata->quadactivitybounds));
10765 }
10766 
10767 /** propagates bounds on a quadratic constraint */
10768 static
10770  SCIP* scip, /**< SCIP data structure */
10771  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
10772  SCIP_CONS* cons, /**< constraint to process */
10773  SCIP_RESULT* result, /**< pointer to store the result of the propagation call */
10774  int* nchgbds, /**< buffer where to add the the number of changed bounds */
10775  SCIP_Bool* redundant /**< buffer where to store whether constraint has been found to be redundant */
10776  )
10777 { /*lint --e{666}*/
10778  SCIP_CONSDATA* consdata;
10779  SCIP_INTERVAL consbounds; /* lower and upper bounds of constraint */
10780  SCIP_INTERVAL consactivity; /* activity of linear plus quadratic part */
10781  SCIP_Real intervalinfty; /* infinity used for interval computation */
10782  SCIP_Real minquadactivity; /* lower bound on finite activities of quadratic part */
10783  SCIP_Real maxquadactivity; /* upper bound on finite activities of quadratic part */
10784  int quadminactinf; /* number of quadratic variables that contribute -infinity to minimal activity of quadratic term */
10785  int quadmaxactinf; /* number of quadratic variables that contribute +infinity to maximal activity of quadratic term */
10786  SCIP_INTERVAL* quadactcontr; /* contribution of each quadratic variable term to quadactivity */
10787 
10788  SCIP_VAR* var;
10789  SCIP_INTERVAL rhs; /* right hand side of quadratic equation */
10790  SCIP_INTERVAL tmp;
10791  SCIP_ROUNDMODE roundmode;
10792  SCIP_Real bnd;
10793  int i;
10794 
10795  assert(scip != NULL);
10796  assert(conshdlr != NULL);
10797  assert(cons != NULL);
10798  assert(result != NULL);
10799  assert(nchgbds != NULL);
10800  assert(redundant != NULL);
10801 
10802  consdata = SCIPconsGetData(cons);
10803  assert(consdata != NULL);
10804 
10805  *result = SCIP_DIDNOTRUN;
10806  *redundant = FALSE;
10807 
10808  *result = SCIP_DIDNOTFIND;
10809 
10810  intervalinfty = 1000 * SCIPinfinity(scip) * SCIPinfinity(scip);
10811 
10812  quadactcontr = NULL;
10813  quadminactinf = -1;
10814  quadmaxactinf = -1;
10815 
10816  SCIPdebugMsg(scip, "start domain propagation for constraint <%s>\n", SCIPconsGetName(cons));
10817 
10818  /* make sure we have activity of linear term and that they are consistent */
10819  consdataUpdateLinearActivity(scip, consdata, intervalinfty);
10820  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
10821  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
10822  assert(consdata->minlinactivityinf >= 0);
10823  assert(consdata->maxlinactivityinf >= 0);
10824 
10825  /* sort quadratic variable terms, in case we need to search for terms occuring in bilinear terms later
10826  * we sort here already, since we rely on a constant variable order during this method
10827  */
10828  if( consdata->nbilinterms > 0 )
10829  {
10830  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
10831  }
10832 
10833  /* compute activity of quad term part, if not up to date
10834  * in that case, we also collect the contribution of each quad var term for later */
10835  if( SCIPintervalIsEmpty(intervalinfty, consdata->quadactivitybounds) )
10836  {
10837  SCIP_CALL( SCIPallocBufferArray(scip, &quadactcontr, consdata->nquadvars) );
10838  propagateBoundsGetQuadActivity(scip, consdata, intervalinfty, &minquadactivity, &maxquadactivity, &quadminactinf, &quadmaxactinf, quadactcontr);
10839  assert(!SCIPintervalIsEmpty(intervalinfty, consdata->quadactivitybounds));
10840  }
10841 
10842  SCIPdebugMsg(scip, "linear activity: [%g, %g] quadratic activity: [%g, %g]\n",
10843  (consdata->minlinactivityinf > 0 ? -intervalinfty : consdata->minlinactivity),
10844  (consdata->maxlinactivityinf > 0 ? intervalinfty : consdata->maxlinactivity),
10845  consdata->quadactivitybounds.inf, consdata->quadactivitybounds.sup);
10846 
10847  /* extend constraint bounds by epsilon to avoid some numerical difficulties */
10848  SCIPintervalSetBounds(&consbounds,
10849  -infty2infty(SCIPinfinity(scip), intervalinfty, -consdata->lhs+SCIPepsilon(scip)),
10850  +infty2infty(SCIPinfinity(scip), intervalinfty, consdata->rhs+SCIPepsilon(scip)));
10851 
10852  /* check redundancy and infeasibility */
10853  SCIPintervalSetBounds(&consactivity, consdata->minlinactivityinf > 0 ? -intervalinfty : consdata->minlinactivity,
10854  consdata->maxlinactivityinf > 0 ? intervalinfty : consdata->maxlinactivity);
10855  SCIPintervalAdd(intervalinfty, &consactivity, consactivity, consdata->quadactivitybounds);
10856  if( SCIPintervalIsSubsetEQ(intervalinfty, consactivity, consbounds) )
10857  {
10858  SCIPdebugMsg(scip, "found constraint <%s> to be redundant: sides: [%g, %g], activity: [%g, %g]\n",
10859  SCIPconsGetName(cons), consdata->lhs, consdata->rhs, SCIPintervalGetInf(consactivity), SCIPintervalGetSup(consactivity));
10860  *redundant = TRUE;
10861  goto CLEANUP;
10862  }
10863 
10864  /* was SCIPintervalAreDisjoint(consbounds, consactivity), but that would allow violations up to eps only
10865  * we need to decide feasibility w.r.t. feastol (but still want to propagate w.r.t. eps)
10866  */
10867  if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisGT(scip, consdata->lhs-SCIPfeastol(scip), SCIPintervalGetSup(consactivity))) ||
10868  (!SCIPisInfinity(scip, consdata->rhs) && SCIPisLT(scip, consdata->rhs+SCIPfeastol(scip), SCIPintervalGetInf(consactivity))) )
10869  {
10870  SCIPdebugMsg(scip, "found constraint <%s> to be infeasible; sides: [%g, %g], activity: [%g, %g], infeas: %g\n",
10871  SCIPconsGetName(cons), consdata->lhs, consdata->rhs, SCIPintervalGetInf(consactivity), SCIPintervalGetSup(consactivity),
10872  MAX(consdata->lhs - SCIPintervalGetSup(consactivity), SCIPintervalGetInf(consactivity) - consdata->rhs));
10873  *result = SCIP_CUTOFF;
10874  goto CLEANUP;
10875  }
10876 
10877  /* propagate linear part \in rhs = consbounds - quadactivity (use the one from consdata, since that includes infinities) */
10878  SCIPintervalSub(intervalinfty, &rhs, consbounds, consdata->quadactivitybounds);
10879  if( !SCIPintervalIsEntire(intervalinfty, rhs) )
10880  {
10881  SCIP_Real coef;
10882 
10883  for( i = 0; i < consdata->nlinvars; ++i )
10884  {
10885  coef = consdata->lincoefs[i];
10886  var = consdata->linvars[i];
10887 
10888  /* skip fixed variables
10889  * @todo is that a good or a bad idea?
10890  * we can't expect much more tightening, but may detect infeasiblity, but shouldn't the check on the constraints activity detect that?
10891  */
10892  if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
10893  continue;
10894 
10895  /* due to large variable bounds and large coefficients, it might happen that the activity of the linear part
10896  * exceeds +/-SCIPinfinity() after updating the activities in consdataUpdateLinearActivity{Lb,Ub}Change; in
10897  * order to detect this case we need to check whether the value of consdata->{min,max}linactivity is infinite
10898  * (see #1433)
10899  */
10900  if( coef > 0.0 )
10901  {
10902  if( SCIPintervalGetSup(rhs) < intervalinfty )
10903  {
10904  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
10905  /* try to tighten the upper bound on var x */
10906  if( consdata->minlinactivityinf == 0 && !SCIPisInfinity(scip, -consdata->minlinactivity) )
10907  {
10908  assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
10909  /* tighten upper bound on x to (rhs.sup - (minlinactivity - coef * xlb)) / coef */
10910  roundmode = SCIPintervalGetRoundingMode();
10912  bnd = SCIPintervalGetSup(rhs);
10913  bnd -= consdata->minlinactivity;
10914  bnd += coef * SCIPvarGetLbLocal(var);
10915  bnd /= coef;
10916  SCIPintervalSetRoundingMode(roundmode);
10917  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10918  if( *result == SCIP_CUTOFF )
10919  break;
10920  }
10921  else if( consdata->minlinactivityinf == 1 && SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
10922  {
10923  /* x was the variable that made the minimal linear activity equal -infinity, so
10924  * we tighten upper bound on x to just (rhs.sup - minlinactivity) / coef */
10925  roundmode = SCIPintervalGetRoundingMode();
10927  bnd = SCIPintervalGetSup(rhs);
10928  bnd -= consdata->minlinactivity;
10929  bnd /= coef;
10930  SCIPintervalSetRoundingMode(roundmode);
10931  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10932  if( *result == SCIP_CUTOFF )
10933  break;
10934  }
10935  /* otherwise the minimal activity is -infinity and x is not solely responsible for this */
10936  }
10937 
10938  if( SCIPintervalGetInf(rhs) > -intervalinfty )
10939  {
10940  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
10941  /* try to tighten the lower bound on var x */
10942  if( consdata->maxlinactivityinf == 0 && !SCIPisInfinity(scip, consdata->maxlinactivity) )
10943  {
10944  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
10945  /* tighten lower bound on x to (rhs.inf - (maxlinactivity - coef * xub)) / coef */
10946  roundmode = SCIPintervalGetRoundingMode();
10948  bnd = SCIPintervalGetInf(rhs);
10949  bnd -= consdata->maxlinactivity;
10950  bnd += coef * SCIPvarGetUbLocal(var);
10951  bnd /= coef;
10952  SCIPintervalSetRoundingMode(roundmode);
10953  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10954  if( *result == SCIP_CUTOFF )
10955  break;
10956  }
10957  else if( consdata->maxlinactivityinf == 1 && SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
10958  {
10959  /* x was the variable that made the maximal linear activity equal infinity, so
10960  * we tighten upper bound on x to just (rhs.inf - maxlinactivity) / coef */
10961  roundmode = SCIPintervalGetRoundingMode();
10963  bnd = SCIPintervalGetInf(rhs);
10964  bnd -= consdata->maxlinactivity;
10965  bnd /= coef;
10966  SCIPintervalSetRoundingMode(roundmode);
10967  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10968  if( *result == SCIP_CUTOFF )
10969  break;
10970  }
10971  /* otherwise the maximal activity is +infinity and x is not solely responsible for this */
10972  }
10973  }
10974  else
10975  {
10976  assert(coef < 0.0 );
10977  if( SCIPintervalGetInf(rhs) > -intervalinfty )
10978  {
10979  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
10980  /* try to tighten the upper bound on var x */
10981  if( consdata->maxlinactivityinf == 0 && !SCIPisInfinity(scip, consdata->maxlinactivity) )
10982  {
10983  assert(!SCIPisInfinity(scip, SCIPvarGetLbLocal(var)));
10984  /* compute upper bound on x to (maxlinactivity - coef * xlb) - rhs.inf / (-coef) */
10985  roundmode = SCIPintervalGetRoundingMode();
10987  bnd = consdata->maxlinactivity;
10988  bnd += (-coef) * SCIPvarGetLbLocal(var);
10989  bnd -= SCIPintervalGetInf(rhs);
10990  bnd /= (-coef);
10991  SCIPintervalSetRoundingMode(roundmode);
10992  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10993  if( *result == SCIP_CUTOFF )
10994  break;
10995  }
10996  else if( consdata->maxlinactivityinf == 1 && SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
10997  {
10998  /* x was the variable that made the maximal linear activity equal infinity, so
10999  * we tighten upper bound on x to just (maxlinactivity - rhs.inf) / (-coef) */
11000  roundmode = SCIPintervalGetRoundingMode();
11002  bnd = consdata->maxlinactivity;
11003  bnd -= SCIPintervalGetInf(rhs);
11004  bnd /= (-coef);
11005  SCIPintervalSetRoundingMode(roundmode);
11006  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
11007  if( *result == SCIP_CUTOFF )
11008  break;
11009  }
11010  /* otherwise the maximal activity is infinity and x is not solely responsible for this */
11011  }
11012 
11013  if( SCIPintervalGetSup(rhs) < intervalinfty )
11014  {
11015  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
11016  /* try to tighten the lower bound on var x */
11017  if( consdata->minlinactivityinf == 0 && !SCIPisInfinity(scip, -consdata->minlinactivity) )
11018  {
11019  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
11020  /* compute lower bound on x to (minlinactivity - coef * xub) - rhs.sup / (-coef) */
11021  roundmode = SCIPintervalGetRoundingMode();
11023  bnd = consdata->minlinactivity;
11024  bnd += (-coef) * SCIPvarGetUbLocal(var);
11025  bnd -= SCIPintervalGetSup(rhs);
11026  bnd /= (-coef);
11027  SCIPintervalSetRoundingMode(roundmode);
11028  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
11029  if( *result == SCIP_CUTOFF )
11030  break;
11031  }
11032  else if( consdata->minlinactivityinf == 1 && SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
11033  {
11034  /* x was the variable that made the maximal linear activity equal -infinity, so
11035  * we tighten lower bound on x to just (minlinactivity - rhs.sup) / (-coef) */
11036  roundmode = SCIPintervalGetRoundingMode();
11038  bnd = consdata->minlinactivity;
11039  bnd -= SCIPintervalGetSup(rhs);
11040  bnd /= (-coef);
11041  SCIPintervalSetRoundingMode(roundmode);
11042  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
11043  if( *result == SCIP_CUTOFF )
11044  break;
11045  }
11046  /* otherwise the minimal activity is -infinity and x is not solely responsible for this */
11047  }
11048  }
11049  }
11050  if( *result == SCIP_CUTOFF )
11051  goto CLEANUP;
11052  }
11053 
11054  /* propagate quadratic part \in rhs = consbounds - linactivity */
11055  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
11056  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
11057  consdataUpdateLinearActivity(scip, consdata, intervalinfty); /* make sure, activities of linear part did not become invalid by above bound changes, if any */
11058  assert(consdata->minlinactivityinf > 0 || consdata->maxlinactivityinf > 0 || consdata->minlinactivity <= consdata->maxlinactivity);
11059  SCIPintervalSetBounds(&tmp,
11060  (consdata->minlinactivityinf > 0 ? -intervalinfty : consdata->minlinactivity),
11061  (consdata->maxlinactivityinf > 0 ? intervalinfty : consdata->maxlinactivity));
11062  SCIPintervalSub(intervalinfty, &rhs, consbounds, tmp);
11063  if( !SCIPintervalIsEntire(intervalinfty, rhs) )
11064  {
11065  if( consdata->nquadvars == 1 )
11066  {
11067  /* quadratic part is just a*x^2+b*x -> a common case that we treat directly */
11068  SCIP_INTERVAL lincoef; /* linear coefficient of quadratic equation */
11069 
11070  assert(consdata->nbilinterms == 0);
11071 
11072  var = consdata->quadvarterms[0].var;
11073  SCIPintervalSet(&lincoef, consdata->quadvarterms[0].lincoef);
11074 
11075  /* propagate a*x^2 + b*x \in rhs */
11076  SCIP_CALL( propagateBoundsQuadVar(scip, cons, intervalinfty, var, consdata->quadvarterms[0].sqrcoef, lincoef, rhs, result, nchgbds) );
11077  }
11078  else if( consdata->nbilinterms == 1 && consdata->nquadvars == 2 )
11079  {
11080  /* quadratic part is just ax*x^2+bx*x + ay*y^2+by*y + c*xy -> a common case that we treat directly */
11081  assert(consdata->bilinterms[0].var1 == consdata->quadvarterms[0].var || consdata->bilinterms[0].var1 == consdata->quadvarterms[1].var);
11082  assert(consdata->bilinterms[0].var2 == consdata->quadvarterms[0].var || consdata->bilinterms[0].var2 == consdata->quadvarterms[1].var);
11083 
11084  /* 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 */
11085  SCIP_CALL( propagateBoundsBilinearTerm(scip, cons, intervalinfty,
11086  consdata->quadvarterms[0].var, consdata->quadvarterms[0].sqrcoef, consdata->quadvarterms[0].lincoef,
11087  consdata->quadvarterms[1].var, consdata->quadvarterms[1].sqrcoef, consdata->quadvarterms[1].lincoef,
11088  consdata->bilinterms[0].coef,
11089  rhs, result, nchgbds) );
11090  if( *result != SCIP_CUTOFF )
11091  {
11092  /* 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 */
11093  SCIP_CALL( propagateBoundsBilinearTerm(scip, cons, intervalinfty,
11094  consdata->quadvarterms[1].var, consdata->quadvarterms[1].sqrcoef, consdata->quadvarterms[1].lincoef,
11095  consdata->quadvarterms[0].var, consdata->quadvarterms[0].sqrcoef, consdata->quadvarterms[0].lincoef,
11096  consdata->bilinterms[0].coef,
11097  rhs, result, nchgbds) );
11098  }
11099  }
11100  else
11101  {
11102  /* general case */
11103 
11104  /* compute "advanced" information on quad var term activities, if not up-to-date */
11105  if( quadminactinf == -1 )
11106  {
11107  assert(quadactcontr == NULL);
11108  SCIP_CALL( SCIPallocBufferArray(scip, &quadactcontr, consdata->nquadvars) );
11109  propagateBoundsGetQuadActivity(scip, consdata, intervalinfty, &minquadactivity, &maxquadactivity, &quadminactinf, &quadmaxactinf, quadactcontr);
11110  }
11111  assert(quadactcontr != NULL);
11112  assert(quadminactinf >= 0);
11113  assert(quadmaxactinf >= 0);
11114 
11115  /* if the quad activities are not hopelessly unbounded on useful sides, try to deduce domain reductions on quad vars */
11116  if( (SCIPintervalGetSup(rhs) < intervalinfty && quadminactinf <= 1) ||
11117  ( SCIPintervalGetInf(rhs) > -intervalinfty && quadmaxactinf <= 1) )
11118  {
11119  SCIP_INTERVAL lincoef;
11120  SCIP_INTERVAL rhs2;
11121  int j;
11122  int k;
11123 
11124  for( i = 0; i < consdata->nquadvars; ++i )
11125  {
11126  var = consdata->quadvarterms[i].var;
11127 
11128  /* skip fixed variables
11129  * @todo is that a good or a bad idea?
11130  * we can't expect much more tightening, but may detect infeasiblity, but shouldn't the check on the constraints activity detect that?
11131  */
11132  if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
11133  continue;
11134 
11135  /* compute rhs2 such that we can propagate quadvarterm(x_i) \in rhs2 */
11136 
11137  /* setup rhs2.sup = rhs.sup - (quadactivity.inf - quadactcontr[i].inf), if everything were finite
11138  * if only quadactcontr[i].inf is infinite (i.e., the other i are all finite), we just get rhs2.sup = rhs.sup
11139  * otherwise we get rhs2.sup = infinity */
11140  if( SCIPintervalGetSup(rhs) < intervalinfty )
11141  {
11142  if( quadminactinf == 0 || (quadminactinf == 1 && SCIPintervalGetInf(quadactcontr[i]) <= -intervalinfty) )
11143  {
11144  roundmode = SCIPintervalGetRoundingMode();
11146  rhs2.sup = rhs.sup - minquadactivity; /*lint !e644*/
11147  /* if the residual quad min activity w.r.t. quad var term i is finite and nonzero, so add it to right hand side */
11148  if( quadminactinf == 0 && SCIPintervalGetInf(quadactcontr[i]) != 0.0 )
11149  rhs2.sup += SCIPintervalGetInf(quadactcontr[i]);
11150  SCIPintervalSetRoundingMode(roundmode);
11151  }
11152  else
11153  {
11154  /* there are either >= 2 quad var terms contributing -infinity, or there is one which is not i */
11155  rhs2.sup = intervalinfty;
11156  }
11157  }
11158  else
11159  {
11160  rhs2.sup = intervalinfty;
11161  }
11162 
11163  /* setup rhs2.inf = rhs.inf - (quadactivity.sup - quadactcontr[i].sup), see also above */
11164  if( SCIPintervalGetInf(rhs) > -intervalinfty )
11165  {
11166  if( quadmaxactinf == 0 || (quadmaxactinf == 1 && SCIPintervalGetSup(quadactcontr[i]) >= intervalinfty) )
11167  {
11168  roundmode = SCIPintervalGetRoundingMode();
11170  rhs2.inf = rhs.inf - maxquadactivity; /*lint !e644*/
11171  /* if the residual quad max activity w.r.t. quad var term i is finite and nonzero, so add it to right hand side */
11172  if( quadmaxactinf == 0 && SCIPintervalGetSup(quadactcontr[i]) != 0.0 )
11173  rhs2.inf += SCIPintervalGetSup(quadactcontr[i]);
11174  SCIPintervalSetRoundingMode(roundmode);
11175  }
11176  else
11177  {
11178  /* there are either >= 2 quad var terms contributing infinity, or there is one which is not i */
11179  rhs2.inf = -intervalinfty;
11180  }
11181  }
11182  else
11183  {
11184  rhs2.inf = -intervalinfty;
11185  }
11186  assert(!SCIPintervalIsEmpty(intervalinfty, rhs2));
11187 
11188  /* if rhs2 is entire, then there is nothing we could propagate */
11189  if( SCIPintervalIsEntire(intervalinfty, rhs2) )
11190  continue;
11191 
11192  /* assemble linear coefficient for quad equation a*x^2 + b*x \in rhs2 */
11193  SCIPintervalSet(&lincoef, consdata->quadvarterms[i].lincoef);
11194  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
11195  {
11196  k = consdata->quadvarterms[i].adjbilin[j];
11197 #if 1
11198  if( consdata->bilinterms[k].var1 == var )
11199  {
11200  /* bilinear term k contributes to the activity of quad var term i, so just add bounds to linear coef */
11201  SCIPintervalSetBounds(&tmp,
11202  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
11203  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
11204  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
11205  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
11206  }
11207  else
11208  {
11209  /* bilinear term k does not contribute to the activity of quad var term i
11210  * so bounds on term k are contained in rhs2
11211  * if they are finite, we try to remove them from rhs2 and update lincoef instead
11212  * 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
11213  * HOWEVER: when computing rhs2, we may not just have added the bounds for the bilinear term, but for the associated quadratic term
11214  * for this complete term, we used SCIPintervalQuad to compute the bounds
11215  * since we do not want to repeat a call to SCIPintervalQuad for that quadratic term with bilinear term k removed,
11216  * we only remove the bounds for the bilinear term k from rhs2 if the associated quadratic term consists only of this bilinear term,
11217  * i.e., the quadratic term corresponding to var1 should be only var1*var2, but have no square or linear coefs or other bilinear terms
11218  * (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)
11219  */
11220  SCIP_INTERVAL me;
11221  SCIP_INTERVAL bilinbounds;
11222  int otherpos;
11223 
11224  assert(consdata->bilinterms[k].var2 == var);
11225 
11226  assert(consdata->quadvarssorted);
11227  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->bilinterms[k].var1, &otherpos) );
11228  assert(otherpos >= 0);
11229  assert(consdata->quadvarterms[otherpos].var == consdata->bilinterms[k].var1);
11230 
11231  if( (consdata->quadvarterms[otherpos].sqrcoef != 0.0) || consdata->quadvarterms[otherpos].lincoef != 0.0 ||
11232  consdata->quadvarterms[otherpos].nadjbilin > 1 )
11233  continue;
11234 
11235  /* set tmp to bounds of other variable and multiply with bilin coef */
11236  SCIPintervalSetBounds(&tmp,
11237  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var1), SCIPvarGetUbLocal(consdata->bilinterms[k].var1))),
11238  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var1), SCIPvarGetUbLocal(consdata->bilinterms[k].var1))));
11239  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
11240 
11241  /* set me to bounds of i'th variable */
11243  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
11244  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
11245 
11246  /* remove me*tmp from rhs2 */
11247 
11248  roundmode = SCIPintervalGetRoundingMode();
11249 
11250  if( rhs2.inf > -intervalinfty )
11251  {
11252  /* need upward rounding for SCIPintervalMulSup */
11254  SCIPintervalMulSup(intervalinfty, &bilinbounds, me, tmp);
11255  /* rhs2.inf += bilinbounds.sup, but we are in upward rounding */
11256  if( bilinbounds.sup < intervalinfty )
11257  rhs2.inf = SCIPintervalNegateReal(SCIPintervalNegateReal(rhs2.inf) - bilinbounds.sup);
11258  }
11259 
11260  if( rhs2.sup < intervalinfty )
11261  {
11262  /* need downward rounding for SCIPintervalMulInf */
11264  SCIPintervalMulInf(intervalinfty, &bilinbounds, me, tmp);
11265  /* rhs2.sup += bilinbounds.inf, but we are in downward rounding */
11266  if( bilinbounds.inf > -intervalinfty )
11267  rhs2.sup = SCIPintervalNegateReal(SCIPintervalNegateReal(rhs2.sup) - bilinbounds.inf);
11268  }
11269 
11270  SCIPintervalSetRoundingMode(roundmode);
11271 
11272  /* in theory, rhs2 should not be empty here
11273  * what we tried to do here is to remove the contribution of the k'th bilinear term (=bilinbounds) to [minquadactivity,maxquadactivity] from rhs2
11274  * however, quadactivity is computed differently (as x*(a1*y1+...+an*yn)) than bilinbounds (a*ak*yk) and since interval arithmetics do overestimation,
11275  * it can happen that bilinbounds is actually slightly larger than quadactivity, which results in rhs2 being (slightly) empty
11276  * 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
11277  * also infinite bounds into account, this complicates the code even further
11278  * instead, I'll just work around this by turning an empty rhs2 into a small non-empty one
11279  */
11280  if( SCIPintervalIsEmpty(intervalinfty, rhs2) )
11281  {
11282  assert(SCIPisSumRelEQ(scip, rhs2.inf, rhs2.sup));
11283  SCIPswapReals(&rhs2.inf, &rhs2.sup);
11284  }
11285 
11286  /* add tmp to lincoef */
11287  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
11288  }
11289 #else
11290  if( consdata->bilinterms[k].var1 != var )
11291  continue; /* this term does not contribute to the activity of quad var term i */
11292 
11293  SCIPintervalSetBounds(&tmp,
11294  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
11295  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
11296  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
11297  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
11298 #endif
11299  }
11300 
11301  /* deduce domain reductions for x_i */
11302  SCIP_CALL( propagateBoundsQuadVar(scip, cons, intervalinfty, var, consdata->quadvarterms[i].sqrcoef, lincoef, rhs2, result, nchgbds) );
11303  if( *result == SCIP_CUTOFF )
11304  goto CLEANUP;
11305  }
11306  }
11307  }
11308  }
11309 
11310  CLEANUP:
11311  SCIPfreeBufferArrayNull(scip, &quadactcontr);
11312 
11313  return SCIP_OKAY;
11314 }
11315 
11316 /** calls domain propagation for a set of constraints */
11317 static
11319  SCIP* scip, /**< SCIP data structure */
11320  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11321  SCIP_CONS** conss, /**< constraints to process */
11322  int nconss, /**< number of constraints */
11323  SCIP_RESULT* result, /**< pointer to store the result of the propagation calls */
11324  int* nchgbds /**< buffer where to add the the number of changed bounds */
11325  )
11326 {
11327  SCIP_CONSHDLRDATA* conshdlrdata;
11328  SCIP_RESULT propresult;
11329  SCIP_Bool redundant;
11330  int c;
11331  int roundnr;
11332  SCIP_Bool success;
11333  int maxproprounds;
11334 
11335  assert(scip != NULL);
11336  assert(conshdlr != NULL);
11337  assert(conss != NULL || nconss == 0);
11338  assert(result != NULL);
11339  assert(nchgbds != NULL);
11340 
11342 
11343  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11344  assert(conshdlrdata != NULL);
11345 
11346  *result = SCIP_DIDNOTFIND;
11347  roundnr = 0;
11348  if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING )
11349  maxproprounds = conshdlrdata->maxproproundspresolve;
11350  else
11351  maxproprounds = conshdlrdata->maxproprounds;
11352 
11353  do
11354  {
11355  success = FALSE;
11356  ++roundnr;
11357 
11358  SCIPdebugMsg(scip, "starting domain propagation round %d of %d for %d constraints\n", roundnr, maxproprounds, nconss);
11359 
11360  for( c = 0; c < nconss && *result != SCIP_CUTOFF; ++c )
11361  {
11362  assert(conss != NULL);
11363  if( !SCIPconsIsEnabled(conss[c]) )
11364  continue;
11365 
11366  if( SCIPconsIsMarkedPropagate(conss[c]) )
11367  {
11368  /* unmark constraint for propagation */
11369  SCIP_CALL( SCIPunmarkConsPropagate(scip, conss[c]) );
11370 
11371  SCIP_CALL( propagateBoundsCons(scip, conshdlr, conss[c], &propresult, nchgbds, &redundant) );
11372  if( propresult != SCIP_DIDNOTFIND && propresult != SCIP_DIDNOTRUN )
11373  {
11374  *result = propresult;
11375  success = TRUE;
11376  }
11377  if( redundant )
11378  {
11379  SCIPdebugMsg(scip, "deleting constraint <%s> locally\n", SCIPconsGetName(conss[c]));
11380  SCIP_CALL( SCIPdelConsLocal(scip, conss[c]) );
11381  }
11382  }
11383  }
11384  }
11385  while( success && *result != SCIP_CUTOFF && roundnr < maxproprounds );
11386 
11387  return SCIP_OKAY;
11388 }
11389 
11390 /** checks for a linear variable that can be increase or decreased without harming feasibility */
11391 static
11393  SCIP* scip, /**< SCIP data structure */
11394  SCIP_CONSDATA* consdata /**< constraint data */
11395  )
11396 {
11397  int i;
11398  int poslock;
11399  int neglock;
11400 
11401  consdata->linvar_maydecrease = -1;
11402  consdata->linvar_mayincrease = -1;
11403 
11404  /* check for a linear variable that can be increase or decreased without harming feasibility */
11405  for( i = 0; i < consdata->nlinvars; ++i )
11406  {
11407  /* compute locks of i'th linear variable */
11408  assert(consdata->lincoefs[i] != 0.0);
11409  if( consdata->lincoefs[i] > 0.0 )
11410  {
11411  poslock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
11412  neglock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
11413  }
11414  else
11415  {
11416  poslock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
11417  neglock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
11418  }
11419 
11420  if( SCIPvarGetNLocksDownType(consdata->linvars[i], SCIP_LOCKTYPE_MODEL) - neglock == 0 )
11421  {
11422  /* for a*x + q(y) \in [lhs, rhs], we can decrease x without harming other constraints */
11423  /* if we have already one candidate, then take the one where the loss in the objective function is less */
11424  if( (consdata->linvar_maydecrease < 0) ||
11425  (SCIPvarGetObj(consdata->linvars[consdata->linvar_maydecrease]) / consdata->lincoefs[consdata->linvar_maydecrease] > SCIPvarGetObj(consdata->linvars[i]) / consdata->lincoefs[i]) )
11426  consdata->linvar_maydecrease = i;
11427  }
11428 
11429  if( SCIPvarGetNLocksDownType(consdata->linvars[i], SCIP_LOCKTYPE_MODEL) - poslock == 0 )
11430  {
11431  /* for a*x + q(y) \in [lhs, rhs], we can increase x without harm */
11432  /* if we have already one candidate, then take the one where the loss in the objective function is less */
11433  if( (consdata->linvar_mayincrease < 0) ||
11434  (SCIPvarGetObj(consdata->linvars[consdata->linvar_mayincrease]) / consdata->lincoefs[consdata->linvar_mayincrease] > SCIPvarGetObj(consdata->linvars[i]) / consdata->lincoefs[i]) )
11435  consdata->linvar_mayincrease = i;
11436  }
11437  }
11438 
11439 #ifdef SCIP_DEBUG
11440  if( consdata->linvar_mayincrease >= 0 )
11441  {
11442  SCIPdebugMsg(scip, "may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvars[consdata->linvar_mayincrease]));
11443  }
11444  if( consdata->linvar_maydecrease >= 0 )
11445  {
11446  SCIPdebugMsg(scip, "may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvars[consdata->linvar_maydecrease]));
11447  }
11448 #endif
11449 }
11450 
11451 /** Given a solution where every quadratic constraint is either feasible or can be made feasible by
11452  * moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
11453  *
11454  * The method assumes that this is always possible and that not all constraints are feasible already.
11455  */
11456 static
11458  SCIP* scip, /**< SCIP data structure */
11459  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11460  SCIP_CONS** conss, /**< constraints to process */
11461  int nconss, /**< number of constraints */
11462  SCIP_SOL* sol, /**< solution to process */
11463  SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
11464  )
11465 {
11466  SCIP_CONSHDLRDATA* conshdlrdata;
11467  SCIP_CONSDATA* consdata;
11468  SCIP_SOL* newsol;
11469  SCIP_VAR* var;
11470  int c;
11471  SCIP_Real viol;
11472  SCIP_Real delta;
11473  SCIP_Real gap;
11474  SCIP_Bool solviolbounds;
11475 
11476  assert(scip != NULL);
11477  assert(conshdlr != NULL);
11478  assert(conss != NULL || nconss == 0);
11479  assert(success != NULL);
11480 
11481  *success = FALSE;
11482 
11483  /* don't propose new solutions if not in presolve or solving */
11485  return SCIP_OKAY;
11486 
11487  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11488  assert(conshdlrdata != NULL);
11489 
11490  if( sol != NULL )
11491  {
11492  SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
11493  }
11494  else
11495  {
11496  SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
11497  }
11498  SCIP_CALL( SCIPunlinkSol(scip, newsol) );
11499  SCIPdebugMsg(scip, "attempt to make solution from <%s> feasible by shifting linear variable\n",
11500  sol != NULL ? (SCIPsolGetHeur(sol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(sol)) : "tree") : "LP");
11501 
11502  for( c = 0; c < nconss; ++c )
11503  {
11504  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
11505  assert(consdata != NULL);
11506 
11507  /* recompute violation of solution in case solution has changed
11508  * get absolution violation and sign
11509  * @todo do this only if solution has changed
11510  */
11511  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
11512  {
11513  SCIP_CALL( computeViolation(scip, conss[c], newsol, &solviolbounds) ); /*lint !e613*/
11514  assert(!solviolbounds);
11515  viol = consdata->lhs - consdata->activity;
11516  }
11517  else if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
11518  {
11519  SCIP_CALL( computeViolation(scip, conss[c], newsol, &solviolbounds) ); /*lint !e613*/
11520  assert(!solviolbounds);
11521  viol = consdata->rhs - consdata->activity;
11522  }
11523  else
11524  continue; /* constraint is satisfied */
11525 
11526  assert(viol != 0.0);
11527  if( consdata->linvar_mayincrease >= 0 &&
11528  ((viol > 0.0 && consdata->lincoefs[consdata->linvar_mayincrease] > 0.0) || (viol < 0.0 && consdata->lincoefs[consdata->linvar_mayincrease] < 0.0)) )
11529  {
11530  /* have variable where increasing makes the constraint less violated */
11531  var = consdata->linvars[consdata->linvar_mayincrease];
11532  /* compute how much we would like to increase var */
11533  delta = viol / consdata->lincoefs[consdata->linvar_mayincrease];
11534  assert(delta > 0.0);
11535  /* if var has an upper bound, may need to reduce delta */
11536  if( !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
11537  {
11538  gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
11539  delta = MIN(MAX(0.0, gap), delta);
11540  }
11541  if( SCIPisPositive(scip, delta) )
11542  {
11543  /* if variable is integral, round delta up so that it will still have an integer value */
11544  if( SCIPvarIsIntegral(var) )
11545  delta = SCIPceil(scip, delta);
11546 
11547  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
11548  /*lint --e{613} */
11549  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]));
11550 
11551  /* adjust constraint violation, if satisfied go on to next constraint */
11552  viol -= consdata->lincoefs[consdata->linvar_mayincrease] * delta;
11553  if( SCIPisZero(scip, viol) )
11554  continue;
11555  }
11556  }
11557 
11558  assert(viol != 0.0);
11559  if( consdata->linvar_maydecrease >= 0 &&
11560  ((viol > 0.0 && consdata->lincoefs[consdata->linvar_maydecrease] < 0.0) || (viol < 0.0 && consdata->lincoefs[consdata->linvar_maydecrease] > 0.0)) )
11561  {
11562  /* have variable where decreasing makes constraint less violated */
11563  var = consdata->linvars[consdata->linvar_maydecrease];
11564  /* compute how much we would like to decrease var */
11565  delta = viol / consdata->lincoefs[consdata->linvar_maydecrease];
11566  assert(delta < 0.0);
11567  /* if var has a lower bound, may need to reduce delta */
11568  if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) )
11569  {
11570  gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
11571  delta = MAX(MIN(0.0, gap), delta);
11572  }
11573  if( SCIPisNegative(scip, delta) )
11574  {
11575  /* if variable is integral, round delta down so that it will still have an integer value */
11576  if( SCIPvarIsIntegral(var) )
11577  delta = SCIPfloor(scip, delta);
11578  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
11579  /*lint --e{613} */
11580  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]));
11581 
11582  /* adjust constraint violation, if satisfied go on to next constraint */
11583  viol -= consdata->lincoefs[consdata->linvar_maydecrease] * delta;
11584  if( SCIPisZero(scip, viol) )
11585  continue;
11586  }
11587  }
11588 
11589  /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
11590  break;
11591  }
11592 
11593  /* if we have a solution that should satisfy all quadratic constraints and has a better objective than the current upper bound,
11594  * then pass it to the trysol heuristic
11595  */
11596  if( c == nconss && (SCIPisInfinity(scip, SCIPgetUpperbound(scip)) || SCIPisSumLT(scip, SCIPgetSolTransObj(scip, newsol), SCIPgetUpperbound(scip))) )
11597  {
11598  SCIPdebugMsg(scip, "pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
11599 
11600  assert(conshdlrdata->trysolheur != NULL);
11601  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
11602 
11603  *success = TRUE;
11604  }
11605 
11606  SCIP_CALL( SCIPfreeSol(scip, &newsol) );
11607 
11608  return SCIP_OKAY;
11609 }
11610 
11611 /** helper function to enforce constraints */
11612 static
11614  SCIP* scip, /**< SCIP data structure */
11615  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11616  SCIP_CONS** conss, /**< constraints to process */
11617  int nconss, /**< number of constraints */
11618  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
11619  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
11620  SCIP_Bool solinfeasible, /**< was the solution already declared infeasible by a constraint handler? */
11621  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
11622  )
11623 {
11624  SCIP_CONSHDLRDATA* conshdlrdata;
11625  SCIP_CONSDATA* consdata;
11626  SCIP_CONS* maxviolcon;
11627  SCIP_Real maxviol;
11628  SCIP_RESULT propresult;
11629  SCIP_RESULT separateresult;
11630  int nchgbds;
11631  int nnotify;
11632  SCIP_Real sepaefficacy;
11633  SCIP_Bool solviolbounds;
11634 
11635  assert(scip != NULL);
11636  assert(conshdlr != NULL);
11637  assert(conss != NULL || nconss == 0);
11638  assert(nconss >= 0);
11639  assert(nusefulconss >= 0);
11640  assert(result != NULL);
11641 
11642  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11643  assert(conshdlrdata != NULL);
11644 
11645  SCIP_CALL( computeViolations(scip, conss, nconss, sol, &solviolbounds, &maxviolcon) );
11646 
11647  if( maxviolcon == NULL )
11648  {
11649  *result = SCIP_FEASIBLE;
11650  return SCIP_OKAY;
11651  }
11652 
11653  *result = SCIP_INFEASIBLE;
11654 
11655  if( solviolbounds )
11656  {
11657  /* if LP solution violates variable bounds, then this should be because a row was added that
11658  * introduced this variable newly to the LP, in which case it gets value 0.0; the row should
11659  * have been added to resolve an infeasibility, so solinfeasible should be TRUE
11660  * see also issue #627
11661  */
11662  assert(solinfeasible);
11663  /* however, if solinfeasible is actually not TRUE, then better cut off the node to avoid that SCIP
11664  * stops because infeasible cannot be resolved */
11665  /*lint --e{774} */
11666  if( !solinfeasible )
11667  *result = SCIP_CUTOFF;
11668  return SCIP_OKAY;
11669  }
11670 
11671  consdata = SCIPconsGetData(maxviolcon);
11672  assert(consdata != NULL);
11673  maxviol = consdata->lhsviol + consdata->rhsviol;
11674  assert(SCIPisGT(scip, maxviol, SCIPfeastol(scip)));
11675 
11676  SCIPdebugMsg(scip, "enforcement with max violation %g in cons <%s> for %s solution\n", maxviol, SCIPconsGetName(maxviolcon),
11677  sol == NULL ? "LP" : "relaxation");
11678 
11679  /* if we are above the 100'th enforcement round for this node, something is strange
11680  * (maybe the LP / relaxator does not think that the cuts we add are violated, or we do ECP on a high-dimensional convex function)
11681  * 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
11682  * (in optimized more, returning SCIP_INFEASIBLE in *result would be sufficient, but in debug mode this would give an assert in scip.c)
11683  * the reason to wait for 100 rounds is to avoid calls to SCIPisStopped in normal runs, which may be expensive
11684  * we only increment nenforounds until 101 to avoid an overflow
11685  */
11686  if( conshdlrdata->lastenfonode == SCIPgetCurrentNode(scip) )
11687  {
11688  if( conshdlrdata->nenforounds > 100 )
11689  {
11690  if( SCIPisStopped(scip) )
11691  {
11692  SCIP_NODE* child;
11693 
11694  SCIP_CALL( SCIPcreateChild(scip, &child, 1.0, SCIPnodeGetEstimate(SCIPgetCurrentNode(scip))) );
11695  *result = SCIP_BRANCHED;
11696 
11697  return SCIP_OKAY;
11698  }
11699  }
11700 
11701  ++conshdlrdata->nenforounds;
11702 
11703  /* cut off the current subtree, if a limit on the enforcement rounds should be applied. At this point, feasible
11704  * solutions might get cut off; the enfolplimit parameter should therefore only be set if SCIP is used as a
11705  * heuristic solver and when the returned result (infeasible, optimal, the gap) can be ignored
11706  */
11707  if( conshdlrdata->enfolplimit != -1 && conshdlrdata->nenforounds > conshdlrdata->enfolplimit )
11708  {
11710  "cut off subtree because enforcement limit was reached; this might lead to incorrect results\n");
11711  *result = SCIP_CUTOFF;
11712  return SCIP_OKAY;
11713  }
11714  }
11715  else
11716  {
11717  conshdlrdata->lastenfonode = SCIPgetCurrentNode(scip);
11718  conshdlrdata->nenforounds = 0;
11719  }
11720 
11721  /* run domain propagation */
11722  nchgbds = 0;
11723  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, &propresult, &nchgbds) );
11724  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
11725  {
11726  SCIPdebugMsg(scip, "propagation succeeded (%s)\n", propresult == SCIP_CUTOFF ? "cutoff" : "reduceddom");
11727  *result = propresult;
11728  return SCIP_OKAY;
11729  }
11730 
11731  /* we would like a cut that is efficient enough that it is not redundant in the LP (>lpfeastol)
11732  * however, we also don't want very weak cuts, so try to reach at least feastol (=lpfeastol by default, though)
11733  */
11734  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, SCIPfeastol(scip), TRUE, &separateresult, &sepaefficacy) );
11735  if( separateresult == SCIP_CUTOFF )
11736  {
11737  SCIPdebugMsg(scip, "separation found cutoff\n");
11738  *result = SCIP_CUTOFF;
11739  return SCIP_OKAY;
11740  }
11741  if( separateresult == SCIP_SEPARATED )
11742  {
11743  SCIPdebugMsg(scip, "separation succeeded (bestefficacy = %g, minefficacy = %g)\n", sepaefficacy, SCIPfeastol(scip));
11744  *result = SCIP_SEPARATED;
11745  return SCIP_OKAY;
11746  }
11747 
11748  /* we are not feasible, the whole node is not infeasible, and we cannot find a good cut
11749  * -> collect variables for branching
11750  */
11751 
11752  SCIPdebugMsg(scip, "separation failed (bestefficacy = %g < %g = minefficacy ); max viol: %g\n", sepaefficacy, SCIPfeastol(scip), maxviol);
11753 
11754  /* find branching candidates */
11755  SCIP_CALL( registerBranchingCandidates(scip, conshdlr, conss, nconss, sol, &nnotify) );
11756 
11757  if( nnotify == 0 && !solinfeasible && SCIPfeastol(scip) > SCIPlpfeastol(scip) )
11758  {
11759  /* fallback 1: we also have no branching candidates, so try to find a weak cut */
11760  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, SCIPlpfeastol(scip), TRUE, &separateresult, &sepaefficacy) );
11761  if( separateresult == SCIP_CUTOFF )
11762  {
11763  SCIPdebugMsg(scip, "separation found cutoff\n");
11764  *result = SCIP_CUTOFF;
11765  return SCIP_OKAY;
11766  }
11767  if( separateresult == SCIP_SEPARATED )
11768  {
11769  SCIPdebugMsg(scip, "separation fallback succeeded, efficacy = %g\n", sepaefficacy);
11770  *result = SCIP_SEPARATED;
11771  return SCIP_OKAY;
11772  }
11773  }
11774 
11775  if( nnotify == 0 && !solinfeasible )
11776  {
11777  /* fallback 2: separation probably failed because of numerical difficulties with a convex constraint;
11778  * if noone declared solution infeasible yet and we had not even found a weak cut, try to resolve by branching
11779  */
11780  SCIP_VAR* brvar = NULL;
11781  SCIP_CALL( registerLargeRelaxValueVariableForBranching(scip, conss, nconss, sol, &brvar) );
11782  if( brvar == NULL )
11783  {
11784  /* fallback 3: all quadratic variables seem to be fixed -> replace by linear constraint */
11785  SCIP_Bool addedcons;
11786  SCIP_Bool reduceddom;
11787  SCIP_Bool infeasible;
11788 
11789  SCIP_CALL( replaceByLinearConstraints(scip, conss, nconss, &addedcons, &reduceddom, &infeasible) );
11790  /* if the linear constraints are actually feasible, then adding them and returning SCIP_CONSADDED confuses SCIP
11791  * when it enforces the new constraints again and nothing resolves the infeasibility that we declare here
11792  * thus, we only add them if considered violated, and otherwise claim the solution is feasible (but print a
11793  * warning) */
11794  if ( infeasible )
11795  *result = SCIP_CUTOFF;
11796  else if ( addedcons )
11797  *result = SCIP_CONSADDED;
11798  else if ( reduceddom )
11799  *result = SCIP_REDUCEDDOM;
11800  else
11801  {
11802  *result = SCIP_FEASIBLE;
11803  SCIPwarningMessage(scip, "could not enforce feasibility by separating or branching; declaring solution with viol %g as feasible\n", maxviol);
11804  assert(!SCIPisInfinity(scip, maxviol));
11805  }
11806  return SCIP_OKAY;
11807  }
11808  else
11809  {
11810  SCIPdebugMsg(scip, "Could not find any usual branching variable candidate. Proposed variable <%s> with LP value %g for branching.\n",
11811  SCIPvarGetName(brvar), SCIPgetSolVal(scip, sol, brvar));
11812  nnotify = 1;
11813  }
11814  }
11815 
11816  assert(*result == SCIP_INFEASIBLE && (solinfeasible || nnotify > 0));
11817  return SCIP_OKAY;
11818 }
11819 
11820 /** tries to upgrade a nonlinear constraint into a quadratic constraint */
11821 static
11822 SCIP_DECL_NONLINCONSUPGD(nonlinconsUpgdQuadratic)
11824  SCIP_EXPRGRAPH* exprgraph;
11825  SCIP_EXPRGRAPHNODE* node;
11826  int i;
11827 
11828  assert(nupgdconss != NULL);
11829  assert(upgdconss != NULL);
11830 
11831  *nupgdconss = 0;
11832 
11833  node = SCIPgetExprgraphNodeNonlinear(scip, cons);
11834 
11835  /* no interest in linear constraints */
11836  if( node == NULL )
11837  return SCIP_OKAY;
11838 
11839  /* if a quadratic expression has been simplified, then all children of the node should be variables */
11841  return SCIP_OKAY;
11842 
11843  switch( SCIPexprgraphGetNodeOperator(node) )
11844  {
11845  case SCIP_EXPR_VARIDX:
11846  case SCIP_EXPR_CONST:
11847  case SCIP_EXPR_PLUS:
11848  case SCIP_EXPR_MINUS:
11849  case SCIP_EXPR_SUM:
11850  case SCIP_EXPR_LINEAR:
11851  /* these should not appear as exprgraphnodes after constraint presolving */
11852  return SCIP_OKAY;
11853 
11854  case SCIP_EXPR_DIV:
11855  case SCIP_EXPR_SQRT:
11856  case SCIP_EXPR_REALPOWER:
11857  case SCIP_EXPR_INTPOWER:
11858  case SCIP_EXPR_SIGNPOWER:
11859  case SCIP_EXPR_EXP:
11860  case SCIP_EXPR_LOG:
11861  case SCIP_EXPR_SIN:
11862  case SCIP_EXPR_COS:
11863  case SCIP_EXPR_TAN:
11864  /* case SCIP_EXPR_ERF: */
11865  /* case SCIP_EXPR_ERFI: */
11866  case SCIP_EXPR_MIN:
11867  case SCIP_EXPR_MAX:
11868  case SCIP_EXPR_ABS:
11869  case SCIP_EXPR_SIGN:
11870  case SCIP_EXPR_PRODUCT:
11871  case SCIP_EXPR_POLYNOMIAL:
11872  case SCIP_EXPR_USER:
11873  /* these do not look like an quadratic expression (assuming the expression graph simplifier did run) */
11874  return SCIP_OKAY;
11875 
11876  case SCIP_EXPR_MUL:
11877  case SCIP_EXPR_SQUARE:
11878  case SCIP_EXPR_QUADRATIC:
11879  /* these mean that we have something quadratic */
11880  break;
11881 
11882  case SCIP_EXPR_PARAM:
11883  case SCIP_EXPR_LAST:
11884  default:
11885  SCIPwarningMessage(scip, "unexpected expression operator %d in nonlinear constraint <%s>\n", SCIPexprgraphGetNodeOperator(node), SCIPconsGetName(cons));
11886  return SCIP_OKAY;
11887  }
11888 
11889  /* setup a quadratic constraint */
11890 
11891  if( upgdconsssize < 1 )
11892  {
11893  /* request larger upgdconss array */
11894  *nupgdconss = -1;
11895  return SCIP_OKAY;
11896  }
11897 
11898  *nupgdconss = 1;
11899  SCIP_CALL( SCIPcreateConsQuadratic(scip, &upgdconss[0], SCIPconsGetName(cons),
11901  0, NULL, 0, NULL,
11902  SCIPgetLhsNonlinear(scip, cons), SCIPgetRhsNonlinear(scip, cons),
11906  assert(!SCIPconsIsStickingAtNode(cons));
11907 
11908  exprgraph = SCIPgetExprgraphNonlinear(scip, SCIPconsGetHdlr(cons));
11909 
11910  /* add variables from expression tree as "quadratic" variables to quadratic constraint */
11911  for( i = 0; i < SCIPexprgraphGetNodeNChildren(node); ++i )
11912  {
11913  assert(SCIPexprgraphGetNodeChildren(node)[i] != NULL);
11914  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, upgdconss[0], (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[i]), 0.0, 0.0) );
11915  }
11916 
11917  switch( SCIPexprgraphGetNodeOperator(node) )
11918  {
11919  case SCIP_EXPR_MUL:
11920  /* expression is product of two variables, so add bilinear term to constraint */
11921  assert(SCIPexprgraphGetNodeNChildren(node) == 2);
11922 
11923  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, upgdconss[0],
11926  1.0) );
11927 
11928  break;
11929 
11930  case SCIP_EXPR_SQUARE:
11931  /* expression is square of a variable, so change square coefficient of quadratic variable */
11932  assert(SCIPexprgraphGetNodeNChildren(node) == 1);
11933 
11934  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, upgdconss[0],
11936  1.0) );
11937 
11938  break;
11939 
11940  case SCIP_EXPR_QUADRATIC:
11941  {
11942  /* expression is quadratic */
11943  SCIP_QUADELEM* quadelems;
11944  int nquadelems;
11945  SCIP_Real* lincoefs;
11946 
11948  nquadelems = SCIPexprgraphGetNodeQuadraticNQuadElements(node);
11950 
11952 
11953  if( lincoefs != NULL )
11954  for( i = 0; i < SCIPexprgraphGetNodeNChildren(node); ++i )
11955  if( lincoefs[i] != 0.0 )
11956  {
11957  /* linear term */
11958  SCIP_CALL( SCIPaddQuadVarLinearCoefQuadratic(scip, upgdconss[0],
11960  lincoefs[i]) );
11961  }
11962 
11963  for( i = 0; i < nquadelems; ++i )
11964  {
11965  assert(quadelems[i].idx1 < SCIPexprgraphGetNodeNChildren(node));
11966  assert(quadelems[i].idx2 < SCIPexprgraphGetNodeNChildren(node));
11967 
11968  if( quadelems[i].idx1 == quadelems[i].idx2 )
11969  {
11970  /* square term */
11971  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, upgdconss[0],
11972  (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[quadelems[i].idx1]),
11973  quadelems[i].coef) );
11974  }
11975  else
11976  {
11977  /* bilinear term */
11978  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, upgdconss[0],
11979  (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[quadelems[i].idx1]),
11980  (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[quadelems[i].idx2]),
11981  quadelems[i].coef) );
11982  }
11983  }
11984 
11985  break;
11986  }
11987 
11988  default:
11989  SCIPerrorMessage("you should not be here\n");
11990  return SCIP_ERROR;
11991  } /*lint !e788 */
11992 
11993  return SCIP_OKAY;
11994 }
11995 
11996 /*
11997  * Callback methods of constraint handler
11998  */
11999 
12000 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
12001 static
12002 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyQuadratic)
12003 { /*lint --e{715}*/
12004  assert(scip != NULL);
12005  assert(conshdlr != NULL);
12006  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12007 
12008  /* call inclusion method of constraint handler */
12010 
12011  *valid = TRUE;
12012 
12013  return SCIP_OKAY;
12014 }
12015 
12016 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12017 static
12018 SCIP_DECL_CONSFREE(consFreeQuadratic)
12020  SCIP_CONSHDLRDATA* conshdlrdata;
12021  int i;
12022 
12023  assert(scip != NULL);
12024  assert(conshdlr != NULL);
12025 
12026  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12027  assert(conshdlrdata != NULL);
12028 
12029  for( i = 0; i < conshdlrdata->nquadconsupgrades; ++i )
12030  {
12031  assert(conshdlrdata->quadconsupgrades[i] != NULL);
12032  SCIPfreeBlockMemory(scip, &conshdlrdata->quadconsupgrades[i]); /*lint !e866*/
12033  }
12034  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->quadconsupgrades, conshdlrdata->quadconsupgradessize);
12035  SCIPfreeBlockMemory(scip, &conshdlrdata);
12036 
12037  return SCIP_OKAY;
12038 }
12039 
12040 /** initialization method of constraint handler (called after problem was transformed) */
12041 static
12042 SCIP_DECL_CONSINIT(consInitQuadratic)
12043 { /*lint --e{715} */
12044  SCIP_CONSHDLRDATA* conshdlrdata;
12045 
12046  assert(scip != NULL);
12047  assert(conshdlr != NULL);
12048 
12049  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12050  assert(conshdlrdata != NULL);
12051 
12052  conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
12053  conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
12054 
12055  return SCIP_OKAY;
12056 }
12057 
12058 
12059 /** deinitialization method of constraint handler (called before transformed problem is freed) */
12060 static
12061 SCIP_DECL_CONSEXIT(consExitQuadratic)
12062 { /*lint --e{715} */
12063  SCIP_CONSHDLRDATA* conshdlrdata;
12064 
12065  assert(scip != NULL);
12066  assert(conshdlr != NULL);
12067 
12068  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12069  assert(conshdlrdata != NULL);
12070 
12071  conshdlrdata->subnlpheur = NULL;
12072  conshdlrdata->trysolheur = NULL;
12073 
12074  return SCIP_OKAY;
12075 }
12076 
12077 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
12078 #if 0
12079 static
12080 SCIP_DECL_CONSINITPRE(consInitpreQuadratic)
12081 { /*lint --e{715}*/
12082  SCIP_CONSHDLRDATA* conshdlrdata;
12083  SCIP_CONSDATA* consdata;
12084  int c;
12085 
12086  assert(scip != NULL);
12087  assert(conshdlr != NULL);
12088  assert(conss != NULL || nconss == 0);
12089 
12090  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12091  assert(conshdlrdata != NULL);
12092 
12093  return SCIP_OKAY;
12094 }
12095 #endif
12096 
12097 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12098 static
12099 SCIP_DECL_CONSEXITPRE(consExitpreQuadratic)
12100 { /*lint --e{715}*/
12101  SCIP_CONSDATA* consdata;
12102  int c;
12103 #ifndef NDEBUG
12104  int i;
12105 #endif
12106 
12107  assert(scip != NULL);
12108  assert(conshdlr != NULL);
12109  assert(conss != NULL || nconss == 0);
12110 
12111  for( c = 0; c < nconss; ++c )
12112  {
12113  assert(conss != NULL);
12114  consdata = SCIPconsGetData(conss[c]);
12115  assert(consdata != NULL);
12116 
12117  if( !consdata->isremovedfixings )
12118  {
12119  SCIP_CALL( removeFixedVariables(scip, conss[c]) );
12120  }
12121 
12122  /* make sure we do not have duplicate bilinear terms, quad var terms, or linear vars */
12123  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
12124  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
12125  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
12126 
12127  assert(consdata->isremovedfixings);
12128  assert(consdata->linvarsmerged);
12129  assert(consdata->quadvarsmerged);
12130  assert(consdata->bilinmerged);
12131 
12132 #ifndef NDEBUG
12133  for( i = 0; i < consdata->nlinvars; ++i )
12134  assert(SCIPvarIsActive(consdata->linvars[i]));
12135 
12136  for( i = 0; i < consdata->nquadvars; ++i )
12137  assert(SCIPvarIsActive(consdata->quadvarterms[i].var));
12138 #endif
12139 
12140  /* tell SCIP that we have something nonlinear */
12141  if( SCIPconsIsAdded(conss[c]) && consdata->nquadvars > 0 )
12142  SCIPenableNLP(scip);
12143  }
12144 
12145  return SCIP_OKAY;
12146 }
12147 
12148 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin)
12149  *
12150  * @note Also called from consEnableQuadratic during solving stage.
12151  */
12152 static
12153 SCIP_DECL_CONSINITSOL(consInitsolQuadratic)
12155  SCIP_CONSHDLRDATA* conshdlrdata;
12156  SCIP_CONSDATA* consdata;
12157  int c;
12158  int i;
12159 
12160  assert(scip != NULL);
12161  assert(conshdlr != NULL);
12162  assert(conss != NULL || nconss == 0);
12163 
12164  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12165  assert(conshdlrdata != NULL);
12166 
12167  for( c = 0; c < nconss; ++c )
12168  {
12169  assert(conss != NULL);
12170  consdata = SCIPconsGetData(conss[c]);
12171  assert(consdata != NULL);
12172 
12173  /* check for a linear variable that can be increase or decreased without harming feasibility */
12174  consdataFindUnlockedLinearVar(scip, consdata);
12175 
12176  /* setup lincoefsmin, lincoefsmax */
12177  consdata->lincoefsmin = SCIPinfinity(scip);
12178  consdata->lincoefsmax = 0.0;
12179  for( i = 0; i < consdata->nlinvars; ++i )
12180  {
12181  consdata->lincoefsmin = MIN(consdata->lincoefsmin, REALABS(consdata->lincoefs[i])); /*lint !e666 */
12182  consdata->lincoefsmax = MAX(consdata->lincoefsmax, REALABS(consdata->lincoefs[i])); /*lint !e666 */
12183  }
12184 
12185  /* add nlrow representation to NLP, if NLP had been constructed */
12186  if( SCIPisNLPConstructed(scip) && SCIPconsIsEnabled(conss[c]) )
12187  {
12188  if( consdata->nlrow == NULL )
12189  {
12190  /* compute curvature for the quadratic constraint if not done yet */
12191  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) );
12192 
12193  SCIP_CALL( createNlRow(scip, conss[c]) );
12194  assert(consdata->nlrow != NULL);
12195  }
12196  SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
12197  }
12198 
12199  /* setup sepaquadvars and sepabilinvar2pos */
12200  assert(consdata->sepaquadvars == NULL);
12201  assert(consdata->sepabilinvar2pos == NULL);
12202  if( consdata->nquadvars > 0 )
12203  {
12204  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->sepaquadvars, consdata->nquadvars) );
12205  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->sepabilinvar2pos, consdata->nbilinterms) );
12206 
12207  /* make sure, quadratic variable terms are sorted */
12208  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
12209 
12210  for( i = 0; i < consdata->nquadvars; ++i )
12211  consdata->sepaquadvars[i] = consdata->quadvarterms[i].var;
12212 
12213  for( i = 0; i < consdata->nbilinterms; ++i )
12214  {
12215  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->bilinterms[i].var2, &consdata->sepabilinvar2pos[i]) );
12216  }
12217  }
12218 
12219  if( conshdlrdata->checkfactorable )
12220  {
12221  /* check if constraint function is factorable, i.e., can be written as product of two linear functions */
12222  SCIP_CALL( checkFactorable(scip, conss[c]) );
12223  }
12224 
12225  /* compute gauge function using interior points per constraint, only when there are quadratic variables */
12226  if( conshdlrdata->gaugecuts && SCIPgetSubscipDepth(scip) == 0 && consdata->nquadvars > 0 )
12227  {
12228  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
12229  if( (consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
12230  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)) )
12231  {
12232  SCIP_CALL( computeGauge(scip, conshdlr, conss[c]) );
12233  }
12234  }
12235 
12236  /* compute eigendecomposition for convex quadratics */
12237  if( conshdlrdata->projectedcuts && SCIPgetSubscipDepth(scip) == 0 && consdata->nquadvars > 0 )
12238  {
12239  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
12240  if( (consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
12241  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)) )
12242  {
12243  SCIP_CALL( computeED(scip, conshdlr, conss[c]) );
12244  }
12245  }
12246 
12247  /* mark constraint for propagation */
12248  SCIP_CALL( SCIPmarkConsPropagate(scip, conss[c]) );
12249  consdata->ispropagated = FALSE;
12250  }
12251 
12252  if( SCIPgetStage(scip) != SCIP_STAGE_INITSOLVE )
12253  {
12254  /* if called from consEnableQuadratic, then don't do below */
12255  return SCIP_OKAY;
12256  }
12257 
12258  conshdlrdata->newsoleventfilterpos = -1;
12259  if( nconss != 0 && conshdlrdata->linearizeheursol )
12260  {
12261  SCIP_EVENTHDLR* eventhdlr;
12262 
12263  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
12264  assert(eventhdlr != NULL);
12265 
12266  /* @todo Should we catch every new solution or only new *best* solutions */
12267  SCIP_CALL( SCIPcatchEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
12268  }
12269 
12270  if( nconss != 0 && !SCIPisIpoptAvailableIpopt() && !SCIPisInRestart(scip) )
12271  {
12272  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");
12273  }
12274 
12275  /* reset flags and counters */
12276  conshdlrdata->sepanlp = FALSE;
12277  conshdlrdata->lastenfonode = NULL;
12278  conshdlrdata->nenforounds = 0;
12279 
12280  return SCIP_OKAY;
12281 }
12282 
12283 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed)
12284  *
12285  * @note Also called from consDisableQuadratic during solving stage.
12286  */
12287 static
12288 SCIP_DECL_CONSEXITSOL(consExitsolQuadratic)
12289 { /*lint --e{715}*/
12290  SCIP_CONSHDLRDATA* conshdlrdata;
12291  SCIP_CONSDATA* consdata;
12292  int c;
12293 
12294  assert(scip != NULL);
12295  assert(conshdlr != NULL);
12296  assert(conss != NULL || nconss == 0);
12297 
12298  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12299  assert(conshdlrdata != NULL);
12300 
12301  for( c = 0; c < nconss; ++c )
12302  {
12303  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
12304  assert(consdata != NULL);
12305 
12306  /* free nonlinear row representation */
12307  if( consdata->nlrow != NULL )
12308  {
12309  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
12310  }
12311 
12312  assert(!SCIPconsIsEnabled(conss[c]) || consdata->sepaquadvars != NULL || consdata->nquadvars == 0); /*lint !e613 */
12313  assert(!SCIPconsIsEnabled(conss[c]) || consdata->sepabilinvar2pos != NULL || consdata->nquadvars == 0); /*lint !e613 */
12314  SCIPfreeBlockMemoryArrayNull(scip, &consdata->sepaquadvars, consdata->nquadvars);
12315  SCIPfreeBlockMemoryArrayNull(scip, &consdata->sepabilinvar2pos, consdata->nbilinterms);
12316 
12317  SCIPfreeBlockMemoryArrayNull(scip, &consdata->factorleft, consdata->nquadvars + 1);
12318  SCIPfreeBlockMemoryArrayNull(scip, &consdata->factorright, consdata->nquadvars + 1);
12319 
12320  SCIPfreeBlockMemoryArrayNull(scip, &consdata->interiorpoint, consdata->nquadvars);
12321  SCIPfreeBlockMemoryArrayNull(scip, &consdata->gaugecoefs, consdata->nquadvars);
12322  SCIPfreeBlockMemoryArrayNull(scip, &consdata->eigenvalues, consdata->nquadvars);
12323  SCIPfreeBlockMemoryArrayNull(scip, &consdata->eigenvectors, (int)(consdata->nquadvars*consdata->nquadvars));
12324  SCIPfreeBlockMemoryArrayNull(scip, &consdata->bp, consdata->nquadvars);
12325  }
12326 
12327  if( SCIPgetStage(scip) != SCIP_STAGE_EXITSOLVE )
12328  {
12329  /* if called from consDisableQuadratic, then don't do below */
12330  return SCIP_OKAY;
12331  }
12332 
12333  if( conshdlrdata->newsoleventfilterpos >= 0 )
12334  {
12335  SCIP_EVENTHDLR* eventhdlr;
12336 
12337  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
12338  assert(eventhdlr != NULL);
12339 
12340  SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
12341  conshdlrdata->newsoleventfilterpos = -1;
12342  }
12343 
12344  /* free all stored bilinear terms in the constraint handler and constraint data; note that we might not want to
12345  * recollect all bilinear terms and therefore keep them even if consDisableQuadratic is called
12346  */
12347  SCIP_CALL( freeAllBilinearTerms(scip, conshdlrdata, conss, nconss) );
12348 
12349  return SCIP_OKAY;
12350 }
12351 
12352 /** frees specific constraint data */
12353 static
12354 SCIP_DECL_CONSDELETE(consDeleteQuadratic)
12356  assert(scip != NULL);
12357  assert(conshdlr != NULL);
12358  assert(cons != NULL);
12359  assert(consdata != NULL);
12360  assert(SCIPconsGetData(cons) == *consdata);
12361 
12362  SCIP_CALL( consdataFree(scip, consdata) );
12363 
12364  assert(*consdata == NULL);
12365 
12366  return SCIP_OKAY;
12367 }
12368 
12369 /** transforms constraint data into data belonging to the transformed problem */
12370 static
12371 SCIP_DECL_CONSTRANS(consTransQuadratic)
12372 {
12373  SCIP_CONSDATA* sourcedata;
12374  SCIP_CONSDATA* targetdata;
12375  int i;
12376 
12377  sourcedata = SCIPconsGetData(sourcecons);
12378  assert(sourcedata != NULL);
12379 
12380  SCIP_CALL( consdataCreate(scip, &targetdata,
12381  sourcedata->lhs, sourcedata->rhs,
12382  sourcedata->nlinvars, sourcedata->linvars, sourcedata->lincoefs,
12383  sourcedata->nquadvars, sourcedata->quadvarterms,
12384  sourcedata->nbilinterms, sourcedata->bilinterms,
12385  FALSE) );
12386 
12387  for( i = 0; i < targetdata->nlinvars; ++i )
12388  {
12389  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->linvars[i], &targetdata->linvars[i]) );
12390  SCIP_CALL( SCIPcaptureVar(scip, targetdata->linvars[i]) );
12391  }
12392 
12393  for( i = 0; i < targetdata->nquadvars; ++i )
12394  {
12395  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->quadvarterms[i].var, &targetdata->quadvarterms[i].var) );
12396  SCIP_CALL( SCIPcaptureVar(scip, targetdata->quadvarterms[i].var) );
12397  }
12398 
12399  for( i = 0; i < targetdata->nbilinterms; ++i )
12400  {
12401  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->bilinterms[i].var1, &targetdata->bilinterms[i].var1) );
12402  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->bilinterms[i].var2, &targetdata->bilinterms[i].var2) );
12403 
12404  if( SCIPvarCompare(targetdata->bilinterms[i].var1, targetdata->bilinterms[i].var2) > 0 )
12405  {
12406  SCIP_VAR* tmp;
12407  tmp = targetdata->bilinterms[i].var2;
12408  targetdata->bilinterms[i].var2 = targetdata->bilinterms[i].var1;
12409  targetdata->bilinterms[i].var1 = tmp;
12410  }
12411  }
12412 
12413  /* create target constraint */
12414  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12415  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12416  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
12417  SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons),
12418  SCIPconsIsStickingAtNode(sourcecons)) );
12419 
12420  SCIPdebugMsg(scip, "created transformed quadratic constraint ");
12421  SCIPdebugPrintCons(scip, *targetcons, NULL);
12422 
12423  return SCIP_OKAY;
12424 }
12425 
12426 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
12427 static
12428 SCIP_DECL_CONSINITLP(consInitlpQuadratic)
12430  SCIP_CONSHDLRDATA* conshdlrdata;
12431  SCIP_CONSDATA* consdata;
12432  SCIP_VAR* var;
12433  SCIP_ROW* row;
12434  SCIP_Real* x;
12435  int c;
12436  int i;
12437 
12438  assert(scip != NULL);
12439  assert(conshdlr != NULL);
12440  assert(conss != NULL || nconss == 0);
12441 
12442  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12443  assert(conshdlrdata != NULL);
12444 
12445  *infeasible = FALSE;
12446 
12447  for( c = 0; c < nconss && !(*infeasible); ++c )
12448  {
12449  assert(conss[c] != NULL); /*lint !e613 */
12450 
12451  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
12452 
12453  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
12454  assert(consdata != NULL);
12455 
12456  row = NULL;
12457 
12458  if( consdata->nquadvars == 0 )
12459  {
12460  /* if we are actually linear, add the constraint as row to the LP */
12461  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(conss[c]), SCIPconsGetName(conss[c]), consdata->lhs, consdata->rhs,
12462  SCIPconsIsLocal(conss[c]), FALSE , TRUE) ); /*lint !e613 */
12463  SCIP_CALL( SCIPaddVarsToRow(scip, row, consdata->nlinvars, consdata->linvars, consdata->lincoefs) );
12464  SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
12465  SCIP_CALL( SCIPreleaseRow (scip, &row) );
12466  continue;
12467  }
12468 
12469  /* alloc memory for reference point */
12470  SCIP_CALL( SCIPallocBufferArray(scip, &x, consdata->nquadvars) );
12471 
12472  /* for convex parts, add linearizations in 5 points */
12473  if( (consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
12474  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)) )
12475  {
12476  SCIP_Real lb;
12477  SCIP_Real ub;
12478  SCIP_Real lambda;
12479  int k;
12480 
12481  for( k = 0; k < 5; ++k )
12482  {
12483  lambda = 0.1 * (k+1); /* lambda = 0.1, 0.2, 0.3, 0.4, 0.5 */
12484  for( i = 0; i < consdata->nquadvars; ++i )
12485  {
12486  var = consdata->quadvarterms[i].var;
12487  lb = SCIPvarGetLbGlobal(var);
12488  ub = SCIPvarGetUbGlobal(var);
12489 
12490  if( ub > -INITLPMAXVARVAL )
12491  lb = MAX(lb, -INITLPMAXVARVAL);
12492  if( lb < INITLPMAXVARVAL )
12493  ub = MIN(ub, INITLPMAXVARVAL);
12494 
12495  /* make bounds finite */
12496  if( SCIPisInfinity(scip, -lb) )
12497  lb = MIN(-10.0, ub - 0.1*REALABS(ub)); /*lint !e666 */
12498  if( SCIPisInfinity(scip, ub) )
12499  ub = MAX( 10.0, lb + 0.1*REALABS(lb)); /*lint !e666 */
12500 
12502  x[i] = lambda * ub + (1.0 - lambda) * lb;
12503  else
12504  x[i] = lambda * lb + (1.0 - lambda) * ub;
12505  }
12506 
12507  SCIP_CALL( generateCut(scip, conshdlr, conss[c], x, NULL, consdata->isconvex ? SCIP_SIDETYPE_RIGHT : SCIP_SIDETYPE_LEFT, &row, NULL,
12508  FALSE, -SCIPinfinity(scip)) ); /*lint !e613 */
12509  if( row != NULL )
12510  {
12511  SCIPdebugMsg(scip, "initlp adds row <%s> for lambda = %g of conss <%s>\n", SCIProwGetName(row), lambda, SCIPconsGetName(conss[c])); /*lint !e613 */
12512  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
12513 
12514  SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
12515  SCIP_CALL( SCIPreleaseRow (scip, &row) );
12516  }
12517  }
12518  }
12519 
12520  /* for concave parts, add underestimator w.r.t. at most 2 reference points */
12521  if( !(*infeasible) && ((! consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs))
12522  || (! consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs))) )
12523  {
12524  SCIP_Bool unbounded;
12525  SCIP_Bool possquare;
12526  SCIP_Bool negsquare;
12527  SCIP_Real lb;
12528  SCIP_Real ub;
12529  SCIP_Real lambda;
12530  int k;
12531 
12532  unbounded = FALSE; /* whether there are unbounded variables */
12533  possquare = FALSE; /* whether there is a positive square term */
12534  negsquare = FALSE; /* whether there is a negative square term */
12535  for( k = 0; k < 2; ++k )
12536  {
12537  /* Set reference point to 0 projected on bounds for unbounded variables or in between lower and upper bound
12538  * for bounded variables in the first round, we set it closer to the best bound for one part of the
12539  * variables, in the second closer to the best bound for the other part of the variables.
12540  * Additionally, we use slightly different weights for each variable.
12541  * The reason for the latter is, that for a bilinear term with bounded variables, there are always two linear underestimators
12542  * if the same weight is used for both variables of a product, then rounding and luck decides which underestimator is chosen
12543  * of course, the possible number of cuts is something in the order of 2^nquadvars, and we choose two of them here.
12544  */
12545  for( i = 0; i < consdata->nquadvars; ++i )
12546  {
12547  var = consdata->quadvarterms[i].var;
12548  lb = SCIPvarGetLbGlobal(var);
12549  ub = SCIPvarGetUbGlobal(var);
12550 
12551  if( SCIPisInfinity(scip, -lb) )
12552  {
12553  if( SCIPisInfinity(scip, ub) )
12554  x[i] = 0.0;
12555  else
12556  x[i] = MIN(0.0, ub);
12557  unbounded = TRUE;
12558  }
12559  else
12560  {
12561  if( SCIPisInfinity(scip, ub) )
12562  {
12563  x[i] = MAX(0.0, lb);
12564  unbounded = TRUE;
12565  }
12566  else
12567  {
12568  lambda = 0.4 + 0.2 * ((i+k)%2) + 0.01 * i / (double)consdata->nquadvars;
12569  x[i] = lambda * SCIPvarGetBestBoundLocal(var) + (1.0-lambda) * SCIPvarGetWorstBoundLocal(var);
12570  }
12571  }
12572 
12573  possquare |= consdata->quadvarterms[i].sqrcoef > 0.0; /*lint !e514 */
12574  negsquare |= consdata->quadvarterms[i].sqrcoef < 0.0; /*lint !e514 */
12575  }
12576 
12577  if( !consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs) )
12578  {
12579  SCIP_CALL( generateCut(scip, conshdlr, conss[c], x, NULL, SCIP_SIDETYPE_RIGHT, &row, NULL,
12580  conshdlrdata->checkcurvature, -SCIPinfinity(scip)) ); /*lint !e613 */
12581  if( row != NULL )
12582  {
12583  SCIPdebugMsg(scip, "initlp adds row <%s> for rhs of conss <%s>, round %d\n", SCIProwGetName(row), SCIPconsGetName(conss[c]), k); /*lint !e613 */
12584  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
12585 
12586  SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
12587  SCIP_CALL( SCIPreleaseRow (scip, &row) );
12588  }
12589  }
12590  if( !(*infeasible) && !consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs) )
12591  {
12592  SCIP_CALL( generateCut(scip, conshdlr, conss[c], x, NULL, SCIP_SIDETYPE_LEFT, &row, NULL,
12593  conshdlrdata->checkcurvature, -SCIPinfinity(scip)) ); /*lint !e613 */
12594  if( row != NULL )
12595  {
12596  SCIPdebugMsg(scip, "initlp adds row <%s> for lhs of conss <%s>, round %d\n", SCIProwGetName(row), SCIPconsGetName(conss[c]), k); /*lint !e613 */
12597  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
12598 
12599  SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
12600  SCIP_CALL( SCIPreleaseRow (scip, &row) );
12601  }
12602  }
12603 
12604  /* if there are unbounded variables, then there is typically only at most one possible underestimator, so don't try another round
12605  * 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 */
12606  if( unbounded ||
12607  (consdata->nbilinterms == 0 && (!possquare || SCIPisInfinity(scip, consdata->rhs))) ||
12608  (consdata->nbilinterms == 0 && (!negsquare || SCIPisInfinity(scip, -consdata->lhs))) )
12609  break;
12610  }
12611  }
12612 
12613  SCIPfreeBufferArray(scip, &x);
12614  }
12615 
12616  /* store all bilinear terms into constraint handler data; this code is not in initsolve because the sub-NLP
12617  * heuristic triggers this callback and should not collect all bilinear terms
12618  */
12619  SCIP_CALL( storeAllBilinearTerms(scip, conshdlrdata, conss, nconss) );
12620 
12621  return SCIP_OKAY;
12622 }
12623 
12624 /** separation method of constraint handler for LP solutions */
12625 static
12626 SCIP_DECL_CONSSEPALP(consSepalpQuadratic)
12627 {
12628  SCIP_CONSHDLRDATA* conshdlrdata;
12629  SCIP_Bool solviolbounds;
12630  SCIP_CONS* maxviolcon;
12631 
12632  assert(scip != NULL);
12633  assert(conshdlr != NULL);
12634  assert(conss != NULL || nconss == 0);
12635  assert(result != NULL);
12636 
12637  *result = SCIP_DIDNOTFIND;
12638 
12639  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12640  assert(conshdlrdata != NULL);
12641 
12642  SCIP_CALL( computeViolations(scip, conss, nconss, NULL, &solviolbounds, &maxviolcon) );
12643 
12644  /* don't try to separate solutions that violate variable bounds */
12645  if( solviolbounds )
12646  return SCIP_OKAY;
12647 
12648  /* if nothing violated, then nothing to separate */
12649  if( maxviolcon == NULL )
12650  return SCIP_OKAY;
12651 
12652  /* at root, check if we want to solve the NLP relaxation and use its solutions as reference point
12653  * if there is something convex, then linearizing in the solution of the NLP relaxation can be very useful
12654  */
12655  if( SCIPgetDepth(scip) == 0 && !conshdlrdata->sepanlp &&
12656  (SCIPgetNContVars(scip) >= conshdlrdata->sepanlpmincont * SCIPgetNVars(scip) ||
12657  (SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY && conshdlrdata->sepanlpmincont <= 1.0)) &&
12658  SCIPisNLPConstructed(scip) && SCIPgetNNlpis(scip) > 0 )
12659  {
12660  SCIP_CONSDATA* consdata;
12661  SCIP_NLPSOLSTAT solstat;
12662  SCIP_Bool solvednlp;
12663  int c;
12664 
12665  solstat = SCIPgetNLPSolstat(scip);
12666  solvednlp = FALSE;
12667  if( solstat == SCIP_NLPSOLSTAT_UNKNOWN )
12668  {
12669  /* NLP is not solved yet, so we might want to do this
12670  * but first check whether there is a violated constraint side which corresponds to a convex function
12671  */
12672  for( c = 0; c < nconss; ++c )
12673  {
12674  assert(conss[c] != NULL); /*lint !e613 */
12675 
12676  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
12677  assert(consdata != NULL);
12678 
12679  /* skip feasible constraints */
12680  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
12681  continue;
12682 
12683  /* make sure curvature has been checked */
12684  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
12685 
12686  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && consdata->isconvex) ||
12687  ( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && consdata->isconcave) )
12688  break;
12689  }
12690 
12691  if( c < nconss )
12692  {
12693  /* try to solve NLP and update solstat */
12694 
12695  /* ensure linear conss are in NLP */
12696  if( conshdlrdata->subnlpheur != NULL )
12697  {
12698  SCIP_CALL( SCIPaddLinearConsToNlpHeurSubNlp(scip, conshdlrdata->subnlpheur, TRUE, TRUE) );
12699  }
12700 
12701  /* set LP solution as starting values, if available */
12703  {
12705  }
12706 
12707  /* SCIP_CALL( SCIPsetNLPIntPar(scip, SCIP_NLPPAR_VERBLEVEL, 1) ); */
12708  SCIP_CALL( SCIPsolveNLP(scip) );
12709 
12710  solstat = SCIPgetNLPSolstat(scip);
12711  SCIPdebugMsg(scip, "solved NLP relax, solution status: %d\n", solstat);
12712 
12713  solvednlp = TRUE;
12714  }
12715  }
12716 
12717  conshdlrdata->sepanlp = TRUE;
12718 
12719  if( solstat == SCIP_NLPSOLSTAT_GLOBINFEASIBLE )
12720  {
12721  SCIPdebugMsg(scip, "NLP relaxation is globally infeasible, thus can cutoff node\n");
12722  *result = SCIP_CUTOFF;
12723  return SCIP_OKAY;
12724  }
12725 
12726  if( solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
12727  {
12728  /* if we have feasible NLP solution, generate linearization cuts there */
12729  SCIP_Bool lpsolseparated;
12730  SCIP_SOL* nlpsol;
12731 
12732  SCIP_CALL( SCIPcreateNLPSol(scip, &nlpsol, NULL) );
12733  assert(nlpsol != NULL);
12734 
12735  /* if we solved the NLP and solution is integral, then pass it to trysol heuristic */
12736  if( solvednlp && conshdlrdata->trysolheur != NULL )
12737  {
12738  int nfracvars;
12739 
12740  nfracvars = 0;
12741  if( SCIPgetNBinVars(scip) > 0 || SCIPgetNIntVars(scip) > 0 )
12742  {
12743  SCIP_CALL( SCIPgetNLPFracVars(scip, NULL, NULL, NULL, &nfracvars, NULL) );
12744  }
12745 
12746  if( nfracvars == 0 )
12747  {
12748  SCIPdebugMsg(scip, "pass solution with obj. value %g to trysol\n", SCIPgetSolOrigObj(scip, nlpsol));
12749  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, nlpsol) );
12750  }
12751  }
12752 
12753  SCIP_CALL( addLinearizationCuts(scip, conshdlr, conss, nconss, nlpsol, &lpsolseparated, SCIPgetSepaMinEfficacy(scip)) );
12754 
12755  SCIP_CALL( SCIPfreeSol(scip, &nlpsol) );
12756 
12757  /* if a cut that separated the LP solution was added, then return, otherwise continue with usual separation in LP solution */
12758  if( lpsolseparated )
12759  {
12760  SCIPdebugMsg(scip, "linearization cuts separate LP solution\n");
12761  *result = SCIP_SEPARATED;
12762 
12763  return SCIP_OKAY;
12764  }
12765  }
12766  }
12767  /* if we do not want to try solving the NLP, or have no NLP, or have no NLP solver, or solving the NLP failed,
12768  * or separating with NLP solution as reference point failed, then try (again) with LP solution as reference point
12769  */
12770 
12771  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, NULL, SCIPgetSepaMinEfficacy(scip), FALSE, result, NULL) );
12772 
12773  return SCIP_OKAY;
12774 }
12775 
12776 /** separation method of constraint handler for arbitrary primal solutions */
12777 static
12778 SCIP_DECL_CONSSEPASOL(consSepasolQuadratic)
12780  SCIP_Bool solviolbounds;
12781  SCIP_CONS* maxviolcon;
12782 
12783  assert(scip != NULL);
12784  assert(conshdlr != NULL);
12785  assert(conss != NULL || nconss == 0);
12786  assert(sol != NULL);
12787  assert(result != NULL);
12788 
12789  *result = SCIP_DIDNOTFIND;
12790 
12791  SCIP_CALL( computeViolations(scip, conss, nconss, sol, &solviolbounds, &maxviolcon) );
12792 
12793  /* don't separate solution that are outside variable bounds */
12794  if( solviolbounds )
12795  return SCIP_OKAY;
12796 
12797  /* if nothing violated, then nothing to separate */
12798  if( maxviolcon == NULL )
12799  return SCIP_OKAY;
12800 
12801  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, SCIPgetSepaMinEfficacy(scip), FALSE, result, NULL) );
12802 
12803  return SCIP_OKAY;
12804 }
12805 
12806 /** constraint enforcing method of constraint handler for LP solutions */
12807 static
12808 SCIP_DECL_CONSENFOLP(consEnfolpQuadratic)
12809 { /*lint --e{715}*/
12810  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, solinfeasible, result) );
12811 
12812  return SCIP_OKAY;
12813 }
12814 
12815 /** constraint enforcing method of constraint handler for relaxation solutions */
12816 static
12817 SCIP_DECL_CONSENFORELAX(consEnforelaxQuadratic)
12818 { /*lint --e{715}*/
12819  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, solinfeasible, result) );
12820 
12821  return SCIP_OKAY;
12822 }
12823 
12824 /** constraint enforcing method of constraint handler for pseudo solutions */
12825 static
12826 SCIP_DECL_CONSENFOPS(consEnfopsQuadratic)
12827 { /*lint --e{715}*/
12828  SCIP_Bool solviolbounds;
12829  SCIP_CONS* maxviolcon;
12830  SCIP_CONSDATA* consdata;
12831  SCIP_RESULT propresult;
12832  SCIP_VAR* var;
12833  int c;
12834  int i;
12835  int nchgbds;
12836  int nnotify;
12837 
12838  assert(scip != NULL);
12839  assert(conss != NULL || nconss == 0);
12840 
12841  SCIP_CALL( computeViolations(scip, conss, nconss, NULL, &solviolbounds, &maxviolcon) );
12842 
12843  /* pseudo solutions should be within bounds by definition */
12844  assert(!solviolbounds);
12845 
12846  if( maxviolcon == NULL )
12847  {
12848  *result = SCIP_FEASIBLE;
12849  return SCIP_OKAY;
12850  }
12851 
12852  *result = SCIP_INFEASIBLE;
12853 
12854  SCIPdebugMsg(scip, "enfops with max violation in cons <%s>\n", SCIPconsGetName(maxviolcon));
12855 
12856  /* run domain propagation */
12857  nchgbds = 0;
12858  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, &propresult, &nchgbds) );
12859  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
12860  {
12861  *result = propresult;
12862  return SCIP_OKAY;
12863  }
12864 
12865  /* we are not feasible and we cannot proof that the whole node is infeasible
12866  * -> collect all variables in violated constraints for branching
12867  */
12868  nnotify = 0;
12869  for( c = 0; c < nconss; ++c )
12870  {
12871  assert(conss != NULL);
12872  consdata = SCIPconsGetData(conss[c]);
12873  assert(consdata != NULL);
12874 
12875  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
12876  continue;
12877 
12878  for( i = 0; i < consdata->nlinvars; ++i )
12879  {
12880  var = consdata->linvars[i];
12881  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
12882  {
12883  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
12884  ++nnotify;
12885  }
12886  }
12887 
12888  for( i = 0; i < consdata->nquadvars; ++i )
12889  {
12890  var = consdata->quadvarterms[i].var;
12891  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
12892  {
12893  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
12894  ++nnotify;
12895  }
12896  }
12897  }
12898 
12899  if( nnotify == 0 )
12900  {
12901  SCIP_Bool addedcons;
12902  SCIP_Bool reduceddom;
12903  SCIP_Bool infeasible;
12904 
12905  /* if no branching candidate found, then all variables are almost fixed
12906  * calling replaceByLinearConstraints() should lead to fix all almost-fixed quadratic variables, and possibly replace some quad. conss by linear ones
12907  */
12908  SCIP_CALL( replaceByLinearConstraints(scip, conss, nconss, &addedcons, &reduceddom, &infeasible) );
12909  if( addedcons )
12910  {
12911  *result = SCIP_CONSADDED;
12912  return SCIP_OKAY;
12913  }
12914  if( reduceddom )
12915  {
12916  *result = SCIP_REDUCEDDOM;
12917  return SCIP_OKAY;
12918  }
12919  if( infeasible )
12920  {
12921  *result = SCIP_CUTOFF;
12922  return SCIP_OKAY;
12923  }
12924 
12925  SCIPdebugMsg(scip, "All variables in violated constraints fixed (up to epsilon). Cannot find branching candidate. Forcing solution of LP.\n");
12926  *result = SCIP_SOLVELP;
12927  }
12928 
12929  assert(*result == SCIP_SOLVELP || (*result == SCIP_INFEASIBLE && nnotify > 0));
12930  return SCIP_OKAY;
12931 }
12932 
12933 /** domain propagation method of constraint handler */
12934 static
12935 SCIP_DECL_CONSPROP(consPropQuadratic)
12937  int nchgbds;
12938 
12939  assert(scip != NULL);
12940  assert(conshdlr != NULL);
12941  assert(conss != NULL || nconss == 0);
12942  assert(result != NULL);
12943 
12944  nchgbds = 0;
12945  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nmarkedconss, result, &nchgbds) );
12946 
12947  return SCIP_OKAY;
12948 } /*lint !e715 */
12949 
12950 /** presolving method of constraint handler */
12951 static
12952 SCIP_DECL_CONSPRESOL(consPresolQuadratic)
12953 { /*lint --e{715,788}*/
12954  SCIP_CONSHDLRDATA* conshdlrdata;
12955  SCIP_CONSDATA* consdata;
12956  SCIP_RESULT solveresult;
12957  SCIP_Bool redundant;
12958  SCIP_Bool havechange;
12959  SCIP_Bool doreformulations;
12960  int c;
12961  int i;
12962 
12963  assert(scip != NULL);
12964  assert(conshdlr != NULL);
12965  assert(conss != NULL || nconss == 0);
12966  assert(result != NULL);
12967 
12968  *result = SCIP_DIDNOTFIND;
12969 
12970  /* if other presolvers did not find enough changes for another presolving round and we are in exhaustive presolving,
12971  * then try the reformulations (replacing products with binaries, disaggregation, setting default variable bounds)
12972  * otherwise, we wait with these
12973  */
12974  doreformulations = ((presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0) && SCIPisPresolveFinished(scip);
12975  SCIPdebugMsg(scip, "presolving will %swait with reformulation\n", doreformulations ? "not " : "");
12976 
12977  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12978  assert(conshdlrdata != NULL);
12979 
12980  for( c = 0; c < nconss; ++c )
12981  {
12982  assert(conss != NULL);
12983  consdata = SCIPconsGetData(conss[c]);
12984  assert(consdata != NULL);
12985 
12986  SCIPdebugMsg(scip, "process constraint <%s>\n", SCIPconsGetName(conss[c]));
12987  SCIPdebugPrintCons(scip, conss[c], NULL);
12988 
12989  if( !consdata->initialmerge )
12990  {
12991  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
12992  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
12993  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
12994  consdata->initialmerge = TRUE;
12995  }
12996 
12997  havechange = FALSE;
12998 #ifdef CHECKIMPLINBILINEAR
12999  if( consdata->isimpladded && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
13000  {
13001  int nbilinremoved;
13002  SCIP_CALL( presolveApplyImplications(scip, conss[c], &nbilinremoved) );
13003  if( nbilinremoved > 0 )
13004  {
13005  *nchgcoefs += nbilinremoved;
13006  havechange = TRUE;
13007  *result = SCIP_SUCCESS;
13008  }
13009  assert(!consdata->isimpladded);
13010  }
13011 #endif
13012  /* 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
13013  * we want to do this before (multi)aggregated variables are replaced, since that may change structure, e.g., introduce bilinear terms
13014  */
13015  if( !consdata->ispresolved || !consdata->ispropagated || nnewchgvartypes > 0 )
13016  {
13017  SCIP_Bool upgraded;
13018 
13019  SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss, presoltiming) );
13020  if( upgraded )
13021  {
13022  *result = SCIP_SUCCESS;
13023  continue;
13024  }
13025  }
13026 
13027  if( !consdata->isremovedfixings )
13028  {
13029  SCIP_CALL( removeFixedVariables(scip, conss[c]) );
13030  assert(consdata->isremovedfixings);
13031  havechange = TRUE;
13032  }
13033 
13034  /* try to "solve" the constraint, e.g., reduce to a variable aggregation */
13035  SCIP_CALL( presolveSolve(scip, conss[c], &solveresult, &redundant, naggrvars) );
13036  if( solveresult == SCIP_CUTOFF )
13037  {
13038  SCIPdebugMsg(scip, "solving constraint <%s> says problem is infeasible in presolve\n", SCIPconsGetName(conss[c]));
13039  *result = SCIP_CUTOFF;
13040  return SCIP_OKAY;
13041  }
13042  if( redundant )
13043  {
13044  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
13045  ++*ndelconss;
13046  *result = SCIP_SUCCESS;
13047  break;
13048  }
13049  if( solveresult == SCIP_SUCCESS )
13050  {
13051  *result = SCIP_SUCCESS;
13052  havechange = TRUE;
13053  }
13054 
13055  /* @todo divide constraint by gcd of coefficients if all are integral */
13056 
13057  if( doreformulations )
13058  {
13059  int naddconss_old;
13060 
13061  naddconss_old = *naddconss;
13062 
13063  SCIP_CALL( presolveTryAddAND(scip, conshdlr, conss[c], naddconss) );
13064  assert(*naddconss >= naddconss_old);
13065 
13066  if( *naddconss == naddconss_old )
13067  {
13068  /* user not so empathic about AND, or we don't have products of two binaries, so try this more general reformulation */
13069  SCIP_CALL( presolveTryAddLinearReform(scip, conshdlr, conss[c], naddconss) );
13070  assert(*naddconss >= naddconss_old);
13071  }
13072 
13073  if( conshdlrdata->maxdisaggrsize > 1 )
13074  {
13075  /* try disaggregation, if enabled */
13076  SCIP_CALL( presolveDisaggregate(scip, conshdlr, conss[c], naddconss) );
13077  }
13078 
13079  if( *naddconss > naddconss_old )
13080  {
13081  /* if something happened, report success and cleanup constraint */
13082  *result = SCIP_SUCCESS;
13083  havechange = TRUE;
13084  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
13085  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
13086  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
13087  }
13088  }
13089 
13090  if( consdata->nlinvars == 0 && consdata->nquadvars == 0 )
13091  {
13092  /* all variables fixed or removed, constraint function is 0.0 now */
13093  if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasPositive(scip, consdata->lhs)) ||
13094  ( !SCIPisInfinity(scip, consdata->rhs) && SCIPisFeasNegative(scip, consdata->rhs)) )
13095  { /* left hand side positive or right hand side negative */
13096  SCIPdebugMsg(scip, "constraint <%s> is constant and infeasible\n", SCIPconsGetName(conss[c]));
13097  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
13098  ++*ndelconss;
13099  *result = SCIP_CUTOFF;
13100  return SCIP_OKAY;
13101  }
13102 
13103  /* left and right hand side are consistent */
13104  SCIPdebugMsg(scip, "constraint <%s> is constant and feasible, deleting\n", SCIPconsGetName(conss[c]));
13105  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
13106  ++*ndelconss;
13107  *result = SCIP_SUCCESS;
13108  continue;
13109  }
13110 
13111  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 && !consdata->ispropagated )
13112  {
13113  /* try domain propagation if there were bound changes or constraint has changed (in which case, processVarEvents may have set ispropagated to false) */
13114  SCIP_RESULT propresult;
13115  int roundnr;
13116 
13117  roundnr = 0;
13118  do
13119  {
13120  ++roundnr;
13121 
13122  SCIPdebugMsg(scip, "starting domain propagation round %d of %d\n", roundnr, conshdlrdata->maxproproundspresolve);
13123 
13124  if( !consdata->ispropagated )
13125  {
13126  consdata->ispropagated = TRUE;
13127 
13128  SCIP_CALL( propagateBoundsCons(scip, conshdlr, conss[c], &propresult, nchgbds, &redundant) );
13129 
13130  if( propresult == SCIP_CUTOFF )
13131  {
13132  SCIPdebugMsg(scip, "propagation on constraint <%s> says problem is infeasible in presolve\n",
13133  SCIPconsGetName(conss[c]));
13134  *result = SCIP_CUTOFF;
13135  return SCIP_OKAY;
13136  }
13137 
13138  /* delete constraint if found redundant by bound tightening */
13139  if( redundant )
13140  {
13141  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
13142  ++*ndelconss;
13143  *result = SCIP_SUCCESS;
13144  break;
13145  }
13146 
13147  if( propresult == SCIP_REDUCEDDOM )
13148  {
13149  *result = SCIP_SUCCESS;
13150  havechange = TRUE;
13151  }
13152  }
13153  }
13154  while( !consdata->ispropagated && roundnr < conshdlrdata->maxproproundspresolve );
13155 
13156  if( redundant )
13157  continue;
13158  }
13159 
13160  /* check if we have a single linear continuous variable that we can make implicit integer */
13161  if( (nnewchgvartypes != 0 || havechange || !consdata->ispresolved)
13162  && (SCIPisEQ(scip, consdata->lhs, consdata->rhs) && SCIPisIntegral(scip, consdata->lhs)) )
13163  {
13164  int ncontvar;
13165  SCIP_VAR* candidate;
13166  SCIP_Bool fail;
13167 
13168  fail = FALSE;
13169  candidate = NULL;
13170  ncontvar = 0;
13171 
13172  for( i = 0; !fail && i < consdata->nlinvars; ++i )
13173  {
13174  if( !SCIPisIntegral(scip, consdata->lincoefs[i]) )
13175  {
13176  fail = TRUE;
13177  }
13178  else if( SCIPvarGetType(consdata->linvars[i]) == SCIP_VARTYPE_CONTINUOUS )
13179  {
13180  if( ncontvar > 0 ) /* now at 2nd continuous variable */
13181  fail = TRUE;
13182  else if( SCIPisEQ(scip, ABS(consdata->lincoefs[i]), 1.0) )
13183  candidate = consdata->linvars[i];
13184  ++ncontvar;
13185  }
13186  }
13187  for( i = 0; !fail && i < consdata->nquadvars; ++i )
13188  fail = SCIPvarGetType(consdata->quadvarterms[i].var) == SCIP_VARTYPE_CONTINUOUS ||
13189  !SCIPisIntegral(scip, consdata->quadvarterms[i].lincoef) ||
13190  !SCIPisIntegral(scip, consdata->quadvarterms[i].sqrcoef);
13191  for( i = 0; !fail && i < consdata->nbilinterms; ++i )
13192  fail = !SCIPisIntegral(scip, consdata->bilinterms[i].coef);
13193 
13194  if( !fail && candidate != NULL )
13195  {
13196  SCIP_Bool infeasible;
13197 
13198  SCIPdebugMsg(scip, "make variable <%s> implicit integer due to constraint <%s>\n", SCIPvarGetName(candidate), SCIPconsGetName(conss[c]));
13199 
13200  SCIP_CALL( SCIPchgVarType(scip, candidate, SCIP_VARTYPE_IMPLINT, &infeasible) );
13201  if( infeasible )
13202  {
13203  SCIPdebugMsg(scip, "infeasible upgrade of variable <%s> to integral type, domain is empty\n", SCIPvarGetName(candidate));
13204  *result = SCIP_CUTOFF;
13205 
13206  return SCIP_OKAY;
13207  }
13208 
13209  ++(*nchgvartypes);
13210  *result = SCIP_SUCCESS;
13211  havechange = TRUE;
13212  }
13213  }
13214 
13215  /* call upgrade methods again if constraint has been changed */
13216  if( havechange )
13217  {
13218  SCIP_Bool upgraded;
13219 
13220  SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss, presoltiming) );
13221  if( upgraded )
13222  {
13223  *result = SCIP_SUCCESS;
13224  continue;
13225  }
13226  }
13227 
13228  /* fix quadratic variables with proper square coefficients contained in a single quadratic constraint to their
13229  * upper or lower bounds
13230  */
13231  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 && conshdlrdata->checkquadvarlocks != 'd'
13232  && SCIPisPresolveFinished(scip) )
13233  {
13234  SCIP_CONS* cons;
13235  SCIP_VAR* vars[2];
13236  SCIP_BOUNDTYPE boundtypes[2];
13237  SCIP_Real bounds[2];
13238  char name[SCIP_MAXSTRLEN];
13239 
13240  /* merge variables in order to get correct locks for quadratic variables */
13241  if( !consdata->initialmerge )
13242  {
13243  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
13244  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
13245  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
13246  consdata->initialmerge = TRUE;
13247  }
13248 
13249  for( i = 0; i < consdata->nquadvars; ++i )
13250  {
13251  if( hasQuadvarHpProperty(scip, consdata, i) )
13252  {
13253  SCIP_VAR* var;
13254 
13255  var = consdata->quadvarterms[i].var;
13256  assert(var != NULL);
13257 
13258  /* try to change the variable type to binary */
13259  if( conshdlrdata->checkquadvarlocks == 't' && SCIPisEQ(scip, SCIPvarGetLbGlobal(var), 0.0) && SCIPisEQ(scip, SCIPvarGetUbGlobal(var), 1.0) )
13260  {
13261  SCIP_Bool infeasible;
13262 
13263  assert(SCIPvarGetType(var) != SCIP_VARTYPE_BINARY);
13264  SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, &infeasible) );
13265 
13266  if( infeasible )
13267  {
13268  SCIPdebugMsg(scip, "detect infeasibility after changing variable <%s> to binary type\n", SCIPvarGetName(var));
13269  *result = SCIP_CUTOFF;
13270  return SCIP_OKAY;
13271  }
13272  }
13273  /* add bound disjunction constraint if bounds of variable are finite */
13274  else if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
13275  {
13276  vars[0] = var;
13277  vars[1] = var;
13278  boundtypes[0] = SCIP_BOUNDTYPE_LOWER;
13279  boundtypes[1] = SCIP_BOUNDTYPE_UPPER;
13280  bounds[0] = SCIPvarGetUbGlobal(var);
13281  bounds[1] = SCIPvarGetLbGlobal(var);
13282 
13283  SCIPdebugMsg(scip, "add bound disjunction constraint for %s\n", SCIPvarGetName(var));
13284 
13285  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "quadvarbnddisj_%s", SCIPvarGetName(var));
13286  SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &cons, name, 2, vars, boundtypes, bounds, TRUE, TRUE,
13287  TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
13288 
13289  SCIP_CALL( SCIPaddCons(scip, cons) );
13290  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
13291  }
13292 
13293  *result = SCIP_SUCCESS;
13294  }
13295  }
13296  }
13297 
13298  consdata->ispresolved = TRUE;
13299  }
13300 
13301  return SCIP_OKAY;
13302 }
13303 
13304 /** variable rounding lock method of constraint handler */
13305 static
13306 SCIP_DECL_CONSLOCK(consLockQuadratic)
13307 { /*lint --e{715}*/
13308  SCIP_CONSDATA* consdata;
13309  SCIP_Bool haslb;
13310  SCIP_Bool hasub;
13311  int i;
13312 
13313  assert(scip != NULL);
13314  assert(cons != NULL);
13315  assert(locktype == SCIP_LOCKTYPE_MODEL);
13316 
13317  consdata = SCIPconsGetData(cons);
13318  assert(consdata != NULL);
13319 
13320  haslb = !SCIPisInfinity(scip, -consdata->lhs);
13321  hasub = !SCIPisInfinity(scip, consdata->rhs);
13322 
13323  for( i = 0; i < consdata->nlinvars; ++i )
13324  {
13325  if( consdata->lincoefs[i] > 0 )
13326  {
13327  if( haslb )
13328  {
13329  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->linvars[i], locktype, nlockspos, nlocksneg) );
13330  }
13331  if( hasub )
13332  {
13333  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->linvars[i], locktype, nlocksneg, nlockspos) );
13334  }
13335  }
13336  else
13337  {
13338  if( haslb )
13339  {
13340  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->linvars[i], locktype, nlocksneg, nlockspos) );
13341  }
13342  if( hasub )
13343  {
13344  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->linvars[i], locktype, nlockspos, nlocksneg) );
13345  }
13346  }
13347  }
13348 
13349  for( i = 0; i < consdata->nquadvars; ++i )
13350  {
13351  /* @todo try to be more clever, but variable locks that depend on the bounds of other variables are not trival to maintain */
13352  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->quadvarterms[i].var, SCIP_LOCKTYPE_MODEL, nlockspos+nlocksneg,
13353  nlockspos+nlocksneg) );
13354  }
13355 
13356  return SCIP_OKAY;
13357 }
13358 
13359 /** constraint enabling notification method of constraint handler */
13360 static
13361 SCIP_DECL_CONSENABLE(consEnableQuadratic)
13363  SCIP_CONSHDLRDATA* conshdlrdata;
13364 
13365  assert(scip != NULL);
13366  assert(conshdlr != NULL);
13367  assert(cons != NULL);
13368  assert(SCIPconsIsTransformed(cons));
13369  assert(SCIPconsIsActive(cons));
13370 
13371  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13372  assert(conshdlrdata != NULL);
13373 
13374  SCIPdebugMsg(scip, "enable cons <%s>\n", SCIPconsGetName(cons));
13375 
13376  if( SCIPgetStage(scip) >= SCIP_STAGE_EXITPRESOLVE )
13377  {
13378  /* merge duplicate bilinear terms, move quad terms that are linear to linear vars */
13379  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
13380  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, cons) );
13381  SCIP_CALL( mergeAndCleanLinearVars(scip, cons) );
13382  }
13383 
13384  /* catch variable events */
13385  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
13386 
13387  /* initialize solving data */
13388  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
13389  {
13390  SCIP_CALL( consInitsolQuadratic(scip, conshdlr, &cons, 1) );
13391  }
13392 
13393  return SCIP_OKAY;
13394 }
13395 
13396 /** constraint disabling notification method of constraint handler */
13397 static
13398 SCIP_DECL_CONSDISABLE(consDisableQuadratic)
13399 { /*lint --e{715}*/
13400  SCIP_CONSHDLRDATA* conshdlrdata;
13401 
13402  assert(scip != NULL);
13403  assert(conshdlr != NULL);
13404  assert(cons != NULL);
13405  assert(SCIPconsIsTransformed(cons));
13406 
13407  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13408  assert(conshdlrdata != NULL);
13409 
13410  SCIPdebugMsg(scip, "disable cons <%s>\n", SCIPconsGetName(cons));
13411 
13412  /* free solving data */
13413  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
13414  {
13415  SCIP_CALL( consExitsolQuadratic(scip, conshdlr, &cons, 1, FALSE) );
13416  }
13417 
13418  /* drop variable events */
13419  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
13420 
13421  return SCIP_OKAY;
13422 }
13423 
13424 /** constraint display method of constraint handler */
13425 static
13426 SCIP_DECL_CONSPRINT(consPrintQuadratic)
13427 { /*lint --e{715}*/
13428  SCIP_CONSDATA* consdata;
13429 
13430  assert(scip != NULL);
13431  assert(cons != NULL);
13432 
13433  consdata = SCIPconsGetData(cons);
13434  assert(consdata != NULL);
13435 
13436  /* print left hand side for ranged rows */
13437  if( !SCIPisInfinity(scip, -consdata->lhs)
13438  && !SCIPisInfinity(scip, consdata->rhs)
13439  && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
13440  SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
13441 
13442  /* print coefficients and variables */
13443  if( consdata->nlinvars == 0 && consdata->nquadvars == 0 )
13444  {
13445  SCIPinfoMessage(scip, file, "0 ");
13446  }
13447  else
13448  {
13449  SCIP_VAR*** monomialvars;
13450  SCIP_Real** monomialexps;
13451  SCIP_Real* monomialcoefs;
13452  int* monomialnvars;
13453  int nmonomials;
13454  int monomialssize;
13455  int j;
13456 
13457  monomialssize = consdata->nlinvars + 2 * consdata->nquadvars + consdata->nbilinterms;
13458  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars, monomialssize) );
13459  SCIP_CALL( SCIPallocBufferArray(scip, &monomialexps, monomialssize) );
13460  SCIP_CALL( SCIPallocBufferArray(scip, &monomialcoefs, monomialssize) );
13461  SCIP_CALL( SCIPallocBufferArray(scip, &monomialnvars, monomialssize) );
13462 
13463  nmonomials = 0;
13464  for( j = 0; j < consdata->nlinvars; ++j )
13465  {
13466  assert(nmonomials < monomialssize);
13467 
13468  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 1) ); /*lint !e866 */
13469 
13470  monomialvars[nmonomials][0] = consdata->linvars[j];
13471  monomialexps[nmonomials] = NULL;
13472  monomialcoefs[nmonomials] = consdata->lincoefs[j];
13473  monomialnvars[nmonomials] = 1;
13474  ++nmonomials;
13475  }
13476 
13477  for( j = 0; j < consdata->nquadvars; ++j )
13478  {
13479  if( consdata->quadvarterms[j].lincoef != 0.0 )
13480  {
13481  assert(nmonomials < monomialssize);
13482 
13483  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 1) ); /*lint !e866 */
13484 
13485  monomialvars[nmonomials][0] = consdata->quadvarterms[j].var;
13486  monomialexps[nmonomials] = NULL;
13487  monomialcoefs[nmonomials] = consdata->quadvarterms[j].lincoef;
13488  monomialnvars[nmonomials] = 1;
13489  ++nmonomials;
13490  }
13491 
13492  if( consdata->quadvarterms[j].sqrcoef != 0.0 )
13493  {
13494  assert(nmonomials < monomialssize);
13495 
13496  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 1) ); /*lint !e866 */
13497  SCIP_CALL( SCIPallocBufferArray(scip, &monomialexps[nmonomials], 1) ); /*lint !e866 */
13498 
13499  monomialvars[nmonomials][0] = consdata->quadvarterms[j].var;
13500  monomialexps[nmonomials][0] = 2.0;
13501  monomialcoefs[nmonomials] = consdata->quadvarterms[j].sqrcoef;
13502  monomialnvars[nmonomials] = 1;
13503  ++nmonomials;
13504  }
13505  }
13506 
13507  for( j = 0; j < consdata->nbilinterms; ++j )
13508  {
13509  assert(nmonomials < monomialssize);
13510 
13511  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 2) ); /*lint !e866 */
13512 
13513  monomialvars[nmonomials][0] = consdata->bilinterms[j].var1;
13514  monomialvars[nmonomials][1] = consdata->bilinterms[j].var2;
13515  monomialexps[nmonomials] = NULL;
13516  monomialcoefs[nmonomials] = consdata->bilinterms[j].coef;
13517  monomialnvars[nmonomials] = 2;
13518  ++nmonomials;
13519  }
13520 
13521  SCIP_CALL( SCIPwriteVarsPolynomial(scip, file, monomialvars, monomialexps, monomialcoefs, monomialnvars, nmonomials, TRUE) );
13522 
13523  for( j = 0; j < nmonomials; ++j )
13524  {
13525  SCIPfreeBufferArray(scip, &monomialvars[j]);
13526  SCIPfreeBufferArrayNull(scip, &monomialexps[j]);
13527  }
13528 
13529  SCIPfreeBufferArray(scip, &monomialvars);
13530  SCIPfreeBufferArray(scip, &monomialexps);
13531  SCIPfreeBufferArray(scip, &monomialcoefs);
13532  SCIPfreeBufferArray(scip, &monomialnvars);
13533  }
13534 
13535  /* print right hand side */
13536  if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
13537  {
13538  SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
13539  }
13540  else if( !SCIPisInfinity(scip, consdata->rhs) )
13541  {
13542  SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
13543  }
13544  else if( !SCIPisInfinity(scip, -consdata->lhs) )
13545  {
13546  SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
13547  }
13548  else
13549  {
13550  /* should be ignored by parser */
13551  SCIPinfoMessage(scip, file, " [free]");
13552  }
13553 
13554  return SCIP_OKAY;
13555 }
13556 
13557 /** feasibility check method of constraint handler for integral solutions */
13558 static
13559 SCIP_DECL_CONSCHECK(consCheckQuadratic)
13560 { /*lint --e{715}*/
13561  SCIP_CONSHDLRDATA* conshdlrdata;
13562  SCIP_CONSDATA* consdata;
13563  SCIP_Real maxviol;
13564  int c;
13565  SCIP_Bool maypropfeasible; /* whether we may be able to propose a feasible solution */
13566  SCIP_Bool solviolbounds;
13567 
13568  assert(scip != NULL);
13569  assert(conss != NULL || nconss == 0);
13570  assert(result != NULL);
13571 
13572  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13573  assert(conshdlrdata != NULL);
13574 
13575  *result = SCIP_FEASIBLE;
13576 
13577  maxviol = 0.0;
13578  maypropfeasible = conshdlrdata->linfeasshift && (conshdlrdata->trysolheur != NULL) &&
13580  for( c = 0; c < nconss; ++c )
13581  {
13582  assert(conss != NULL);
13583  SCIP_CALL( computeViolation(scip, conss[c], sol, &solviolbounds) );
13584  assert(!solviolbounds); /* see also issue #627 */
13585 
13586  consdata = SCIPconsGetData(conss[c]);
13587  assert(consdata != NULL);
13588 
13589  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
13590  {
13591  *result = SCIP_INFEASIBLE;
13592  if( printreason )
13593  {
13594  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
13595  SCIPinfoMessage(scip, NULL, ";\n");
13596  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
13597  {
13598  SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g\n", consdata->lhsviol);
13599  }
13600  if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
13601  {
13602  SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g\n", consdata->rhsviol);
13603  }
13604  }
13605  if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible && !completely )
13606  return SCIP_OKAY;
13607  if( consdata->lhsviol > maxviol || consdata->rhsviol > maxviol )
13608  maxviol = consdata->lhsviol + consdata->rhsviol;
13609 
13610  /* do not try to shift linear variables if activity is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
13611  if( maypropfeasible && SCIPisInfinity(scip, REALABS(consdata->activity)) )
13612  maypropfeasible = FALSE;
13613 
13614  if( maypropfeasible )
13615  {
13616  /* update information on linear variables that may be in- or decreased, if initsolve has not done so yet */
13618  consdataFindUnlockedLinearVar(scip, consdata);
13619 
13620  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
13621  {
13622  /* check if there is a variable which may help to get the left hand side satisfied
13623  * if there is no such var, then we cannot get feasible */
13624  if( !(consdata->linvar_mayincrease >= 0 && consdata->lincoefs[consdata->linvar_mayincrease] > 0.0) &&
13625  ! (consdata->linvar_maydecrease >= 0 && consdata->lincoefs[consdata->linvar_maydecrease] < 0.0) )
13626  maypropfeasible = FALSE;
13627  }
13628  else
13629  {
13630  assert(SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)));
13631  /* check if there is a variable which may help to get the right hand side satisfied
13632  * if there is no such var, then we cannot get feasible */
13633  if( !(consdata->linvar_mayincrease >= 0 && consdata->lincoefs[consdata->linvar_mayincrease] < 0.0) &&
13634  ! (consdata->linvar_maydecrease >= 0 && consdata->lincoefs[consdata->linvar_maydecrease] > 0.0) )
13635  maypropfeasible = FALSE;
13636  }
13637  }
13638  }
13639  }
13640 
13641  if( *result == SCIP_INFEASIBLE && maypropfeasible )
13642  {
13643  SCIP_Bool success;
13644 
13645  SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
13646 
13647  /* do not pass solution to NLP heuristic if we made it feasible this way */
13648  if( success )
13649  return SCIP_OKAY;
13650  }
13651 
13652  if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL && !SCIPisInfinity(scip, maxviol) )
13653  {
13654  SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
13655  }
13656 
13657  return SCIP_OKAY;
13658 }
13659 
13660 /** constraint copying method of constraint handler */
13661 static
13662 SCIP_DECL_CONSCOPY(consCopyQuadratic)
13664  SCIP_CONSDATA* consdata;
13665  SCIP_CONSDATA* targetconsdata;
13666  SCIP_VAR** linvars;
13667  SCIP_QUADVARTERM* quadvarterms;
13668  SCIP_BILINTERM* bilinterms;
13669  int i;
13670  int j;
13671  int k;
13672 
13673  assert(scip != NULL);
13674  assert(cons != NULL);
13675  assert(sourcescip != NULL);
13676  assert(sourceconshdlr != NULL);
13677  assert(sourcecons != NULL);
13678  assert(varmap != NULL);
13679  assert(valid != NULL);
13680 
13681  consdata = SCIPconsGetData(sourcecons);
13682  assert(consdata != NULL);
13683 
13684  linvars = NULL;
13685  quadvarterms = NULL;
13686  bilinterms = NULL;
13687 
13688  *valid = TRUE;
13689 
13690  if( consdata->nlinvars != 0 )
13691  {
13692  SCIP_CALL( SCIPallocBufferArray(sourcescip, &linvars, consdata->nlinvars) );
13693  for( i = 0; i < consdata->nlinvars; ++i )
13694  {
13695  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, consdata->linvars[i], &linvars[i], varmap, consmap, global, valid) );
13696  assert(!(*valid) || linvars[i] != NULL);
13697 
13698  /* we do not copy, if a variable is missing */
13699  if( !(*valid) )
13700  goto TERMINATE;
13701  }
13702  }
13703 
13704  if( consdata->nbilinterms != 0 )
13705  {
13706  SCIP_CALL( SCIPallocBufferArray(sourcescip, &bilinterms, consdata->nbilinterms) );
13707  }
13708 
13709  if( consdata->nquadvars != 0 )
13710  {
13711  SCIP_CALL( SCIPallocBufferArray(sourcescip, &quadvarterms, consdata->nquadvars) );
13712  for( i = 0; i < consdata->nquadvars; ++i )
13713  {
13714  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, consdata->quadvarterms[i].var, &quadvarterms[i].var, varmap, consmap, global, valid) );
13715  assert(!(*valid) || quadvarterms[i].var != NULL);
13716 
13717  /* we do not copy, if a variable is missing */
13718  if( !(*valid) )
13719  goto TERMINATE;
13720 
13721  quadvarterms[i].lincoef = consdata->quadvarterms[i].lincoef;
13722  quadvarterms[i].sqrcoef = consdata->quadvarterms[i].sqrcoef;
13723  quadvarterms[i].eventdata = NULL;
13724  quadvarterms[i].nadjbilin = consdata->quadvarterms[i].nadjbilin;
13725  quadvarterms[i].adjbilin = consdata->quadvarterms[i].adjbilin;
13726 
13727  assert(consdata->nbilinterms != 0 || consdata->quadvarterms[i].nadjbilin == 0);
13728 
13729  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
13730  {
13731  assert(bilinterms != NULL);
13732 
13733  k = consdata->quadvarterms[i].adjbilin[j];
13734  assert(consdata->bilinterms[k].var1 != NULL);
13735  assert(consdata->bilinterms[k].var2 != NULL);
13736  if( consdata->bilinterms[k].var1 == consdata->quadvarterms[i].var )
13737  {
13738  assert(consdata->bilinterms[k].var2 != consdata->quadvarterms[i].var);
13739  bilinterms[k].var1 = quadvarterms[i].var;
13740  }
13741  else
13742  {
13743  assert(consdata->bilinterms[k].var2 == consdata->quadvarterms[i].var);
13744  bilinterms[k].var2 = quadvarterms[i].var;
13745  }
13746  bilinterms[k].coef = consdata->bilinterms[k].coef;
13747  }
13748  }
13749  }
13750 
13751  assert(stickingatnode == FALSE);
13752  SCIP_CALL( SCIPcreateConsQuadratic2(scip, cons, name ? name : SCIPconsGetName(sourcecons),
13753  consdata->nlinvars, linvars, consdata->lincoefs,
13754  consdata->nquadvars, quadvarterms,
13755  consdata->nbilinterms, bilinterms,
13756  consdata->lhs, consdata->rhs,
13757  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
13758 
13759  /* copy information on curvature */
13760  targetconsdata = SCIPconsGetData(*cons);
13761  targetconsdata->isconvex = consdata->isconvex;
13762  targetconsdata->isconcave = consdata->isconcave;
13763  targetconsdata->iscurvchecked = consdata->iscurvchecked;
13764 
13765  TERMINATE:
13766  SCIPfreeBufferArrayNull(sourcescip, &quadvarterms);
13767  SCIPfreeBufferArrayNull(sourcescip, &bilinterms);
13768  SCIPfreeBufferArrayNull(sourcescip, &linvars);
13769 
13770  return SCIP_OKAY;
13771 }
13772 
13773 /** constraint parsing method of constraint handler */
13774 static
13775 SCIP_DECL_CONSPARSE(consParseQuadratic)
13776 { /*lint --e{715}*/
13777  SCIP_VAR*** monomialvars;
13778  SCIP_Real** monomialexps;
13779  SCIP_Real* monomialcoefs;
13780  char* endptr;
13781  int* monomialnvars;
13782  int nmonomials;
13783 
13784  SCIP_Real lhs;
13785  SCIP_Real rhs;
13786 
13787  assert(scip != NULL);
13788  assert(success != NULL);
13789  assert(str != NULL);
13790  assert(name != NULL);
13791  assert(cons != NULL);
13792 
13793  /* set left and right hand side to their default values */
13794  lhs = -SCIPinfinity(scip);
13795  rhs = SCIPinfinity(scip);
13796 
13797  (*success) = FALSE;
13798 
13799  /* return of string empty */
13800  if( !*str )
13801  return SCIP_OKAY;
13802 
13803  /* ignore whitespace */
13804  while( isspace((unsigned char)*str) )
13805  ++str;
13806 
13807  /* check for left hand side */
13808  if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
13809  {
13810  /* there is a number coming, maybe it is a left-hand-side */
13811  if( !SCIPstrToRealValue(str, &lhs, &endptr) )
13812  {
13813  SCIPerrorMessage("error parsing number from <%s>\n", str);
13814  return SCIP_OKAY;
13815  }
13816 
13817  /* ignore whitespace */
13818  while( isspace((unsigned char)*endptr) )
13819  ++endptr;
13820 
13821  if( endptr[0] != '<' || endptr[1] != '=' )
13822  {
13823  /* no '<=' coming, so it was the first coefficient, but not a left-hand-side */
13824  lhs = -SCIPinfinity(scip);
13825  }
13826  else
13827  {
13828  /* it was indeed a left-hand-side, so continue parsing after it */
13829  str = endptr + 2;
13830 
13831  /* ignore whitespace */
13832  while( isspace((unsigned char)*str) )
13833  ++str;
13834  }
13835  }
13836 
13837  SCIP_CALL( SCIPparseVarsPolynomial(scip, str, &monomialvars, &monomialexps, &monomialcoefs, &monomialnvars, &nmonomials, &endptr, success) );
13838 
13839  if( *success )
13840  {
13841  /* check for right hand side */
13842  str = endptr;
13843 
13844  /* ignore whitespace */
13845  while( isspace((unsigned char)*str) )
13846  ++str;
13847 
13848  if( *str && str[0] == '<' && str[1] == '=' )
13849  {
13850  /* we seem to get a right-hand-side */
13851  str += 2;
13852 
13853  if( !SCIPstrToRealValue(str, &rhs, &endptr) )
13854  {
13855  SCIPerrorMessage("error parsing right-hand-side from %s\n", str);
13856  *success = FALSE;
13857  }
13858  }
13859  else if( *str && str[0] == '>' && str[1] == '=' )
13860  {
13861  /* we seem to get a left-hand-side */
13862  str += 2;
13863 
13864  /* we should not have a left-hand-side already */
13865  assert(SCIPisInfinity(scip, -lhs));
13866 
13867  if( !SCIPstrToRealValue(str, &lhs, &endptr) )
13868  {
13869  SCIPerrorMessage("error parsing left-hand-side from %s\n", str);
13870  *success = FALSE;
13871  }
13872  }
13873  else if( *str && str[0] == '=' && str[1] == '=' )
13874  {
13875  /* we seem to get a left- and right-hand-side */
13876  str += 2;
13877 
13878  /* we should not have a left-hand-side already */
13879  assert(SCIPisInfinity(scip, -lhs));
13880 
13881  if( !SCIPstrToRealValue(str, &lhs, &endptr) )
13882  {
13883  SCIPerrorMessage("error parsing left-hand-side from %s\n", str);
13884  *success = FALSE;
13885  }
13886  else
13887  {
13888  rhs = lhs;
13889  }
13890  }
13891  }
13892 
13893  if( *success )
13894  {
13895  int i;
13896 
13897  /* setup constraint */
13898  assert(stickingatnode == FALSE);
13899  SCIP_CALL( SCIPcreateConsQuadratic(scip, cons, name, 0, NULL, NULL,
13900  0, NULL, NULL, NULL, lhs, rhs,
13901  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
13902 
13903  for( i = 0; i < nmonomials; ++i )
13904  {
13905  if( monomialnvars[i] == 0 )
13906  {
13907  /* constant monomial */
13908  SCIPaddConstantQuadratic(scip, *cons, monomialcoefs[i]);
13909  }
13910  else if( monomialnvars[i] == 1 && monomialexps[i][0] == 1.0 )
13911  {
13912  /* linear monomial */
13913  SCIP_CALL( SCIPaddLinearVarQuadratic(scip, *cons, monomialvars[i][0], monomialcoefs[i]) );
13914  }
13915  else if( monomialnvars[i] == 1 && monomialexps[i][0] == 2.0 )
13916  {
13917  /* square monomial */
13918  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, monomialvars[i][0], 0.0, monomialcoefs[i]) );
13919  }
13920  else if( monomialnvars[i] == 2 && monomialexps[i][0] == 1.0 && monomialexps[i][1] == 1.0 )
13921  {
13922  /* bilinear term */
13923  SCIP_VAR* var1;
13924  SCIP_VAR* var2;
13925  int pos;
13926 
13927  var1 = monomialvars[i][0];
13928  var2 = monomialvars[i][1];
13929  if( var1 == var2 )
13930  {
13931  /* actually a square term */
13932  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, var1, 0.0, monomialcoefs[i]) );
13933  }
13934  else
13935  {
13936  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, *cons, var1, &pos) );
13937  if( pos == -1 )
13938  {
13939  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, var1, 0.0, 0.0) );
13940  }
13941 
13942  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, *cons, var2, &pos) );
13943  if( pos == -1 )
13944  {
13945  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, var2, 0.0, 0.0) );
13946  }
13947  }
13948 
13949  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, *cons, var1, var2, monomialcoefs[i]) );
13950  }
13951  else
13952  {
13953  SCIPerrorMessage("polynomial in quadratic constraint does not have degree at most 2\n");
13954  *success = FALSE;
13955  SCIP_CALL( SCIPreleaseCons(scip, cons) );
13956  break;
13957  }
13958  }
13959  }
13960 
13961  SCIPfreeParseVarsPolynomialData(scip, &monomialvars, &monomialexps, &monomialcoefs, &monomialnvars, nmonomials);
13962 
13963  return SCIP_OKAY;
13964 }
13965 
13966 /** constraint method of constraint handler which returns the variables (if possible) */
13967 static
13968 SCIP_DECL_CONSGETVARS(consGetVarsQuadratic)
13969 { /*lint --e{715}*/
13970  SCIP_CONSDATA* consdata;
13971 
13972  assert(cons != NULL);
13973  assert(success != NULL);
13974 
13975  consdata = SCIPconsGetData(cons);
13976  assert(consdata != NULL);
13977 
13978  if( varssize < consdata->nlinvars + consdata->nquadvars )
13979  (*success) = FALSE;
13980  else
13981  {
13982  int i;
13983 
13984  assert(vars != NULL);
13985 
13986  BMScopyMemoryArray(vars, consdata->linvars, consdata->nlinvars);
13987 
13988  for( i = 0; i < consdata->nquadvars; ++i )
13989  vars[consdata->nlinvars+i] = consdata->quadvarterms[i].var;
13990 
13991  (*success) = TRUE;
13992  }
13993 
13994  return SCIP_OKAY;
13995 }
13996 
13997 /** constraint method of constraint handler which returns the number of variables (if possible) */
13998 static
13999 SCIP_DECL_CONSGETNVARS(consGetNVarsQuadratic)
14000 { /*lint --e{715}*/
14001  SCIP_CONSDATA* consdata;
14002 
14003  assert(cons != NULL);
14004  assert(success != NULL);
14005 
14006  consdata = SCIPconsGetData(cons);
14007  assert(consdata != NULL);
14008 
14009  (*nvars) = consdata->nlinvars + consdata->nquadvars;
14010  (*success) = TRUE;
14011 
14012  return SCIP_OKAY;
14013 }
14014 
14015 
14016 /*
14017  * constraint specific interface methods
14018  */
14019 
14020 /** creates the handler for quadratic constraints and includes it in SCIP */
14022  SCIP* scip /**< SCIP data structure */
14023  )
14024 {
14025  SCIP_CONSHDLRDATA* conshdlrdata;
14026  SCIP_CONSHDLR* conshdlr;
14027 
14028  /* create quadratic constraint handler data */
14029  SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
14030  BMSclearMemory(conshdlrdata);
14031 
14032  /* include constraint handler */
14035  consEnfolpQuadratic, consEnfopsQuadratic, consCheckQuadratic, consLockQuadratic,
14036  conshdlrdata) );
14037  assert(conshdlr != NULL);
14038 
14039  /* set non-fundamental callbacks via specific setter functions */
14040  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyQuadratic, consCopyQuadratic) );
14041  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteQuadratic) );
14042  SCIP_CALL( SCIPsetConshdlrDisable(scip, conshdlr, consDisableQuadratic) );
14043  SCIP_CALL( SCIPsetConshdlrEnable(scip, conshdlr, consEnableQuadratic) );
14044  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitQuadratic) );
14045  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreQuadratic) );
14046  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolQuadratic) );
14047  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeQuadratic) );
14048  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsQuadratic) );
14049  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsQuadratic) );
14050  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitQuadratic) );
14051  SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolQuadratic) );
14052  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpQuadratic) );
14053  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseQuadratic) );
14054  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolQuadratic, CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
14055  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintQuadratic) );
14056  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropQuadratic, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
14058  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpQuadratic, consSepasolQuadratic, CONSHDLR_SEPAFREQ,
14060  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransQuadratic) );
14061  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxQuadratic) );
14062 
14063  /* add quadratic constraint handler parameters */
14064  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/replacebinaryprod",
14065  "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)",
14066  &conshdlrdata->replacebinaryprodlength, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
14067 
14068  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/empathy4and",
14069  "empathy level for using the AND constraint handler: 0 always avoid using AND; 1 use AND sometimes; 2 use AND as often as possible",
14070  &conshdlrdata->empathy4and, FALSE, 0, 0, 2, NULL, NULL) );
14071 
14072  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/binreforminitial",
14073  "whether to make non-varbound linear constraints added due to replacing products with binary variables initial",
14074  &conshdlrdata->binreforminitial, TRUE, FALSE, NULL, NULL) );
14075 
14076  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/binreformbinaryonly",
14077  "whether to consider only binary variables when replacing products with binary variables",
14078  &conshdlrdata->binreformbinaryonly, FALSE, TRUE, NULL, NULL) );
14079 
14080  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/binreformmaxcoef",
14081  "limit (as factor on 1/feastol) on coefficients and coef. range in linear constraints created when replacing products with binary variables",
14082  &conshdlrdata->binreformmaxcoef, TRUE, 1e-4, 0.0, SCIPinfinity(scip), NULL, NULL) );
14083 
14084  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/cutmaxrange",
14085  "maximal coef range of a cut (maximal coefficient divided by minimal coefficient) in order to be added to LP relaxation",
14086  &conshdlrdata->cutmaxrange, TRUE, 1e+7, 0.0, SCIPinfinity(scip), NULL, NULL) );
14087 
14088  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/mincurvcollectbilinterms",
14089  "minimal curvature of constraints to be considered when returning bilinear terms to other plugins",
14090  &conshdlrdata->mincurvcollectbilinterms, TRUE, 0.8, -SCIPinfinity(scip), SCIPinfinity(scip), NULL, NULL) );
14091 
14092  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/linearizeheursol",
14093  "whether linearizations of convex quadratic constraints should be added to cutpool in a solution found by some heuristic",
14094  &conshdlrdata->linearizeheursol, TRUE, TRUE, NULL, NULL) );
14095 
14096  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/checkcurvature",
14097  "whether multivariate quadratic functions should be checked for convexity/concavity",
14098  &conshdlrdata->checkcurvature, FALSE, TRUE, NULL, NULL) );
14099 
14100  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/checkfactorable",
14101  "whether constraint functions should be checked to be factorable",
14102  &conshdlrdata->checkfactorable, TRUE, TRUE, NULL, NULL) );
14103 
14104  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/checkquadvarlocks",
14105  "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)",
14106  &conshdlrdata->checkquadvarlocks, TRUE, 't', "bdt", NULL, NULL) );
14107 
14108  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/linfeasshift",
14109  "whether to try to make solutions in check function feasible by shifting a linear variable (esp. useful if constraint was actually objective function)",
14110  &conshdlrdata->linfeasshift, TRUE, TRUE, NULL, NULL) );
14111 
14112  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxdisaggrsize",
14113  "maximum number of created constraints when disaggregating a quadratic constraint (<= 1: off)",
14114  &conshdlrdata->maxdisaggrsize, FALSE, 1, 1, INT_MAX, NULL, NULL) );
14115 
14116  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/disaggrmergemethod",
14117  "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)",
14118  &conshdlrdata->disaggrmergemethod, TRUE, 'm', "bms", NULL, NULL) );
14119 
14120  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
14121  "limit on number of propagation rounds for a single constraint within one round of SCIP propagation during solve",
14122  &conshdlrdata->maxproprounds, TRUE, 1, 0, INT_MAX, NULL, NULL) );
14123 
14124  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproproundspresolve",
14125  "limit on number of propagation rounds for a single constraint within one round of SCIP presolve",
14126  &conshdlrdata->maxproproundspresolve, TRUE, 10, 0, INT_MAX, NULL, NULL) );
14127 
14128  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/enfolplimit",
14129  "maximum number of enforcement rounds before declaring the LP relaxation infeasible (-1: no limit); WARNING: changing this parameter might lead to incorrect results!",
14130  &conshdlrdata->enfolplimit, TRUE, -1, -1, INT_MAX, NULL, NULL) );
14131 
14132  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/sepanlpmincont",
14133  "minimal required fraction of continuous variables in problem to use solution of NLP relaxation in root for separation",
14134  &conshdlrdata->sepanlpmincont, FALSE, 1.0, 0.0, 2.0, NULL, NULL) );
14135 
14136  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/enfocutsremovable",
14137  "are cuts added during enforcement removable from the LP in the same node?",
14138  &conshdlrdata->enfocutsremovable, TRUE, FALSE, NULL, NULL) );
14139 
14140  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/gaugecuts",
14141  "should convex quadratics generated strong cuts via gauge function?",
14142  &conshdlrdata->gaugecuts, FALSE, FALSE, NULL, NULL) );
14143 
14144  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/interiorcomputation",
14145  "how the interior point for gauge cuts should be computed: 'a'ny point per constraint, 'm'ost interior per constraint",
14146  &conshdlrdata->interiorcomputation, TRUE, 'a', "am", NULL, NULL) );
14147 
14148  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/projectedcuts",
14149  "should convex quadratics generated strong cuts via projections?",
14150  &conshdlrdata->projectedcuts, FALSE, FALSE, NULL, NULL) );
14151 
14152  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branchscoring",
14153  "which score to give branching candidates: convexification 'g'ap, constraint 'v'iolation, 'c'entrality of variable value in domain",
14154  &conshdlrdata->branchscoring, TRUE, 'g', "cgv", NULL, NULL) );
14155 
14156  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/usebilinineqbranch",
14157  "should linear inequalities be consindered when computing the branching scores for bilinear terms?",
14158  &conshdlrdata->usebilinineqbranch, FALSE, FALSE, NULL, NULL) );
14159 
14160  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/minscorebilinterms",
14161  "minimal required score in order to use linear inequalities for tighter bilinear relaxations",
14162  &conshdlrdata->minscorebilinterms, FALSE, 0.01, 0.0, 1.0, NULL, NULL) );
14163 
14164  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/bilinineqmaxseparounds",
14165  "maximum number of separation rounds to use linear inequalities for the bilinear term relaxation in a local node",
14166  &conshdlrdata->bilinineqmaxseparounds, TRUE, 3, 0, INT_MAX, NULL, NULL) );
14167 
14168  conshdlrdata->eventhdlr = NULL;
14169  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlr),CONSHDLR_NAME"_boundchange", "signals a bound change to a quadratic constraint",
14170  processVarEvent, NULL) );
14171  assert(conshdlrdata->eventhdlr != NULL);
14172 
14173  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME"_newsolution", "handles the event that a new primal solution has been found",
14174  processNewSolutionEvent, NULL) );
14175 
14176  /* include the quadratic constraint upgrade in the nonlinear constraint handler */
14178 
14179  return SCIP_OKAY;
14180 }
14181 
14182 /** includes a quadratic constraint update method into the quadratic constraint handler */
14184  SCIP* scip, /**< SCIP data structure */
14185  SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), /**< method to call for upgrading quadratic constraint */
14186  int priority, /**< priority of upgrading method */
14187  SCIP_Bool active, /**< should the upgrading method be active by default? */
14188  const char* conshdlrname /**< name of the constraint handler */
14189  )
14190 {
14191  SCIP_CONSHDLR* conshdlr;
14192  SCIP_CONSHDLRDATA* conshdlrdata;
14193  SCIP_QUADCONSUPGRADE* quadconsupgrade;
14194  char paramname[SCIP_MAXSTRLEN];
14195  char paramdesc[SCIP_MAXSTRLEN];
14196  int i;
14197 
14198  assert(quadconsupgd != NULL);
14199  assert(conshdlrname != NULL );
14200 
14201  /* find the quadratic constraint handler */
14202  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14203  if( conshdlr == NULL )
14204  {
14205  SCIPerrorMessage("quadratic constraint handler not found\n");
14206  return SCIP_PLUGINNOTFOUND;
14207  }
14208 
14209  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14210  assert(conshdlrdata != NULL);
14211 
14212  if( !conshdlrdataHasUpgrade(scip, conshdlrdata, quadconsupgd, conshdlrname) )
14213  {
14214  /* create a quadratic constraint upgrade data object */
14215  SCIP_CALL( SCIPallocBlockMemory(scip, &quadconsupgrade) );
14216  quadconsupgrade->quadconsupgd = quadconsupgd;
14217  quadconsupgrade->priority = priority;
14218  quadconsupgrade->active = active;
14219 
14220  /* insert quadratic constraint upgrade method into constraint handler data */
14221  assert(conshdlrdata->nquadconsupgrades <= conshdlrdata->quadconsupgradessize);
14222  if( conshdlrdata->nquadconsupgrades+1 > conshdlrdata->quadconsupgradessize )
14223  {
14224  int newsize;
14225 
14226  newsize = SCIPcalcMemGrowSize(scip, conshdlrdata->nquadconsupgrades+1);
14227  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->quadconsupgrades, conshdlrdata->quadconsupgradessize, newsize) );
14228  conshdlrdata->quadconsupgradessize = newsize;
14229  }
14230  assert(conshdlrdata->nquadconsupgrades+1 <= conshdlrdata->quadconsupgradessize);
14231 
14232  for( i = conshdlrdata->nquadconsupgrades; i > 0 && conshdlrdata->quadconsupgrades[i-1]->priority < quadconsupgrade->priority; --i )
14233  conshdlrdata->quadconsupgrades[i] = conshdlrdata->quadconsupgrades[i-1];
14234  assert(0 <= i && i <= conshdlrdata->nquadconsupgrades);
14235  conshdlrdata->quadconsupgrades[i] = quadconsupgrade;
14236  conshdlrdata->nquadconsupgrades++;
14237 
14238  /* adds parameter to turn on and off the upgrading step */
14239  (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
14240  (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable quadratic upgrading for constraint handler <%s>", conshdlrname);
14242  paramname, paramdesc,
14243  &quadconsupgrade->active, FALSE, active, NULL, NULL) );
14244  }
14245 
14246  return SCIP_OKAY;
14247 }
14248 
14249 /** Creates and captures a quadratic constraint.
14250  *
14251  * The constraint should be given in the form
14252  * \f[
14253  * \ell \leq \sum_{i=1}^n b_i x_i + \sum_{j=1}^m a_j y_j z_j \leq u,
14254  * \f]
14255  * where \f$x_i = y_j = z_k\f$ is possible.
14256  *
14257  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
14258  */
14260  SCIP* scip, /**< SCIP data structure */
14261  SCIP_CONS** cons, /**< pointer to hold the created constraint */
14262  const char* name, /**< name of constraint */
14263  int nlinvars, /**< number of linear terms (n) */
14264  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
14265  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
14266  int nquadterms, /**< number of quadratic terms (m) */
14267  SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms (y_j) */
14268  SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms (z_j) */
14269  SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms (a_j) */
14270  SCIP_Real lhs, /**< left hand side of quadratic equation (ell) */
14271  SCIP_Real rhs, /**< right hand side of quadratic equation (u) */
14272  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
14273  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
14274  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
14275  * Usually set to TRUE. */
14276  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
14277  * TRUE for model constraints, FALSE for additional, redundant constraints. */
14278  SCIP_Bool check, /**< should the constraint be checked for feasibility?
14279  * TRUE for model constraints, FALSE for additional, redundant constraints. */
14280  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
14281  * Usually set to TRUE. */
14282  SCIP_Bool local, /**< is constraint only valid locally?
14283  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
14284  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
14285  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
14286  * adds coefficients to this constraint. */
14287  SCIP_Bool dynamic, /**< is constraint subject to aging?
14288  * Usually set to FALSE. Set to TRUE for own cuts which
14289  * are separated as constraints. */
14290  SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
14291  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
14292  )
14293 {
14294  SCIP_CONSHDLR* conshdlr;
14295  SCIP_CONSDATA* consdata;
14296  SCIP_HASHMAP* quadvaridxs;
14297  SCIP_Real sqrcoef;
14298  int i;
14299  int var1pos;
14300  int var2pos;
14301 
14302  int nbilinterms;
14303 
14304  assert(linvars != NULL || nlinvars == 0);
14305  assert(lincoefs != NULL || nlinvars == 0);
14306  assert(quadvars1 != NULL || nquadterms == 0);
14307  assert(quadvars2 != NULL || nquadterms == 0);
14308  assert(quadcoefs != NULL || nquadterms == 0);
14309 
14310  assert(modifiable == FALSE); /* we do not support column generation */
14311 
14312  /* find the quadratic constraint handler */
14313  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14314  if( conshdlr == NULL )
14315  {
14316  SCIPerrorMessage("quadratic constraint handler not found\n");
14317  return SCIP_PLUGINNOTFOUND;
14318  }
14319 
14320  /* create constraint data and constraint */
14321  SCIP_CALL( consdataCreateEmpty(scip, &consdata) );
14322 
14323  consdata->lhs = lhs;
14324  consdata->rhs = rhs;
14325 
14326  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
14327  local, modifiable, dynamic, removable, FALSE) );
14328 
14329  /* add quadratic variables and remember their indices */
14330  SCIP_CALL( SCIPhashmapCreate(&quadvaridxs, SCIPblkmem(scip), nquadterms) );
14331  nbilinterms = 0;
14332  for( i = 0; i < nquadterms; ++i )
14333  {
14334  if( SCIPisZero(scip, quadcoefs[i]) ) /*lint !e613*/
14335  continue;
14336 
14337  /* if it is actually a square term, remember it's coefficient */
14338  /* cppcheck-suppress nullPointer */
14339  if( quadvars1[i] == quadvars2[i] ) /*lint !e613*/
14340  sqrcoef = quadcoefs[i]; /*lint !e613 */
14341  else
14342  sqrcoef = 0.0;
14343 
14344  /* add quadvars1[i], if not in there already */
14345  if( !SCIPhashmapExists(quadvaridxs, quadvars1[i]) ) /*lint !e613*/
14346  {
14347  SCIP_CALL( addQuadVarTerm(scip, *cons, quadvars1[i], 0.0, sqrcoef) ); /*lint !e613*/
14348  assert(consdata->nquadvars >= 0);
14349  assert(consdata->quadvarterms[consdata->nquadvars-1].var == quadvars1[i]); /*lint !e613*/
14350 
14351  SCIP_CALL( SCIPhashmapInsert(quadvaridxs, quadvars1[i], (void*)(size_t)(consdata->nquadvars-1)) ); /*lint !e613*/
14352  }
14353  else if( !SCIPisZero(scip, sqrcoef) )
14354  {
14355  /* if it's there already, but we got a square coefficient, add it to the previous one */
14356  var1pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, quadvars1[i]); /*lint !e613*/
14357  assert(consdata->quadvarterms[var1pos].var == quadvars1[i]); /*lint !e613*/
14358  consdata->quadvarterms[var1pos].sqrcoef += sqrcoef;
14359  }
14360 
14361  /* cppcheck-suppress nullPointer */
14362  if( quadvars1[i] == quadvars2[i] ) /*lint !e613*/
14363  continue;
14364 
14365  /* add quadvars2[i], if not in there already */
14366  if( !SCIPhashmapExists(quadvaridxs, quadvars2[i]) ) /*lint !e613*/
14367  {
14368  assert(sqrcoef == 0.0);
14369  SCIP_CALL( addQuadVarTerm(scip, *cons, quadvars2[i], 0.0, 0.0) ); /*lint !e613*/
14370  assert(consdata->nquadvars >= 0);
14371  assert(consdata->quadvarterms[consdata->nquadvars-1].var == quadvars2[i]); /*lint !e613*/
14372 
14373  SCIP_CALL( SCIPhashmapInsert(quadvaridxs, quadvars2[i], (void*)(size_t)(consdata->nquadvars-1)) ); /*lint !e613*/
14374  }
14375 
14376  ++nbilinterms;
14377  }
14378 
14379  /* add bilinear terms, if we saw any */
14380  if( nbilinterms > 0 )
14381  {
14382  SCIP_CALL( consdataEnsureBilinSize(scip, consdata, nbilinterms) );
14383  for( i = 0; i < nquadterms; ++i )
14384  {
14385  if( SCIPisZero(scip, quadcoefs[i]) ) /*lint !e613*/
14386  continue;
14387 
14388  /* square terms have been taken care of already */
14389  if( quadvars1[i] == quadvars2[i] ) /*lint !e613 */
14390  continue;
14391 
14392  assert(SCIPhashmapExists(quadvaridxs, quadvars1[i])); /*lint !e613*/
14393  assert(SCIPhashmapExists(quadvaridxs, quadvars2[i])); /*lint !e613*/
14394 
14395  var1pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, quadvars1[i]); /*lint !e613*/
14396  var2pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, quadvars2[i]); /*lint !e613*/
14397 
14398  SCIP_CALL( addBilinearTerm(scip, *cons, var1pos, var2pos, quadcoefs[i]) ); /*lint !e613*/
14399  }
14400  }
14401 
14402  /* add linear variables */
14403  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, nlinvars) );
14404  for( i = 0; i < nlinvars; ++i )
14405  {
14406  if( SCIPisZero(scip, lincoefs[i]) ) /*lint !e613*/
14407  continue;
14408 
14409  /* if it's a linear coefficient for a quadratic variable, add it there, otherwise add as linear variable */
14410  if( SCIPhashmapExists(quadvaridxs, linvars[i]) ) /*lint !e613*/
14411  {
14412  var1pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, linvars[i]); /*lint !e613*/
14413  assert(consdata->quadvarterms[var1pos].var == linvars[i]); /*lint !e613*/
14414  consdata->quadvarterms[var1pos].lincoef += lincoefs[i]; /*lint !e613*/
14415  }
14416  else
14417  {
14418  SCIP_CALL( addLinearCoef(scip, *cons, linvars[i], lincoefs[i]) ); /*lint !e613*/
14419  }
14420  }
14421 
14422  SCIPhashmapFree(&quadvaridxs);
14423 
14424  SCIPdebugMsg(scip, "created quadratic constraint ");
14425  SCIPdebugPrintCons(scip, *cons, NULL);
14426 
14427  return SCIP_OKAY;
14428 }
14429 
14430 /** creates and captures a quadratic constraint with all its
14431  * flags set to their default values.
14432  *
14433  * The constraint should be given in the form
14434  * \f[
14435  * \ell \leq \sum_{i=1}^n b_i x_i + \sum_{j=1}^m a_j y_j z_j \leq u,
14436  * \f]
14437  * where \f$x_i = y_j = z_k\f$ is possible.
14438  *
14439  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
14440  */
14442  SCIP* scip, /**< SCIP data structure */
14443  SCIP_CONS** cons, /**< pointer to hold the created constraint */
14444  const char* name, /**< name of constraint */
14445  int nlinvars, /**< number of linear terms (n) */
14446  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
14447  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
14448  int nquadterms, /**< number of quadratic terms (m) */
14449  SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms (y_j) */
14450  SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms (z_j) */
14451  SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms (a_j) */
14452  SCIP_Real lhs, /**< left hand side of quadratic equation (ell) */
14453  SCIP_Real rhs /**< right hand side of quadratic equation (u) */
14454  )
14455 {
14456  SCIP_CALL( SCIPcreateConsQuadratic(scip, cons, name, nlinvars, linvars, lincoefs,
14457  nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
14458  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
14459 
14460  return SCIP_OKAY;
14461 }
14462 
14463 /** Creates and captures a quadratic constraint.
14464  *
14465  * The constraint should be given in the form
14466  * \f[
14467  * \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.
14468  * \f]
14469  *
14470  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
14471  */
14473  SCIP* scip, /**< SCIP data structure */
14474  SCIP_CONS** cons, /**< pointer to hold the created constraint */
14475  const char* name, /**< name of constraint */
14476  int nlinvars, /**< number of linear terms (n) */
14477  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
14478  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
14479  int nquadvarterms, /**< number of quadratic terms (m) */
14480  SCIP_QUADVARTERM* quadvarterms, /**< quadratic variable terms */
14481  int nbilinterms, /**< number of bilinear terms (p) */
14482  SCIP_BILINTERM* bilinterms, /**< bilinear terms */
14483  SCIP_Real lhs, /**< constraint left hand side (ell) */
14484  SCIP_Real rhs, /**< constraint right hand side (u) */
14485  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? */
14486  SCIP_Bool separate, /**< should the constraint be separated during LP processing? */
14487  SCIP_Bool enforce, /**< should the constraint be enforced during node processing? */
14488  SCIP_Bool check, /**< should the constraint be checked for feasibility? */
14489  SCIP_Bool propagate, /**< should the constraint be propagated during node processing? */
14490  SCIP_Bool local, /**< is constraint only valid locally? */
14491  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)? */
14492  SCIP_Bool dynamic, /**< is constraint dynamic? */
14493  SCIP_Bool removable /**< should the constraint be removed from the LP due to aging or cleanup? */
14494  )
14495 {
14496  SCIP_CONSHDLR* conshdlr;
14497  SCIP_CONSDATA* consdata;
14498 
14499  assert(modifiable == FALSE); /* we do not support column generation */
14500  assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
14501  assert(nquadvarterms == 0 || quadvarterms != NULL);
14502  assert(nbilinterms == 0 || bilinterms != NULL);
14503 
14504  /* find the quadratic constraint handler */
14505  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14506  if( conshdlr == NULL )
14507  {
14508  SCIPerrorMessage("quadratic constraint handler not found\n");
14509  return SCIP_PLUGINNOTFOUND;
14510  }
14511 
14512  /* create constraint data */
14513  SCIP_CALL( consdataCreate(scip, &consdata, lhs, rhs,
14514  nlinvars, linvars, lincoefs, nquadvarterms, quadvarterms, nbilinterms, bilinterms,
14515  TRUE) );
14516 
14517  /* create constraint */
14518  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
14519  local, modifiable, dynamic, removable, FALSE) );
14520 
14521  return SCIP_OKAY;
14522 }
14523 
14524 /** creates and captures a quadratic constraint in its most basic version, i.e.,
14525  * all constraint flags are set to their default values.
14526  *
14527  * The constraint should be given in the form
14528  * \f[
14529  * \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.
14530  * \f]
14531  *
14532  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
14533  */
14535  SCIP* scip, /**< SCIP data structure */
14536  SCIP_CONS** cons, /**< pointer to hold the created constraint */
14537  const char* name, /**< name of constraint */
14538  int nlinvars, /**< number of linear terms (n) */
14539  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
14540  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
14541  int nquadvarterms, /**< number of quadratic terms (m) */
14542  SCIP_QUADVARTERM* quadvarterms, /**< quadratic variable terms */
14543  int nbilinterms, /**< number of bilinear terms (p) */
14544  SCIP_BILINTERM* bilinterms, /**< bilinear terms */
14545  SCIP_Real lhs, /**< constraint left hand side (ell) */
14546  SCIP_Real rhs /**< constraint right hand side (u) */
14547  )
14548 {
14549  SCIP_CALL( SCIPcreateConsQuadratic2(scip, cons, name, nlinvars, linvars, lincoefs,
14550  nquadvarterms, quadvarterms, nbilinterms, bilinterms, lhs, rhs,
14551  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
14552 
14553  return SCIP_OKAY;
14554 }
14555 
14556 
14557 /** Adds a constant to the constraint function, that is, subtracts a constant from both sides */
14559  SCIP* scip, /**< SCIP data structure */
14560  SCIP_CONS* cons, /**< constraint */
14561  SCIP_Real constant /**< constant to subtract from both sides */
14562  )
14563 {
14564  SCIP_CONSDATA* consdata;
14565 
14566  assert(scip != NULL);
14567  assert(cons != NULL);
14568  assert(!SCIPisInfinity(scip, REALABS(constant)));
14569 
14570  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
14571  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
14572  {
14573  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
14574  SCIPABORT();
14575  }
14576 
14577  consdata = SCIPconsGetData(cons);
14578  assert(consdata != NULL);
14579  assert(consdata->lhs <= consdata->rhs);
14580 
14581  if( !SCIPisInfinity(scip, -consdata->lhs) )
14582  consdata->lhs -= constant;
14583  if( !SCIPisInfinity(scip, consdata->rhs) )
14584  consdata->rhs -= constant;
14585 
14586  if( consdata->lhs > consdata->rhs )
14587  {
14588  assert(SCIPisEQ(scip, consdata->lhs, consdata->rhs));
14589  consdata->lhs = consdata->rhs;
14590  }
14591 }
14592 
14593 /** Adds a linear variable with coefficient to a quadratic constraint. */
14595  SCIP* scip, /**< SCIP data structure */
14596  SCIP_CONS* cons, /**< constraint */
14597  SCIP_VAR* var, /**< variable */
14598  SCIP_Real coef /**< coefficient of variable */
14599  )
14600 {
14601  assert(scip != NULL);
14602  assert(cons != NULL);
14603  assert(var != NULL);
14604  assert(!SCIPisInfinity(scip, REALABS(coef)));
14605 
14606  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
14607  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
14608  {
14609  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
14610  return SCIP_INVALIDCALL;
14611  }
14612 
14613  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
14614 
14615  return SCIP_OKAY;
14616 }
14617 
14618 /** Adds a quadratic variable with linear and square coefficient to a quadratic constraint. */
14620  SCIP* scip, /**< SCIP data structure */
14621  SCIP_CONS* cons, /**< constraint */
14622  SCIP_VAR* var, /**< variable */
14623  SCIP_Real lincoef, /**< linear coefficient of variable */
14624  SCIP_Real sqrcoef /**< square coefficient of variable */
14625  )
14626 {
14627  assert(scip != NULL);
14628  assert(cons != NULL);
14629  assert(var != NULL);
14630  assert(!SCIPisInfinity(scip, REALABS(lincoef)));
14631  assert(!SCIPisInfinity(scip, REALABS(sqrcoef)));
14632 
14633  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
14634  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
14635  {
14636  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
14637  return SCIP_INVALIDCALL;
14638  }
14639 
14640  SCIP_CALL( addQuadVarTerm(scip, cons, var, lincoef, sqrcoef) );
14641 
14642  return SCIP_OKAY;
14643 }
14644 
14645 /** Adds a linear coefficient for a quadratic variable.
14646  *
14647  * Variable will be added with square coefficient 0.0 if not existing yet.
14648  */
14650  SCIP* scip, /**< SCIP data structure */
14651  SCIP_CONS* cons, /**< constraint */
14652  SCIP_VAR* var, /**< variable */
14653  SCIP_Real coef /**< value to add to linear coefficient of variable */
14654  )
14655 {
14656  SCIP_CONSDATA* consdata;
14657  int pos;
14658 
14659  assert(scip != NULL);
14660  assert(cons != NULL);
14661  assert(var != NULL);
14662  assert(!SCIPisInfinity(scip, REALABS(coef)));
14663 
14664  if( SCIPisZero(scip, coef) )
14665  return SCIP_OKAY;
14666 
14667  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
14668  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
14669  {
14670  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
14671  return SCIP_INVALIDCALL;
14672  }
14673 
14674  consdata = SCIPconsGetData(cons);
14675  assert(consdata != NULL);
14676 
14677  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var, &pos) );
14678  if( pos < 0 )
14679  {
14680  SCIP_CALL( addQuadVarTerm(scip, cons, var, coef, 0.0) );
14681  return SCIP_OKAY;
14682  }
14683  assert(pos < consdata->nquadvars);
14684  assert(consdata->quadvarterms[pos].var == var);
14685 
14686  consdata->quadvarterms[pos].lincoef += coef;
14687 
14688  /* update flags and invalid activities */
14689  consdata->ispropagated = FALSE;
14690  consdata->ispresolved = consdata->ispresolved && !SCIPisZero(scip, consdata->quadvarterms[pos].lincoef);
14691 
14692  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
14693  consdata->activity = SCIP_INVALID;
14694 
14695  return SCIP_OKAY;
14696 }
14697 
14698 /** Adds a square coefficient for a quadratic variable.
14699  *
14700  * Variable will be added with linear coefficient 0.0 if not existing yet.
14701  */
14703  SCIP* scip, /**< SCIP data structure */
14704  SCIP_CONS* cons, /**< constraint */
14705  SCIP_VAR* var, /**< variable */
14706  SCIP_Real coef /**< value to add to square coefficient of variable */
14707  )
14708 {
14709  SCIP_CONSDATA* consdata;
14710  int pos;
14711 
14712  assert(scip != NULL);
14713  assert(cons != NULL);
14714  assert(var != NULL);
14715  assert(!SCIPisInfinity(scip, REALABS(coef)));
14716 
14717  if( SCIPisZero(scip, coef) )
14718  return SCIP_OKAY;
14719 
14720  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
14721  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
14722  {
14723  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
14724  return SCIP_INVALIDCALL;
14725  }
14726 
14727  consdata = SCIPconsGetData(cons);
14728  assert(consdata != NULL);
14729 
14730  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var, &pos) );
14731  if( pos < 0 )
14732  {
14733  SCIP_CALL( addQuadVarTerm(scip, cons, var, 0.0, coef) );
14734  return SCIP_OKAY;
14735  }
14736  assert(pos < consdata->nquadvars);
14737  assert(consdata->quadvarterms[pos].var == var);
14738 
14739  consdata->quadvarterms[pos].sqrcoef += coef;
14740 
14741  /* update flags and invalid activities */
14742  consdata->isconvex = FALSE;
14743  consdata->isconcave = FALSE;
14744  consdata->iscurvchecked = FALSE;
14745  consdata->ispropagated = FALSE;
14746  consdata->ispresolved = consdata->ispresolved && !SCIPisZero(scip, consdata->quadvarterms[pos].sqrcoef);
14747 
14748  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
14749  consdata->activity = SCIP_INVALID;
14750 
14751  return SCIP_OKAY;
14752 }
14753 
14754 /** Adds a bilinear term to a quadratic constraint.
14755  *
14756  * Variables will be added with linear and square coefficient 0.0 if not existing yet.
14757  * If variables are equal, only the square coefficient of the variable is updated.
14758  */
14760  SCIP* scip, /**< SCIP data structure */
14761  SCIP_CONS* cons, /**< constraint */
14762  SCIP_VAR* var1, /**< first variable */
14763  SCIP_VAR* var2, /**< second variable */
14764  SCIP_Real coef /**< coefficient of bilinear term */
14765  )
14766 {
14767  SCIP_CONSDATA* consdata;
14768  int var1pos;
14769  int var2pos;
14770 
14771  assert(scip != NULL);
14772  assert(cons != NULL);
14773  assert(var1 != NULL);
14774  assert(var2 != NULL);
14775  assert(!SCIPisInfinity(scip, REALABS(coef)));
14776 
14777  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
14778  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
14779  {
14780  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
14781  return SCIP_INVALIDCALL;
14782  }
14783 
14784  if( var1 == var2 )
14785  {
14786  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, cons, var1, coef) );
14787  return SCIP_OKAY;
14788  }
14789 
14790  consdata = SCIPconsGetData(cons);
14791  assert(consdata != NULL);
14792 
14793  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var1, &var1pos) );
14794  if( var1pos < 0 )
14795  {
14796  SCIP_CALL( addQuadVarTerm(scip, cons, var1, 0.0, 0.0) );
14797  var1pos = consdata->nquadvars-1;
14798  }
14799 
14800  if( !consdata->quadvarssorted )
14801  {
14802  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
14803  /* sorting may change the position of var1 */
14804  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var1, &var1pos) );
14805  assert(var1pos >= 0);
14806  }
14807 
14808  assert(consdata->quadvarssorted);
14809  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var2, &var2pos) );
14810  if( var2pos < 0 )
14811  {
14812  SCIP_CALL( addQuadVarTerm(scip, cons, var2, 0.0, 0.0) );
14813  var2pos = consdata->nquadvars-1;
14814  }
14815 
14816  assert(consdata->quadvarterms[var1pos].var == var1);
14817  assert(consdata->quadvarterms[var2pos].var == var2);
14818 
14819  SCIP_CALL( addBilinearTerm(scip, cons, var1pos, var2pos, coef) );
14820 
14821  return SCIP_OKAY;
14822 }
14823 
14824 /** Gets the quadratic constraint as a nonlinear row representation. */
14826  SCIP* scip, /**< SCIP data structure */
14827  SCIP_CONS* cons, /**< constraint */
14828  SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
14829  )
14830 {
14831  SCIP_CONSDATA* consdata;
14832 
14833  assert(cons != NULL);
14834  assert(nlrow != NULL);
14835 
14836  consdata = SCIPconsGetData(cons);
14837  assert(consdata != NULL);
14838 
14839  if( consdata->nlrow == NULL )
14840  {
14841  SCIP_CALL( createNlRow(scip, cons) );
14842  }
14843  assert(consdata->nlrow != NULL);
14844  *nlrow = consdata->nlrow;
14845 
14846  return SCIP_OKAY;
14847 }
14848 
14849 /** Gets the number of variables in the linear term of a quadratic constraint. */
14851  SCIP* scip, /**< SCIP data structure */
14852  SCIP_CONS* cons /**< constraint */
14853  )
14854 {
14855  assert(cons != NULL);
14856  assert(SCIPconsGetData(cons) != NULL);
14857 
14858  return SCIPconsGetData(cons)->nlinvars;
14859 }
14860 
14861 /** Gets the variables in the linear part of a quadratic constraint.
14862  * Length is given by SCIPgetNLinearVarsQuadratic.
14863  */
14865  SCIP* scip, /**< SCIP data structure */
14866  SCIP_CONS* cons /**< constraint */
14867  )
14868 {
14869  assert(cons != NULL);
14870  assert(SCIPconsGetData(cons) != NULL);
14871 
14872  return SCIPconsGetData(cons)->linvars;
14873 }
14874 
14875 /** Gets the coefficients in the linear part of a quadratic constraint.
14876  * Length is given by SCIPgetNLinearVarsQuadratic.
14877  */
14879  SCIP* scip, /**< SCIP data structure */
14880  SCIP_CONS* cons /**< constraint */
14881  )
14882 {
14883  assert(cons != NULL);
14884  assert(SCIPconsGetData(cons) != NULL);
14885 
14886  return SCIPconsGetData(cons)->lincoefs;
14887 }
14888 
14889 /** Gets the number of quadratic variable terms of a quadratic constraint.
14890  */
14892  SCIP* scip, /**< SCIP data structure */
14893  SCIP_CONS* cons /**< constraint */
14894  )
14895 {
14896  assert(cons != NULL);
14897  assert(SCIPconsGetData(cons) != NULL);
14898 
14899  return SCIPconsGetData(cons)->nquadvars;
14900 }
14901 
14902 /** Gets the quadratic variable terms of a quadratic constraint.
14903  * Length is given by SCIPgetNQuadVarTermsQuadratic.
14904  */
14906  SCIP* scip, /**< SCIP data structure */
14907  SCIP_CONS* cons /**< constraint */
14908  )
14909 {
14910  assert(cons != NULL);
14911  assert(SCIPconsGetData(cons) != NULL);
14912 
14913  return SCIPconsGetData(cons)->quadvarterms;
14914 }
14915 
14916 /** Ensures that quadratic variable terms are sorted. */
14918  SCIP* scip, /**< SCIP data structure */
14919  SCIP_CONS* cons /**< constraint */
14920  )
14921 {
14922  assert(cons != NULL);
14923  assert(SCIPconsGetData(cons) != NULL);
14924 
14926 
14927  return SCIP_OKAY;
14928 }
14929 
14930 /** Finds the position of a quadratic variable term for a given variable.
14931  *
14932  * @note If the quadratic variable terms have not been sorted before, then a search may reorder the current order of the terms.
14933  */
14935  SCIP* scip, /**< SCIP data structure */
14936  SCIP_CONS* cons, /**< constraint */
14937  SCIP_VAR* var, /**< variable to search for */
14938  int* pos /**< buffer to store position of quadvarterm for var, or -1 if not found */
14939  )
14940 {
14941  assert(cons != NULL);
14942  assert(SCIPconsGetData(cons) != NULL);
14943  assert(var != NULL);
14944  assert(pos != NULL);
14945 
14946  SCIP_CALL( consdataFindQuadVarTerm(scip, SCIPconsGetData(cons), var, pos) );
14947 
14948  return SCIP_OKAY;
14949 }
14950 
14951 /** Gets the number of bilinear terms of a quadratic constraint. */
14953  SCIP* scip, /**< SCIP data structure */
14954  SCIP_CONS* cons /**< constraint */
14955  )
14956 {
14957  assert(cons != NULL);
14958  assert(SCIPconsGetData(cons) != NULL);
14959 
14960  return SCIPconsGetData(cons)->nbilinterms;
14961 }
14962 
14963 /** Gets the bilinear terms of a quadratic constraint.
14964  * Length is given by SCIPgetNBilinTermQuadratic.
14965  */
14967  SCIP* scip, /**< SCIP data structure */
14968  SCIP_CONS* cons /**< constraint */
14969  )
14970 {
14971  assert(cons != NULL);
14972  assert(SCIPconsGetData(cons) != NULL);
14973 
14974  return SCIPconsGetData(cons)->bilinterms;
14975 }
14976 
14977 /** Gets the left hand side of a quadratic constraint. */
14979  SCIP* scip, /**< SCIP data structure */
14980  SCIP_CONS* cons /**< constraint */
14981  )
14982 {
14983  assert(cons != NULL);
14984  assert(SCIPconsGetData(cons) != NULL);
14985 
14986  return SCIPconsGetData(cons)->lhs;
14987 }
14988 
14989 /** Gets the right hand side of a quadratic constraint. */
14991  SCIP* scip, /**< SCIP data structure */
14992  SCIP_CONS* cons /**< constraint */
14993  )
14994 {
14995  assert(cons != NULL);
14996  assert(SCIPconsGetData(cons) != NULL);
14997 
14998  return SCIPconsGetData(cons)->rhs;
14999 }
15000 
15001 /** get index of a variable in linvars that may be decreased without making any other constraint infeasible, or -1 if none */
15003  SCIP* scip, /**< SCIP data structure */
15004  SCIP_CONS* cons /**< constraint */
15005  )
15006 {
15007  SCIP_CONSDATA* consdata;
15008 
15009  assert(cons != NULL);
15010 
15011  consdata = SCIPconsGetData(cons);
15012  assert(consdata != NULL);
15013 
15014  /* check for a linear variable that can be increase or decreased without harming feasibility */
15015  consdataFindUnlockedLinearVar(scip, consdata);
15016 
15017  return consdata->linvar_maydecrease;
15018 }
15019 
15020 /** get index of a variable in linvars that may be increased without making any other constraint infeasible, or -1 if none */
15022  SCIP* scip, /**< SCIP data structure */
15023  SCIP_CONS* cons /**< constraint */
15024  )
15025 {
15026  SCIP_CONSDATA* consdata;
15027 
15028  assert(cons != NULL);
15029 
15030  consdata = SCIPconsGetData(cons);
15031  assert(consdata != NULL);
15032 
15033  /* check for a linear variable that can be increase or decreased without harming feasibility */
15034  consdataFindUnlockedLinearVar(scip, consdata);
15035 
15036  return consdata->linvar_mayincrease;
15037 }
15038 
15039 /** Check the quadratic function of a quadratic constraint for its semi-definiteness, if not done yet. */
15041  SCIP* scip, /**< SCIP data structure */
15042  SCIP_CONS* cons /**< constraint */
15043  )
15044 {
15045  assert(cons != NULL);
15046 
15047  SCIP_CALL( checkCurvature(scip, cons, TRUE) );
15048 
15049  return SCIP_OKAY;
15050 }
15051 
15052 /** Indicates whether the quadratic function of a quadratic constraint is (known to be) convex. */
15054  SCIP* scip, /**< SCIP data structure */
15055  SCIP_CONS* cons /**< constraint */
15056  )
15057 {
15058  SCIP_Bool determined;
15059 
15060  assert(cons != NULL);
15061  assert(SCIPconsGetData(cons) != NULL);
15062 
15063  checkCurvatureEasy(scip, cons, &determined, FALSE);
15064  assert(determined);
15065 
15066  return (SCIPconsGetData(cons)->isconvex);
15067 }
15068 
15069 /** Indicates whether the quadratic function of a quadratic constraint is (known to be) concave. */
15071  SCIP* scip, /**< SCIP data structure */
15072  SCIP_CONS* cons /**< constraint */
15073  )
15074 {
15075  SCIP_Bool determined;
15076 
15077  assert(cons != NULL);
15078  assert(SCIPconsGetData(cons) != NULL);
15079 
15080  checkCurvatureEasy(scip, cons, &determined, FALSE);
15081  assert(determined);
15082 
15083  return (SCIPconsGetData(cons)->isconcave);
15084 }
15085 
15086 /** Computes the violation of a constraint by a solution */
15088  SCIP* scip, /**< SCIP data structure */
15089  SCIP_CONS* cons, /**< constraint */
15090  SCIP_SOL* sol, /**< solution which violation to calculate, or NULL for LP solution */
15091  SCIP_Real* violation /**< pointer to store violation of constraint */
15092  )
15093 {
15094  SCIP_CONSDATA* consdata;
15095  SCIP_Bool solviolbounds;
15096 
15097  assert(scip != NULL);
15098  assert(cons != NULL);
15099  assert(violation != NULL);
15100 
15101  SCIP_CALL( computeViolation(scip, cons, sol, &solviolbounds) );
15102  /* we don't care here whether the solution violated variable bounds */
15103 
15104  consdata = SCIPconsGetData(cons);
15105  assert(consdata != NULL);
15106 
15107  *violation = MAX(consdata->lhsviol, consdata->rhsviol);
15108 
15109  return SCIP_OKAY;
15110 }
15111 
15112 /** Indicates whether the quadratic constraint is local w.r.t. the current local bounds.
15113  *
15114  * That is, checks whether each variable with a square term is fixed and for each bilinear term at least one variable is fixed.
15115  */
15117  SCIP* scip, /**< SCIP data structure */
15118  SCIP_CONS* cons /**< constraint */
15119  )
15120 {
15121  SCIP_CONSDATA* consdata;
15122  SCIP_VAR* var1;
15123  SCIP_VAR* var2;
15124  int i;
15125 
15126  assert(scip != NULL);
15127  assert(cons != NULL);
15128 
15129  consdata = SCIPconsGetData(cons);
15130  assert(consdata != NULL);
15131 
15132  /* check all square terms */
15133  for( i = 0; i < consdata->nquadvars; ++i )
15134  {
15135  if( consdata->quadvarterms[i].sqrcoef == 0.0 )
15136  continue;
15137 
15138  var1 = consdata->quadvarterms[i].var;
15139  assert(var1 != NULL);
15140 
15141  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var1), SCIPvarGetUbLocal(var1)) )
15142  return FALSE;
15143  }
15144 
15145  for( i = 0; i < consdata->nbilinterms; ++i )
15146  {
15147  var1 = consdata->bilinterms[i].var1;
15148  var2 = consdata->bilinterms[i].var2;
15149 
15150  assert(var1 != NULL);
15151  assert(var2 != NULL);
15152 
15153  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var1), SCIPvarGetUbLocal(var1)) &&
15154  ! SCIPisRelEQ(scip, SCIPvarGetLbLocal(var2), SCIPvarGetUbLocal(var2)) )
15155  return FALSE;
15156  }
15157 
15158  return TRUE;
15159 }
15160 
15161 /** Adds the constraint to an NLPI problem. */
15163  SCIP* scip, /**< SCIP data structure */
15164  SCIP_CONS* cons, /**< constraint */
15165  SCIP_NLPI* nlpi, /**< interface to NLP solver */
15166  SCIP_NLPIPROBLEM* nlpiprob, /**< NLPI problem where to add constraint */
15167  SCIP_HASHMAP* scipvar2nlpivar, /**< mapping from SCIP variables to variable indices in NLPI */
15168  SCIP_Bool names /**< whether to pass constraint names to NLPI */
15169  )
15170 {
15171  SCIP_CONSDATA* consdata;
15172  int nlininds;
15173  int* lininds;
15174  SCIP_Real* linvals;
15175  int nquadelems;
15176  SCIP_QUADELEM* quadelems;
15177  SCIP_VAR* othervar;
15178  const char* name;
15179  int j;
15180  int l;
15181  int lincnt;
15182  int quadcnt;
15183  int idx1;
15184  int idx2;
15185 
15186  assert(scip != NULL);
15187  assert(cons != NULL);
15188  assert(nlpi != NULL);
15189  assert(nlpiprob != NULL);
15190  assert(scipvar2nlpivar != NULL);
15191 
15192  consdata = SCIPconsGetData(cons);
15193  assert(consdata != NULL);
15194 
15195  /* count nonzeros in quadratic part */
15196  nlininds = consdata->nlinvars;
15197  nquadelems = consdata->nbilinterms;
15198  for( j = 0; j < consdata->nquadvars; ++j )
15199  {
15200  if( consdata->quadvarterms[j].sqrcoef != 0.0 )
15201  ++nquadelems;
15202  if( consdata->quadvarterms[j].lincoef != 0.0 )
15203  ++nlininds;
15204  }
15205 
15206  /* setup linear part */
15207  lininds = NULL;
15208  linvals = NULL;
15209  lincnt = 0;
15210  if( nlininds > 0 )
15211  {
15212  SCIP_CALL( SCIPallocBufferArray(scip, &lininds, nlininds) );
15213  SCIP_CALL( SCIPallocBufferArray(scip, &linvals, nlininds) );
15214 
15215  for( j = 0; j < consdata->nlinvars; ++j )
15216  {
15217  linvals[j] = consdata->lincoefs[j];
15218  assert(SCIPhashmapExists(scipvar2nlpivar, consdata->linvars[j]));
15219  lininds[j] = (int) (size_t) SCIPhashmapGetImage(scipvar2nlpivar, consdata->linvars[j]);
15220  }
15221 
15222  lincnt = consdata->nlinvars;
15223  }
15224 
15225  /* setup quadratic part */
15226  quadelems = NULL;
15227  if( nquadelems > 0 )
15228  {
15229  SCIP_CALL( SCIPallocBufferArray(scip, &quadelems, nquadelems) );
15230  }
15231  quadcnt = 0;
15232 
15233  for( j = 0; j < consdata->nquadvars; ++j )
15234  {
15235  assert(SCIPhashmapExists(scipvar2nlpivar, consdata->quadvarterms[j].var));
15236  idx1 = (int)(size_t)SCIPhashmapGetImage(scipvar2nlpivar, consdata->quadvarterms[j].var);
15237  if( consdata->quadvarterms[j].lincoef != 0.0 )
15238  {
15239  assert(lininds != NULL);
15240  assert(linvals != NULL);
15241  lininds[lincnt] = idx1;
15242  linvals[lincnt] = consdata->quadvarterms[j].lincoef;
15243  ++lincnt;
15244  }
15245 
15246  if( consdata->quadvarterms[j].sqrcoef != 0.0 )
15247  {
15248  assert(quadcnt < nquadelems);
15249  assert(quadelems != NULL);
15250  quadelems[quadcnt].idx1 = idx1;
15251  quadelems[quadcnt].idx2 = idx1;
15252  quadelems[quadcnt].coef = consdata->quadvarterms[j].sqrcoef;
15253  ++quadcnt;
15254  }
15255 
15256  for( l = 0; l < consdata->quadvarterms[j].nadjbilin; ++l )
15257  {
15258  othervar = consdata->bilinterms[consdata->quadvarterms[j].adjbilin[l]].var2;
15259  /* if othervar is on position 2, then we process this bilinear term later (or it was processed already) */
15260  if( othervar == consdata->quadvarterms[j].var )
15261  continue;
15262 
15263  assert(quadcnt < nquadelems);
15264  assert(quadelems != NULL);
15265  assert(SCIPhashmapExists(scipvar2nlpivar, othervar));
15266  idx2 = (int)(size_t)SCIPhashmapGetImage(scipvar2nlpivar, othervar);
15267  quadelems[quadcnt].idx1 = MIN(idx1, idx2);
15268  quadelems[quadcnt].idx2 = MAX(idx1, idx2);
15269  quadelems[quadcnt].coef = consdata->bilinterms[consdata->quadvarterms[j].adjbilin[l]].coef;
15270  ++quadcnt;
15271  }
15272  }
15273 
15274  assert(quadcnt == nquadelems);
15275  assert(lincnt == nlininds);
15276 
15277  name = names ? SCIPconsGetName(cons) : NULL;
15278 
15279  SCIP_CALL( SCIPnlpiAddConstraints(nlpi, nlpiprob, 1,
15280  &consdata->lhs, &consdata->rhs,
15281  &nlininds, &lininds, &linvals ,
15282  &nquadelems, &quadelems,
15283  NULL, NULL, &name) );
15284 
15285  SCIPfreeBufferArrayNull(scip, &quadelems);
15286  SCIPfreeBufferArrayNull(scip, &lininds);
15287  SCIPfreeBufferArrayNull(scip, &linvals);
15288 
15289  return SCIP_OKAY;
15290 }
15291 
15292 
15293 /** sets the left hand side of a quadratic constraint
15294  *
15295  * @note This method may only be called during problem creation stage for an original constraint.
15296  */
15298  SCIP* scip, /**< SCIP data structure */
15299  SCIP_CONS* cons, /**< constraint data */
15300  SCIP_Real lhs /**< new left hand side */
15301  )
15302 {
15303  SCIP_CONSDATA* consdata;
15304 
15305  assert(scip != NULL);
15306  assert(cons != NULL);
15307  assert(!SCIPisInfinity(scip, lhs));
15308 
15309  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
15310  {
15311  SCIPerrorMessage("constraint is not quadratic\n");
15312  return SCIP_INVALIDDATA;
15313  }
15314 
15315  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) )
15316  {
15317  SCIPerrorMessage("method may only be called during problem creation stage for original constraints\n");
15318  return SCIP_INVALIDDATA;
15319  }
15320 
15321  consdata = SCIPconsGetData(cons);
15322  assert(consdata != NULL);
15323  assert(!SCIPisInfinity(scip, consdata->lhs));
15324 
15325  /* adjust value to not be smaller than -inf */
15326  if( SCIPisInfinity(scip, -lhs) )
15327  lhs = -SCIPinfinity(scip);
15328 
15329  /* check for lhs <= rhs */
15330  if( !SCIPisLE(scip, lhs, consdata->rhs) )
15331  return SCIP_INVALIDDATA;
15332 
15333  consdata->lhs = lhs;
15334 
15335  return SCIP_OKAY;
15336 }
15337 
15338 /** sets the right hand side of a quadratic constraint
15339  *
15340  * @note This method may only be called during problem creation stage for an original constraint.
15341  */
15343  SCIP* scip, /**< SCIP data structure */
15344  SCIP_CONS* cons, /**< constraint data */
15345  SCIP_Real rhs /**< new right hand side */
15346  )
15347 {
15348  SCIP_CONSDATA* consdata;
15349 
15350  assert(scip != NULL);
15351  assert(cons != NULL);
15352  assert(!SCIPisInfinity(scip, -rhs));
15353 
15354  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
15355  {
15356  SCIPerrorMessage("constraint is not quadratic\n");
15357  return SCIP_INVALIDDATA;
15358  }
15359 
15360  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) )
15361  {
15362  SCIPerrorMessage("method may only be called during problem creation stage for original constraints\n");
15363  return SCIP_INVALIDDATA;
15364  }
15365 
15366  consdata = SCIPconsGetData(cons);
15367  assert(consdata != NULL);
15368  assert(!SCIPisInfinity(scip, -consdata->rhs));
15369 
15370  /* adjust value to not be greater than inf */
15371  if( SCIPisInfinity(scip, rhs) )
15372  rhs = SCIPinfinity(scip);
15373 
15374  /* check for lhs <= rhs */
15375  if( !SCIPisLE(scip, consdata->lhs, rhs) )
15376  return SCIP_INVALIDDATA;
15377 
15378  consdata->rhs = rhs;
15379 
15380  return SCIP_OKAY;
15381 }
15382 
15383 /** gets the feasibility of the quadratic constraint in the given solution */
15385  SCIP* scip, /**< SCIP data structure */
15386  SCIP_CONS* cons, /**< constraint data */
15387  SCIP_SOL* sol, /**< solution, or NULL to use current node's solution */
15388  SCIP_Real* feasibility /**< pointer to store the feasibility */
15389  )
15390 {
15391  SCIP_CONSDATA* consdata;
15392  SCIP_Bool solviolbounds;
15393 
15394  assert(scip != NULL);
15395  assert(cons != NULL);
15396  assert(feasibility != NULL);
15397 
15398  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
15399  {
15400  SCIPerrorMessage("constraint is not quadratic\n");
15401  SCIPABORT();
15402  }
15403 
15404  SCIP_CALL( computeViolation(scip, cons, sol, &solviolbounds) );
15405 
15406  consdata = SCIPconsGetData(cons);
15407  assert(consdata != NULL);
15408 
15409  if( SCIPisInfinity(scip, consdata->rhs) && SCIPisInfinity(scip, -consdata->lhs) )
15410  *feasibility = SCIPinfinity(scip);
15411  else if( SCIPisInfinity(scip, -consdata->lhs) )
15412  *feasibility = (consdata->rhs - consdata->activity);
15413  else if( SCIPisInfinity(scip, consdata->rhs) )
15414  *feasibility = (consdata->activity - consdata->lhs);
15415  else
15416  {
15417  assert(!SCIPisInfinity(scip, -consdata->rhs));
15418  assert(!SCIPisInfinity(scip, consdata->lhs));
15419  *feasibility = MIN( consdata->rhs - consdata->activity, consdata->activity - consdata->lhs );
15420  }
15421 
15422  return SCIP_OKAY;
15423 }
15424 
15425 /** gets the activity of the quadratic constraint in the given solution */
15427  SCIP* scip, /**< SCIP data structure */
15428  SCIP_CONS* cons, /**< constraint data */
15429  SCIP_SOL* sol, /**< solution, or NULL to use current node's solution */
15430  SCIP_Real* activity /**< pointer to store the activity */
15431  )
15432 {
15433  SCIP_CONSDATA* consdata;
15434  SCIP_Bool solviolbounds;
15435 
15436  assert(scip != NULL);
15437  assert(cons != NULL);
15438  assert(activity != NULL);
15439 
15440  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
15441  {
15442  SCIPerrorMessage("constraint is not quadratic\n");
15443  SCIPABORT();
15444  }
15445 
15446  SCIP_CALL( computeViolation(scip, cons, sol, &solviolbounds) );
15447 
15448  consdata = SCIPconsGetData(cons);
15449  assert(consdata != NULL);
15450 
15451  *activity = consdata->activity;
15452 
15453  return SCIP_OKAY;
15454 }
15455 
15456 /** changes the linear coefficient value for a given quadratic variable in a quadratic constraint data; if not
15457  * available, it adds it
15458  *
15459  * @note this is only allowed for original constraints and variables in problem creation stage
15460  */
15462  SCIP* scip, /**< SCIP data structure */
15463  SCIP_CONS* cons, /**< constraint data */
15464  SCIP_VAR* var, /**< quadratic variable */
15465  SCIP_Real coef /**< new coefficient */
15466  )
15467 {
15468  SCIP_CONSDATA* consdata;
15469  SCIP_Bool found;
15470  int i;
15471 
15472  assert(scip != NULL);
15473  assert(cons != NULL);
15474  assert(var != NULL);
15475 
15476  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
15477  {
15478  SCIPerrorMessage("constraint is not quadratic\n");
15479  return SCIP_INVALIDDATA;
15480  }
15481 
15482  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) || !SCIPvarIsOriginal(var) )
15483  {
15484  SCIPerrorMessage("method may only be called during problem creation stage for original constraints and variables\n");
15485  return SCIP_INVALIDDATA;
15486  }
15487 
15488  consdata = SCIPconsGetData(cons);
15489  assert(consdata != NULL);
15490 
15491  /* check all quadratic variables */
15492  found = FALSE;
15493  for( i = 0; i < consdata->nquadvars; ++i )
15494  {
15495  if( var == consdata->quadvarterms[i].var )
15496  {
15497  if( found || SCIPisZero(scip, coef) )
15498  {
15499  consdata->quadvarterms[i].lincoef = 0.0;
15500 
15501  /* remember to merge quadratic variable terms */
15502  consdata->quadvarsmerged = FALSE;
15503  }
15504  else
15505  consdata->quadvarterms[i].lincoef = coef;
15506 
15507  found = TRUE;
15508  }
15509  }
15510 
15511  /* check all linear variables */
15512  i = 0;
15513  while( i < consdata->nlinvars )
15514  {
15515  if( var == consdata->linvars[i] )
15516  {
15517  if( found || SCIPisZero(scip, coef) )
15518  {
15519  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
15520 
15521  /* decrease i by one since otherwise we would skip the coefficient which has been switched to position i */
15522  i--;
15523  }
15524  else
15525  {
15526  SCIP_CALL( chgLinearCoefPos(scip, cons, i, coef) );
15527  }
15528 
15529  found = TRUE;
15530  }
15531  i++;
15532  }
15533 
15534  /* add linear term if necessary */
15535  if( !found && !SCIPisZero(scip, coef) )
15536  {
15537  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
15538  }
15539 
15540  consdata->ispropagated = FALSE;
15541  consdata->ispresolved = FALSE;
15542 
15543  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
15544  consdata->activity = SCIP_INVALID;
15545 
15546  return SCIP_OKAY;
15547 }
15548 
15549 /** changes the square coefficient value for a given quadratic variable in a quadratic constraint data; if not
15550  * available, it adds it
15551  *
15552  * @note this is only allowed for original constraints and variables in problem creation stage
15553  */
15555  SCIP* scip, /**< SCIP data structure */
15556  SCIP_CONS* cons, /**< constraint data */
15557  SCIP_VAR* var, /**< quadratic variable */
15558  SCIP_Real coef /**< new coefficient */
15559  )
15560 {
15561  SCIP_CONSDATA* consdata;
15562  SCIP_Bool found;
15563  int i;
15564 
15565  assert(scip != NULL);
15566  assert(cons != NULL);
15567  assert(var != NULL);
15568  assert(!SCIPisInfinity(scip, REALABS(coef)));
15569 
15570  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
15571  {
15572  SCIPerrorMessage("constraint is not quadratic\n");
15573  return SCIP_INVALIDDATA;
15574  }
15575 
15576  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) || !SCIPvarIsOriginal(var) )
15577  {
15578  SCIPerrorMessage("method may only be called during problem creation stage for original constraints and variables\n");
15579  return SCIP_INVALIDDATA;
15580  }
15581 
15582  consdata = SCIPconsGetData(cons);
15583  assert(consdata != NULL);
15584 
15585  /* find the quadratic variable and change its quadratic coefficient */
15586  found = FALSE;
15587  for( i = 0; i < consdata->nquadvars; ++i )
15588  {
15589  if( var == consdata->quadvarterms[i].var )
15590  {
15591  consdata->quadvarterms[i].sqrcoef = (found || SCIPisZero(scip, coef)) ? 0.0 : coef;
15592  found = TRUE;
15593  }
15594  }
15595 
15596  /* add bilinear term if necessary */
15597  if( !found && !SCIPisZero(scip, coef) )
15598  {
15599  SCIP_CALL( addQuadVarTerm(scip, cons, var, 0.0, coef) );
15600  }
15601 
15602  /* update flags and invalidate activities */
15603  consdata->isconvex = FALSE;
15604  consdata->isconcave = FALSE;
15605  consdata->iscurvchecked = FALSE;
15606  consdata->ispropagated = FALSE;
15607  consdata->ispresolved = FALSE;
15608 
15609  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
15610  consdata->activity = SCIP_INVALID;
15611 
15612  /* remember to merge quadratic variable terms */
15613  consdata->quadvarsmerged = FALSE;
15614 
15615  return SCIP_OKAY;
15616 }
15617 
15618 /** changes the bilinear coefficient value for a given quadratic variable in a quadratic constraint data; if not
15619  * available, it adds it
15620  *
15621  * @note this is only allowed for original constraints and variables in problem creation stage
15622  */
15624  SCIP* scip, /**< SCIP data structure */
15625  SCIP_CONS* cons, /**< constraint */
15626  SCIP_VAR* var1, /**< first variable */
15627  SCIP_VAR* var2, /**< second variable */
15628  SCIP_Real coef /**< coefficient of bilinear term */
15629  )
15630 {
15631  SCIP_CONSDATA* consdata;
15632  SCIP_Bool found;
15633  int i;
15634 
15635  assert(scip != NULL);
15636  assert(cons != NULL);
15637  assert(var1 != NULL);
15638  assert(var2 != NULL);
15639  assert(!SCIPisInfinity(scip, REALABS(coef)));
15640 
15641  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
15642  {
15643  SCIPerrorMessage("constraint is not quadratic\n");
15644  return SCIP_INVALIDDATA;
15645  }
15646 
15647  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) || !SCIPvarIsOriginal(var1) || !SCIPvarIsOriginal(var2) )
15648  {
15649  SCIPerrorMessage("method may only be called during problem creation stage for original constraints and variables\n");
15650  return SCIP_INVALIDDATA;
15651  }
15652 
15653  if( var1 == var2 )
15654  {
15655  SCIP_CALL( SCIPchgSquareCoefQuadratic(scip, cons, var1, coef) );
15656  return SCIP_OKAY;
15657  }
15658 
15659  consdata = SCIPconsGetData(cons);
15660  assert(consdata != NULL);
15661 
15662  /* search array of bilinear terms */
15663  found = FALSE;
15664  for( i = 0; i < consdata->nbilinterms; ++i )
15665  {
15666  if( (consdata->bilinterms[i].var1 == var1 && consdata->bilinterms[i].var2 == var2) ||
15667  (consdata->bilinterms[i].var1 == var2 && consdata->bilinterms[i].var2 == var1) )
15668  {
15669  if( found || SCIPisZero(scip, coef) )
15670  {
15671  consdata->bilinterms[i].coef = 0.0;
15672 
15673  /* remember to merge bilinear terms */
15674  consdata->bilinmerged = FALSE;
15675  }
15676  else
15677  consdata->bilinterms[i].coef = coef;
15678  found = TRUE;
15679  }
15680  }
15681 
15682  /* add bilinear term if necessary */
15683  if( !found )
15684  {
15685  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, cons, var1, var2, coef) );
15686  }
15687 
15688  /* update flags and invalidate activities */
15689  consdata->isconvex = FALSE;
15690  consdata->isconcave = FALSE;
15691  consdata->iscurvchecked = FALSE;
15692  consdata->ispropagated = FALSE;
15693  consdata->ispresolved = FALSE;
15694 
15695  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
15696  consdata->activity = SCIP_INVALID;
15697 
15698  return SCIP_OKAY;
15699 }
15700 
15701 /** returns the total number of bilinear terms that are contained in all quadratic constraints */
15703  SCIP* scip /**< SCIP data structure */
15704  )
15705 {
15706  SCIP_CONSHDLRDATA* conshdlrdata;
15707  SCIP_CONSHDLR* conshdlr;
15708 
15709  assert(scip != NULL);
15710 
15711  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
15712 
15713  if( conshdlr == NULL )
15714  return 0;
15715 
15716  conshdlrdata = SCIPconshdlrGetData(conshdlr);
15717  assert(conshdlrdata != NULL);
15718 
15719  return conshdlrdata->nbilinterms;
15720 }
15721 
15722 /** returns all bilinear terms that are contained in all quadratic constraints */
15724  SCIP* scip, /**< SCIP data structure */
15725  SCIP_VAR** RESTRICT x, /**< array to store first variable of each bilinear term */
15726  SCIP_VAR** RESTRICT y, /**< array to second variable of each bilinear term */
15727  int* RESTRICT nbilinterms, /**< buffer to store the total number of bilinear terms */
15728  int* RESTRICT nunderests, /**< array to store the total number of constraints that require to underestimate a bilinear term */
15729  int* RESTRICT noverests, /**< array to store the total number of constraints that require to overestimate a bilinear term */
15730  SCIP_Real* maxnonconvexity /**< largest absolute value of nonconvex eigenvalues of all quadratic constraints containing a bilinear term */
15731  )
15732 {
15733  SCIP_CONSHDLRDATA* conshdlrdata;
15734  SCIP_CONSHDLR* conshdlr;
15735  int i;
15736 
15737  assert(scip != NULL);
15738  assert(x != NULL);
15739  assert(y != NULL);
15740  assert(nbilinterms != NULL);
15741  assert(nunderests != NULL);
15742  assert(noverests!= NULL);
15743  assert(maxnonconvexity != NULL);
15744 
15745  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
15746 
15747  if( conshdlr == NULL )
15748  {
15749  *nbilinterms = 0;
15750  return SCIP_OKAY;
15751  }
15752 
15753  conshdlrdata = SCIPconshdlrGetData(conshdlr);
15754  assert(conshdlrdata != NULL);
15755 
15756  for( i = 0; i < conshdlrdata->nbilinterms; ++i )
15757  {
15758  x[i] = conshdlrdata->bilinestimators[i].x;
15759  y[i] = conshdlrdata->bilinestimators[i].y;
15760  nunderests[i] = conshdlrdata->bilinestimators[i].nunderest;
15761  noverests[i] = conshdlrdata->bilinestimators[i].noverest;
15762  maxnonconvexity[i] = conshdlrdata->bilinestimators[i].maxnonconvexity;
15763  }
15764 
15765  *nbilinterms = conshdlrdata->nbilinterms;
15766 
15767  return SCIP_OKAY;
15768 }
15769 
15770 /** helper function to compute the violation of an inequality of the form xcoef * x <= ycoef * y + constant for two
15771  * corner points of the domain [lbx,ubx]x[lby,uby]
15772  */
15773 static
15774 void getIneqViol(
15775  SCIP_VAR* x, /**< first variable */
15776  SCIP_VAR* y, /**< second variable */
15777  SCIP_Real xcoef, /**< x-coefficient */
15778  SCIP_Real ycoef, /**< y-coefficient */
15779  SCIP_Real constant, /**< constant */
15780  SCIP_Real* viol1, /**< buffer to store the violation of the first corner point */
15781  SCIP_Real* viol2 /**< buffer to store the violation of the second corner point */
15782  )
15783 {
15784  SCIP_Real norm;
15785 
15786  assert(viol1 != NULL);
15787  assert(viol2 != NULL);
15788 
15789  norm = SQRT(SQR(xcoef) + SQR(ycoef));
15790 
15791  /* inequality can be used for underestimating xy if and only if xcoef * ycoef > 0 */
15792  if( xcoef * ycoef >= 0 )
15793  {
15794  /* violation for top-left and bottom-right corner */
15795  *viol1 = MAX(0, (xcoef * SCIPvarGetLbLocal(x) - ycoef * SCIPvarGetUbLocal(y) - constant) / norm); /*lint !e666*/
15796  *viol2 = MAX(0, (xcoef * SCIPvarGetUbLocal(x) - ycoef * SCIPvarGetLbLocal(y) - constant) / norm); /*lint !e666*/
15797  }
15798  else
15799  {
15800  /* violation for top-right and bottom-left corner */
15801  *viol1 = MAX(0, (xcoef * SCIPvarGetUbLocal(x) - ycoef * SCIPvarGetUbLocal(y) - constant) / norm); /*lint !e666*/
15802  *viol2 = MAX(0, (xcoef * SCIPvarGetLbLocal(x) - ycoef * SCIPvarGetLbLocal(y) - constant) / norm); /*lint !e666*/
15803  }
15804 
15805  return;
15806 }
15807 
15808 /** adds a globally valid inequality of the form xcoef x <= ycoef y + constant for a bilinear term (x,y)
15809  *
15810  * @note the indices of bilinear terms match with the entries of bilinear terms returned by SCIPgetAllBilinearTermsQuadratic
15811  */
15813  SCIP* scip, /**< SCIP data structure */
15814  SCIP_VAR* x, /**< first variable */
15815  SCIP_VAR* y, /**< second variable */
15816  int idx, /**< index of the bilinear term */
15817  SCIP_Real xcoef, /**< x coefficient */
15818  SCIP_Real ycoef, /**< y coefficient */
15819  SCIP_Real constant, /**< constant part */
15820  SCIP_Bool* success /**< buffer to store whether inequality has been accepted */
15821  )
15822 {
15823  SCIP_CONSHDLRDATA* conshdlrdata;
15824  SCIP_CONSHDLR* conshdlr;
15825  BILINESTIMATOR* bilinest;
15826  SCIP_Real* ineqs;
15827  SCIP_Real viol1 = 0.0;
15828  SCIP_Real viol2 = 0.0;
15829  int* nineqs;
15830  int i;
15831 
15832  assert(scip != NULL);
15833  assert(x != NULL);
15834  assert(y != NULL);
15835  assert(idx >= 0);
15836  assert(xcoef != SCIP_INVALID); /*lint !e777 */
15837  assert(ycoef != SCIP_INVALID); /*lint !e777 */
15838  assert(constant != SCIP_INVALID); /*lint !e777 */
15839  assert(success != NULL);
15840 
15841  *success = FALSE;
15842 
15843  /* ignore inequalities that only yield to a (possible) bound tightening */
15844  if( SCIPisFeasZero(scip, xcoef) || SCIPisFeasZero(scip, ycoef) )
15845  return SCIP_OKAY;
15846 
15847  /* get constraint handler and its data */
15848  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
15849  if( conshdlr == NULL )
15850  return SCIP_OKAY;
15851 
15852  conshdlrdata = SCIPconshdlrGetData(conshdlr);
15853  assert(conshdlrdata != NULL);
15854  assert(idx < conshdlrdata->nbilinterms);
15855 
15856  bilinest = &conshdlrdata->bilinestimators[idx];
15857  assert(bilinest != NULL);
15858  assert(bilinest->x == x);
15859  assert(bilinest->y == y);
15860 
15861  SCIPdebugMsg(scip, "add bilinear term inequality: %g %s <= %g %s + %g\n", xcoef, SCIPvarGetName(bilinest->x),
15862  ycoef, SCIPvarGetName(bilinest->y), constant);
15863 
15864  if( xcoef * ycoef > 0.0 )
15865  {
15866  ineqs = bilinest->inequnderest;
15867  nineqs = &bilinest->ninequnderest;
15868  }
15869  else
15870  {
15871  ineqs = bilinest->ineqoverest;
15872  nineqs = &bilinest->nineqoverest;
15873  }
15874 
15875  /* compute violation of the inequality of the important corner points */
15876  getIneqViol(x, y, xcoef, ycoef, constant, &viol1, &viol2);
15877  SCIPdebugMsg(scip, "violations of inequality = (%g,%g)\n", viol1, viol2);
15878 
15879  /* inequality does not cut off one of the important corner points */
15880  if( SCIPisFeasLE(scip, MAX(viol1, viol2), 0.0) )
15881  return SCIP_OKAY;
15882 
15883  /* check whether inequality exists already */
15884  for( i = 0; i < *nineqs; ++i )
15885  {
15886  if( SCIPisFeasEQ(scip, xcoef, ineqs[3*i]) && SCIPisFeasEQ(scip, ycoef, ineqs[3*i+1])
15887  && SCIPisFeasEQ(scip, constant, ineqs[3*i+2]) )
15888  {
15889  SCIPdebugMsg(scip, "inequality already found -> skip\n");
15890  return SCIP_OKAY;
15891  }
15892  }
15893 
15894  /* add inequality if we found less than two so far; otherwise compare the violations to decide which which
15895  * inequality might be replaced
15896  */
15897  if( *nineqs < 2 )
15898  {
15899  ineqs[3*(*nineqs)] = xcoef;
15900  ineqs[3*(*nineqs) + 1] = ycoef;
15901  ineqs[3*(*nineqs) + 2] = constant;
15902  ++(*nineqs);
15903  *success = TRUE;
15904  }
15905  else
15906  {
15907  SCIP_Real viols1[2] = {0.0, 0.0};
15908  SCIP_Real viols2[2] = {0.0, 0.0};
15909  SCIP_Real bestviol;
15910  int pos = -1;
15911 
15912  assert(*nineqs == 2);
15913 
15914  /* compute resulting violations of both corner points when replacing an existing inequality
15915  *
15916  * given the violations (v1,w1), (v2,w2), (v3,w3) we select two inequalities i and j that
15917  * maximize max{vi,vj} + max{wi,wj} this measurement guarantees that select inequalities that
15918  * separate both important corner points
15919  */
15920  getIneqViol(x, y, ineqs[0], ineqs[1], ineqs[2], &viols1[0], &viols2[0]);
15921  getIneqViol(x, y, ineqs[3], ineqs[4], ineqs[5], &viols1[1], &viols2[1]);
15922  bestviol = MAX(viols1[0], viols1[1]) + MAX(viols2[0], viols2[1]);
15923 
15924  for( i = 0; i < 2; ++i )
15925  {
15926  SCIP_Real viol = MAX(viol1, viols1[i]) + MAX(viol2, viols2[i]);
15927  if( SCIPisGT(scip, viol, bestviol) )
15928  {
15929  bestviol = viol;
15930  /* remember inequality that should be replaced */
15931  pos = 1 - i;
15932  }
15933  }
15934 
15935  /* replace inequality at pos when replacing an existing inequality improved the total violation */
15936  if( pos != -1 )
15937  {
15938  assert(pos >= 0 && pos < 2);
15939  ineqs[3*pos] = xcoef;
15940  ineqs[3*pos+1] = ycoef;
15941  ineqs[3*pos+2] = constant;
15942  *success = TRUE;
15943  }
15944  }
15945  SCIPdebugMsg(scip, "accepted inequality? %u\n", *success);
15946 
15947  return SCIP_OKAY;
15948 }
15949 
15950 
15951 /** creates a SCIP_ROWPREP datastructure
15952  *
15953  * Initial cut represents 0 <= 0.
15954  */
15956  SCIP* scip, /**< SCIP data structure */
15957  SCIP_ROWPREP** rowprep, /**< buffer to store pointer to rowprep */
15958  SCIP_SIDETYPE sidetype, /**< whether cut will be or lower-equal or larger-equal type */
15959  SCIP_Bool local /**< whether cut will be valid only locally */
15960  )
15961 {
15962  assert(scip != NULL);
15963  assert(rowprep != NULL);
15964 
15965  SCIP_CALL( SCIPallocBlockMemory(scip, rowprep) );
15966  BMSclearMemory(*rowprep);
15967 
15968  (*rowprep)->sidetype = sidetype;
15969  (*rowprep)->local = local;
15970 
15971  return SCIP_OKAY;
15972 }
15973 
15974 /** frees a SCIP_ROWPREP datastructure */
15975 void SCIPfreeRowprep(
15976  SCIP* scip, /**< SCIP data structure */
15977  SCIP_ROWPREP** rowprep /**< pointer that stores pointer to rowprep */
15978  )
15979 {
15980  assert(scip != NULL);
15981  assert(rowprep != NULL);
15982  assert(*rowprep != NULL);
15983 
15984  SCIPfreeBlockMemoryArrayNull(scip, &(*rowprep)->vars, (*rowprep)->varssize);
15985  SCIPfreeBlockMemoryArrayNull(scip, &(*rowprep)->coefs, (*rowprep)->varssize);
15986  SCIPfreeBlockMemory(scip, rowprep);
15987 }
15988 
15989 /** creates a copy of a SCIP_ROWPREP datastructure */
15991  SCIP* scip, /**< SCIP data structure */
15992  SCIP_ROWPREP** target, /**< buffer to store pointer of rowprep copy */
15993  SCIP_ROWPREP* source /**< rowprep to copy */
15994  )
15995 {
15996  assert(scip != NULL);
15997  assert(target != NULL);
15998  assert(source != NULL);
15999 
16000  SCIP_CALL( SCIPduplicateBlockMemory(scip, target, source) );
16001  if( source->coefs != NULL )
16002  {
16003  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*target)->coefs, source->coefs, source->varssize) );
16004  }
16005  if( source->vars != NULL )
16006  {
16007  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*target)->vars, source->vars, source->varssize) );
16008  }
16009 
16010  return SCIP_OKAY;
16011 }
16012 
16013 /** ensures that rowprep has space for at least given number of additional terms
16014  *
16015  * Useful when knowing in advance how many terms will be added.
16016  */
16018  SCIP* scip, /**< SCIP data structure */
16019  SCIP_ROWPREP* rowprep, /**< rowprep */
16020  int size /**< number of additional terms for which to alloc space in rowprep */
16021  )
16022 {
16023  int oldsize;
16024 
16025  assert(scip != NULL);
16026  assert(rowprep != NULL);
16027  assert(size >= 0);
16028 
16029  if( rowprep->varssize >= rowprep->nvars + size )
16030  return SCIP_OKAY; /* already enough space left */
16031 
16032  /* realloc vars and coefs array */
16033  oldsize = rowprep->varssize;
16034  rowprep->varssize = SCIPcalcMemGrowSize(scip, rowprep->nvars + size);
16035 
16036  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &rowprep->vars, oldsize, rowprep->varssize) );
16037  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &rowprep->coefs, oldsize, rowprep->varssize) );
16038 
16039  return SCIP_OKAY;
16040 }
16041 
16042 /** prints a rowprep */
16043 void SCIPprintRowprep(
16044  SCIP* scip, /**< SCIP data structure */
16045  SCIP_ROWPREP* rowprep, /**< rowprep to be printed */
16046  FILE* file /**< file to print to, or NULL for stdout */
16047  )
16048 {
16049  int i;
16050 
16051  assert(scip != NULL);
16052  assert(rowprep != NULL);
16053 
16054  if( *rowprep->name != '\0' )
16055  {
16056  SCIPinfoMessage(scip, file, "[%s](%c) ", rowprep->name, rowprep->local ? 'l' : 'g');
16057  }
16058 
16059  for( i = 0; i < rowprep->nvars; ++i )
16060  {
16061  SCIPinfoMessage(scip, file, "%+.15g*<%s> ", rowprep->coefs[i], SCIPvarGetName(rowprep->vars[i]));
16062  }
16063 
16064  SCIPinfoMessage(scip, file, rowprep->sidetype == SCIP_SIDETYPE_LEFT ? ">= %.15g\n" : "<= %.15g\n", rowprep->side);
16065 }
16066 
16067 /** adds a term coef*var to a rowprep */
16069  SCIP* scip, /**< SCIP data structure */
16070  SCIP_ROWPREP* rowprep, /**< rowprep */
16071  SCIP_VAR* var, /**< variable to add */
16072  SCIP_Real coef /**< coefficient to add */
16073  )
16074 {
16075  assert(scip != NULL);
16076  assert(rowprep != NULL);
16077  assert(var != NULL);
16078 
16079  if( coef == 0.0 )
16080  return SCIP_OKAY;
16081 
16082  SCIP_CALL( SCIPensureRowprepSize(scip, rowprep, 1) );
16083  assert(rowprep->varssize > rowprep->nvars);
16084 
16085  rowprep->vars[rowprep->nvars] = var;
16086  rowprep->coefs[rowprep->nvars] = coef;
16087  ++rowprep->nvars;
16088 
16089  return SCIP_OKAY;
16090 }
16091 
16092 /** adds several terms coef*var to a rowprep */
16094  SCIP* scip, /**< SCIP data structure */
16095  SCIP_ROWPREP* rowprep, /**< rowprep */
16096  int nvars, /**< number of terms to add */
16097  SCIP_VAR** vars, /**< variables to add */
16098  SCIP_Real* coefs /**< coefficients to add */
16099  )
16100 {
16101  assert(scip != NULL);
16102  assert(rowprep != NULL);
16103  assert(vars != NULL || nvars == 0);
16104  assert(coefs != NULL || nvars == 0);
16105 
16106  if( nvars == 0 )
16107  return SCIP_OKAY;
16108 
16109  SCIP_CALL( SCIPensureRowprepSize(scip, rowprep, nvars) );
16110  assert(rowprep->varssize >= rowprep->nvars + nvars);
16111 
16112  /*lint --e{866} */
16113  BMScopyMemoryArray(rowprep->vars + rowprep->nvars, vars, nvars);
16114  BMScopyMemoryArray(rowprep->coefs + rowprep->nvars, coefs, nvars);
16115  rowprep->nvars += nvars;
16116 
16117  return SCIP_OKAY;
16118 }
16119 
16120 #ifdef NDEBUG
16121 #undef SCIPaddRowprepSide
16122 #undef SCIPaddRowprepConstant
16123 #endif
16124 
16125 /** adds constant value to side of rowprep */
16126 void SCIPaddRowprepSide(
16127  SCIP_ROWPREP* rowprep, /**< rowprep */
16128  SCIP_Real side /**< constant value to be added to side */
16129  )
16130 {
16131  assert(rowprep != NULL);
16132 
16133  rowprep->side += side;
16134 }
16135 
16136 /** adds constant term to rowprep
16137  *
16138  * Substracts constant from side.
16139  */
16141  SCIP_ROWPREP* rowprep, /**< rowprep */
16142  SCIP_Real constant /**< constant value to be added */
16143  )
16144 {
16145  assert(rowprep != NULL);
16146 
16147  SCIPaddRowprepSide(rowprep, -constant);
16148 }
16149 
16150 /** computes violation of cut in a given solution */
16152  SCIP* scip, /**< SCIP data structure */
16153  SCIP_ROWPREP* rowprep, /**< rowprep to be turned into a row */
16154  SCIP_SOL* sol /**< solution or NULL for LP solution */
16155  )
16156 {
16157  SCIP_Real activity;
16158  int i;
16159 
16160  activity = 0.0;
16161  for( i = 0; i < rowprep->nvars; ++i )
16162  {
16163  /* Loose variable have the best bound as LP solution value.
16164  * HOWEVER, they become column variables when they are added to a row (via SCIPaddVarsToRow below).
16165  * When this happens, their LP solution value changes to 0.0!
16166  * So when calculating the row activity for an LP solution, we treat loose variable as if they were already column variables.
16167  */
16168  if( sol != NULL || SCIPvarGetStatus(rowprep->vars[i]) != SCIP_VARSTATUS_LOOSE )
16169  activity += rowprep->coefs[i] * SCIPgetSolVal(scip, sol, rowprep->vars[i]);
16170  }
16171 
16172  if( rowprep->sidetype == SCIP_SIDETYPE_RIGHT )
16173  /* cut is activity <= side -> violation is activity - side, if positive */
16174  return MAX(activity - rowprep->side, 0.0);
16175  else
16176  /* cut is activity >= side -> violation is side - activity, if positive */
16177  return MAX(rowprep->side - activity, 0.0);
16178 }
16179 
16180 /** Merge terms that use same variable and eliminate zero coefficients.
16181  *
16182  * Terms are sorted by variable (@see SCIPvarComp) after return.
16183  */
16185  SCIP* scip, /**< SCIP data structure */
16186  SCIP_ROWPREP* rowprep /**< rowprep to be cleaned up */
16187  )
16188 {
16189  int i;
16190  int j;
16191 
16192  assert(scip != NULL);
16193  assert(rowprep != NULL);
16194 
16195  if( rowprep->nvars <= 1 )
16196  return;
16197 
16198  /* sort terms by variable index */
16199  SCIPsortPtrReal((void**)rowprep->vars, rowprep->coefs, SCIPvarComp, rowprep->nvars);
16200 
16201  /* merge terms with same variable, drop 0 coefficients */
16202  i = 0;
16203  j = 1;
16204  while( j < rowprep->nvars )
16205  {
16206  if( rowprep->vars[i] == rowprep->vars[j] )
16207  {
16208  /* merge term j into term i */
16209  rowprep->coefs[i] += rowprep->coefs[j];
16210  ++j;
16211  continue;
16212  }
16213 
16214  if( rowprep->coefs[i] == 0.0 )
16215  {
16216  /* move term j to position i */
16217  rowprep->coefs[i] = rowprep->coefs[j];
16218  rowprep->vars[i] = rowprep->vars[j];
16219  ++j;
16220  continue;
16221  }
16222 
16223  /* move term j to position i+1 and move on */
16224  if( j != i+1 )
16225  {
16226  rowprep->vars[i+1] = rowprep->vars[j];
16227  rowprep->coefs[i+1] = rowprep->coefs[j];
16228  }
16229  ++i;
16230  ++j;
16231  }
16232 
16233  /* remaining term can have coef zero -> forget about it */
16234  if( rowprep->coefs[i] == 0.0 )
16235  --i;
16236 
16237  /* i points to last term */
16238  rowprep->nvars = i+1;
16239 }
16240 
16241 /** sort cut terms by absolute value of coefficients, from largest to smallest */
16242 static
16244  SCIP* scip, /**< SCIP data structure */
16245  SCIP_ROWPREP* rowprep /**< rowprep to be sorted */
16246  )
16247 {
16248  int i;
16249 
16250  assert(scip != NULL);
16251  assert(rowprep != NULL);
16252 
16253  /* special treatment for cuts with few variables */
16254  switch( rowprep->nvars )
16255  {
16256  case 0:
16257  case 1:
16258  break;
16259 
16260  case 2:
16261  {
16262  if( REALABS(rowprep->coefs[0]) < REALABS(rowprep->coefs[1]) )
16263  {
16264  SCIP_Real tmp1;
16265  SCIP_VAR* tmp2;
16266 
16267  tmp1 = rowprep->coefs[0];
16268  rowprep->coefs[0] = rowprep->coefs[1];
16269  rowprep->coefs[1] = tmp1;
16270 
16271  tmp2 = rowprep->vars[0];
16272  rowprep->vars[0] = rowprep->vars[1];
16273  rowprep->vars[1] = tmp2;
16274  }
16275  break;
16276  }
16277 
16278  default :
16279  {
16280  SCIP_Real* abscoefs;
16281 
16282  SCIP_CALL( SCIPallocBufferArray(scip, &abscoefs, rowprep->nvars) );
16283  for( i = 0; i < rowprep->nvars; ++i )
16284  abscoefs[i] = REALABS(rowprep->coefs[i]);
16285  SCIPsortDownRealRealPtr(abscoefs, rowprep->coefs, (void**)rowprep->vars, rowprep->nvars);
16286  SCIPfreeBufferArray(scip, &abscoefs);
16287  }
16288  }
16289 
16290  /* forget about coefs that are exactly zero (unlikely to have some) */
16291  while( rowprep->nvars > 0 && rowprep->coefs[rowprep->nvars-1] == 0.0 )
16292  --rowprep->nvars;
16293 
16294  return SCIP_OKAY;
16295 }
16296 
16297 /** try to improve coef range by aggregating cut with variable bounds
16298  *
16299  * Assumes terms have been sorted by rowprepCleanupSortTerms().
16300  */
16301 static
16303  SCIP* scip, /**< SCIP data structure */
16304  SCIP_ROWPREP* rowprep, /**< rowprep to be improve */
16305  SCIP_SOL* sol, /**< solution that we try to cut off, or NULL for LP solution */
16306  SCIP_Real maxcoefrange /**< maximal allowed coefficients range */
16307  )
16308 {
16309  SCIP_VAR* var;
16310  SCIP_Real lb;
16311  SCIP_Real ub;
16312  SCIP_Real ref;
16313  SCIP_Real coef;
16314  SCIP_Real mincoef;
16315  SCIP_Real maxcoef;
16316  SCIP_Real loss[2];
16317  int maxcoefidx;
16318  int pos;
16319 
16320  maxcoefidx = 0;
16321  if( rowprep->nvars > 0 )
16322  {
16323  maxcoef = REALABS(rowprep->coefs[0]);
16324  mincoef = REALABS(rowprep->coefs[rowprep->nvars-1]);
16325  }
16326  else
16327  mincoef = maxcoef = 1.0;
16328 
16329  /* eliminate minimal or maximal coefs as long as coef range is too large
16330  * this is likely going to eliminate coefs that are within eps of 0.0
16331  * if not, then we do so after scaling (or should we enforce this here?)
16332  */
16333  while( maxcoef / mincoef > maxcoefrange )
16334  {
16335  SCIPdebugMsg(scip, "cut coefficients have very large range: mincoef = %g maxcoef = %g\n", mincoef, maxcoef);
16336 
16337  /* max/min can only be > 1 if there is more than one var
16338  * we need this below for updating the max/min coef after eliminating a term
16339  */
16340  assert(rowprep->nvars > 1);
16341 
16342  /* try to reduce coef range by aggregating with variable bounds
16343  * that is, eliminate a term like a*x from a*x + ... <= side by adding -a*x <= -a*lb(x)
16344  * with ref(x) the reference point we try to eliminate, this would weaken the cut by a*(lb(x)-ref(x))
16345  *
16346  * we consider eliminating either the term with maximal or the one with minimal coefficient,
16347  * taking the one that leads to the least weakening of the cut
16348  *
16349  * TODO (suggested by @bzfserra, see !496):
16350  * - Also one could think of not completely removing the coefficient but do an aggregation that makes the coefficient look better. For instance:
16351  * say you have $`a x + 0.1 y \leq r`$ and $`y`$ has only an upper bound, $`y \leq b`$,
16352  * then you can't really remove $`y`$. However, you could aggregate it with $`0.9 \cdot (y \leq b)`$ to get
16353  * $`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)
16354  */
16355 
16356  for( pos = 0; pos < 2; ++pos )
16357  {
16358  var = rowprep->vars[pos ? rowprep->nvars-1 : maxcoefidx];
16359  coef = rowprep->coefs[pos ? rowprep->nvars-1 : maxcoefidx];
16360  lb = SCIPvarGetLbLocal(var);
16361  ub = SCIPvarGetUbLocal(var);
16362  ref = SCIPgetSolVal(scip, sol, var);
16363  assert(coef != 0.0);
16364 
16365  /* make sure reference point is something reasonable within the bounds, preferable the value from the solution */
16366  if( SCIPisInfinity(scip, REALABS(ref)) )
16367  ref = 0.0;
16368  ref = MAX(lb, MIN(ub, ref));
16369 
16370  /* check whether we can eliminate coef*var from rowprep and how much we would loose w.r.t. ref(x) */
16371  if( ((coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT)) )
16372  {
16373  /* we would need to aggregate with -coef*var <= -coef*lb(x) */
16374  if( SCIPisInfinity(scip, -lb) )
16375  loss[pos] = SCIP_INVALID;
16376  else
16377  loss[pos] = REALABS(coef) * (ref - lb);
16378  }
16379  else
16380  {
16381  assert((coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT));
16382  /* we would need to aggregate with -coef*var >= -coef*ub(x) */
16383  if( SCIPisInfinity(scip, ub) )
16384  loss[pos] = SCIP_INVALID;
16385  else
16386  loss[pos] = REALABS(coef) * (ub - ref);
16387  }
16388  assert(loss[pos] >= 0.0); /* assuming SCIP_INVALID >= 0 */
16389 
16390  SCIPdebugMsg(scip, "aggregating %g*<%s> %c= ... with <%s>[%g] %c= %g looses %g\n",
16391  coef, SCIPvarGetName(var), rowprep->sidetype == SCIP_SIDETYPE_RIGHT ? '<' : '>',
16392  SCIPvarGetName(var), ref,
16393  ((coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT)) ? '>' : '<',
16394  ((coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT)) ? lb : ub, loss[pos]);
16395  }
16396 
16397  /*lint --e{777} */
16398  if( loss[0] == SCIP_INVALID && loss[1] == SCIP_INVALID )
16399  break; /* cannot eliminate coefficient */
16400 
16401  /* select position with smaller loss */
16402  pos = (loss[1] == SCIP_INVALID || loss[1] > loss[0]) ? 0 : 1;
16403 
16404  /* now do the actual elimination */
16405  var = rowprep->vars[pos ? rowprep->nvars-1 : maxcoefidx];
16406  coef = rowprep->coefs[pos ? rowprep->nvars-1 : maxcoefidx];
16407 
16408  /* eliminate coef*var from rowprep: increase side */
16409  if( ((coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT)) )
16410  {
16411  /* we aggregate with -coef*var <= -coef*lb(x) */
16412  assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
16413  SCIPaddRowprepConstant(rowprep, coef * SCIPvarGetLbLocal(var));
16414  rowprep->local |= SCIPisGT(scip, SCIPvarGetLbLocal(var), SCIPvarGetLbGlobal(var));
16415  }
16416  else
16417  {
16418  assert((coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT));
16419  /* we aggregate with -coef*var >= -coef*ub(x) */
16420  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
16421  SCIPaddRowprepConstant(rowprep, coef * SCIPvarGetUbLocal(var));
16422  rowprep->local |= SCIPisLT(scip, SCIPvarGetUbLocal(var), SCIPvarGetUbGlobal(var));
16423  }
16424 
16425  /* eliminate coef*var from rowprep: remove coef */
16426  if( pos == 0 )
16427  {
16428  /* set first term to zero */
16429  rowprep->coefs[maxcoefidx] = 0.0;
16430 
16431  /* update index */
16432  ++maxcoefidx;
16433 
16434  /* update maxcoef */
16435  maxcoef = REALABS(rowprep->coefs[maxcoefidx]);
16436  }
16437  else
16438  {
16439  /* forget last term */
16440  --rowprep->nvars;
16441 
16442  /* update mincoef */
16443  mincoef = REALABS(rowprep->coefs[rowprep->nvars-1]);
16444  }
16445  }
16446 
16447  /* if maximal coefs were removed, then there are now 0's in the beginning of the coefs array
16448  * -> move all remaining coefs and vars up front
16449  */
16450  if( maxcoefidx > 0 )
16451  {
16452  int i;
16453  for( i = maxcoefidx; i < rowprep->nvars; ++i )
16454  {
16455  rowprep->vars[i-maxcoefidx] = rowprep->vars[i];
16456  rowprep->coefs[i-maxcoefidx] = rowprep->coefs[i];
16457  }
16458  rowprep->nvars -= maxcoefidx;
16459  }
16460 }
16461 
16462 
16463 /** scales up rowprep if it seems useful */
16464 static
16466  SCIP* scip, /**< SCIP data structure */
16467  SCIP_ROWPREP* rowprep, /**< rowprep to be improve */
16468  SCIP_Real* viol, /**< violation of cut in sol (input and output) */
16469  SCIP_Real minviol /**< minimal violation we try to achieve */
16470  )
16471 {
16472  SCIP_Real scalefactor;
16473  SCIP_Real mincoef;
16474  SCIP_Real maxcoef;
16475 
16476  assert(scip != NULL);
16477  assert(rowprep != NULL);
16478  assert(viol != NULL);
16479 
16480  /* if violation is very small than better don't scale up */
16481  if( *viol < ROWPREP_SCALEUP_VIOLNONZERO )
16482  return;
16483 
16484  /* if violation is already above minviol, then nothing to do */
16485  if( *viol >= minviol )
16486  return;
16487 
16488  /* if violation is sufficiently positive (>10*eps), but has not reached minviol,
16489  * then consider scaling up to reach approx MINVIOLFACTOR*minviol
16490  */
16491  scalefactor = ROWPREP_SCALEUP_MINVIOLFACTOR * minviol / *viol;
16492 
16493  /* 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) */
16494  mincoef = rowprep->nvars > 0 ? REALABS(rowprep->coefs[rowprep->nvars-1]) : 1.0;
16495  maxcoef = rowprep->nvars > 0 ? REALABS(rowprep->coefs[0]) : 1.0;
16496  if( mincoef < ROWPREP_SCALEUP_MAXMINCOEF && scalefactor * maxcoef < ROWPREP_SCALEUP_MAXMAXCOEF && scalefactor * REALABS(rowprep->side) < ROWPREP_SCALEUP_MAXSIDE )
16497  {
16498  int scaleexp;
16499 
16500  /* SCIPinfoMessage(scip, NULL, "scale up by ~%g, viol=%g: ", scalefactor, myviol);
16501  SCIPprintRowprep(scip, rowprep, NULL); */
16502 
16503  /* SCIPscaleRowprep returns the actually applied scale factor */
16504  scaleexp = SCIPscaleRowprep(rowprep, scalefactor);
16505  *viol = ldexp(*viol, scaleexp);
16506 
16507  /* SCIPinfoMessage(scip, NULL, "scaled up by %g, viol=%g: ", ldexp(1.0, scaleexp), myviol);
16508  SCIPprintRowprep(scip, rowprep, NULL); */
16509  }
16510 }
16511 
16512 /** scales down rowprep if it improves coefs and keeps rowprep violated */
16513 static
16515  SCIP* scip, /**< SCIP data structure */
16516  SCIP_ROWPREP* rowprep, /**< rowprep to be improve */
16517  SCIP_Real* viol, /**< violation of cut in sol (input and output) */
16518  SCIP_Real minviol /**< minimal violation we try to keep */
16519  )
16520 {
16521  SCIP_Real scalefactor;
16522 
16523  /* if maxcoef < ROWPREP_SCALEDOWN_MINMAXCOEF (or no terms), then don't consider scaling down */
16524  if( rowprep->nvars == 0 || REALABS(rowprep->coefs[0]) < ROWPREP_SCALEDOWN_MINMAXCOEF )
16525  return;
16526 
16527  /* consider scaling down so that maxcoef ~ 10 */
16528  scalefactor = 10.0 / REALABS(rowprep->coefs[0]);
16529 
16530  /* if minimal violation would be lost by scaling down, then increase scalefactor such that minviol is still reached */
16531  if( *viol > minviol && scalefactor * *viol < minviol )
16532  {
16533  assert(minviol > 0.0); /* since viol >= 0, the if-condition should ensure that minviol > 0 */
16534  assert(*viol > 0.0); /* since minviol > 0, the if-condition ensures viol > 0 */
16535  scalefactor = ROWPREP_SCALEUP_MINVIOLFACTOR * minviol / *viol;
16536  }
16537 
16538  /* scale by approx. scalefactor if scaling down and minimal coef does not get too small
16539  * myviol < minviol (-> scalefactor > 1) or mincoef < feastol before scaling is possible, in which case we also don't scale down
16540  */
16541  if( scalefactor < 1.0 && scalefactor * REALABS(rowprep->coefs[rowprep->nvars-1]) > ROWPREP_SCALEDOWN_MINCOEF )
16542  {
16543  int scaleexp;
16544 
16545  /* SCIPinfoMessage(scip, NULL, "scale down by ~%g, viol=%g: ", scalefactor, myviol);
16546  SCIPprintRowprep(scip, rowprep, NULL); */
16547 
16548  scaleexp = SCIPscaleRowprep(rowprep, scalefactor);
16549  *viol = ldexp(*viol, scaleexp);
16550 
16551  /* SCIPinfoMessage(scip, NULL, "scaled down by %g, viol=%g: ", ldexp(1.0, scaleexp), myviol);
16552  SCIPprintRowprep(scip, rowprep, NULL); */
16553  }
16554 }
16555 
16556 /** rounds almost integral coefs to integrals, thereby trying to relax the cut */
16557 static
16559  SCIP* scip, /**< SCIP data structure */
16560  SCIP_ROWPREP* rowprep, /**< rowprep to be improve */
16561  SCIP_Real* viol /**< violation of cut in sol (input), set to SCIP_INVALID if some coef changed */
16562  )
16563 {
16564  SCIP_Real coef;
16565  SCIP_Real roundcoef;
16566  int i;
16567 
16568  assert(scip != NULL);
16569  assert(rowprep != NULL);
16570  assert(viol != NULL);
16571 
16572  /* Coefficients smaller than epsilon are rounded to 0.0 when added to row and
16573  * coefficients very close to integral values are rounded to integers when added to LP.
16574  * Both cases can be problematic if variable value is very large (bad numerics).
16575  * Thus, we anticipate by rounding coef here, but also modify constant so that cut is still valid (if possible),
16576  * i.e., bound coef[i]*x by round(coef[i])*x + (coef[i]-round(coef[i])) * bound(x).
16577  * Or in other words, we aggregate with the variable bound.
16578  *
16579  * If the required bound of x is not finite, then only round coef (introduces an error).
16580  * @TODO If only the opposite bound is available, then one could move the coefficient
16581  * away from the closest integer so that the SCIP_ROW won't try to round it.
16582  */
16583  for( i = 0; i < rowprep->nvars; ++i )
16584  {
16585  coef = rowprep->coefs[i];
16586  roundcoef = SCIPround(scip, coef);
16587  if( coef != roundcoef && SCIPisEQ(scip, coef, roundcoef) ) /*lint !e777*/
16588  {
16589  SCIP_Real xbnd;
16590  SCIP_VAR* var;
16591 
16592  var = rowprep->vars[i];
16593  if( rowprep->sidetype == SCIP_SIDETYPE_RIGHT )
16594  if( rowprep->local )
16595  xbnd = coef > roundcoef ? SCIPvarGetLbLocal(var) : SCIPvarGetUbLocal(var);
16596  else
16597  xbnd = coef > roundcoef ? SCIPvarGetLbGlobal(var) : SCIPvarGetUbGlobal(var);
16598  else
16599  if( rowprep->local )
16600  xbnd = coef > roundcoef ? SCIPvarGetUbLocal(var) : SCIPvarGetLbLocal(var);
16601  else
16602  xbnd = coef > roundcoef ? SCIPvarGetUbGlobal(var) : SCIPvarGetLbGlobal(var);
16603 
16604  if( !SCIPisInfinity(scip, REALABS(xbnd)) )
16605  {
16606  /* if there is a bound, then relax row side so rounding coef will not introduce an error */
16607  SCIPdebugMsg(scip, "var <%s> [%g,%g] has almost integral coef %.20g, round coefficient to %g and add constant %g\n",
16608  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), coef, roundcoef, (coef-roundcoef) * xbnd);
16609  SCIPaddRowprepConstant(rowprep, (coef-roundcoef) * xbnd);
16610  }
16611  else
16612  {
16613  /* if there is no bound, then we make the coef integral, too, even though this will introduce an error
16614  * however, SCIP_ROW would do this anyway, but doing this here might eliminate some epsilon coefs (so they don't determine mincoef below)
16615  * and helps to get a more accurate row violation value
16616  */
16617  SCIPdebugMsg(scip, "var <%s> [%g,%g] has almost integral coef %.20g, round coefficient to %g without relaxing side (!)\n",
16618  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), coef, roundcoef);
16619  }
16620  rowprep->coefs[i] = roundcoef;
16621  *viol = SCIP_INVALID;
16622  }
16623  }
16624 
16625  /* forget about coefs that became exactly zero by the above step */
16626  while( rowprep->nvars > 0 && rowprep->coefs[rowprep->nvars-1] == 0.0 )
16627  --rowprep->nvars;
16628 }
16629 
16630 /** relaxes almost zero side */
16631 static
16632 void rowprepCleanupSide(
16633  SCIP* scip, /**< SCIP data structure */
16634  SCIP_ROWPREP* rowprep, /**< rowprep to be improve */
16635  SCIP_Real* viol /**< violation of cut in sol (input), set to SCIP_INVALID if some coef changed */
16636  )
16637 {
16638  /* SCIP_ROW handling will replace a side close to 0 by 0.0, even if that makes the row more restrictive
16639  * we thus relax the side here so that it will either be 0 now or will not be rounded to 0 later
16640  */
16641  if( !SCIPisZero(scip, rowprep->side) )
16642  return;
16643 
16644  if( rowprep->side > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT )
16645  rowprep->side = 1.1*SCIPepsilon(scip);
16646  else if( rowprep->side < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT )
16647  rowprep->side = -1.1*SCIPepsilon(scip);
16648  else
16649  rowprep->side = 0.0;
16650 
16651  *viol = SCIP_INVALID;
16652 }
16653 
16654 /* Cleans up and attempts to improve rowprep
16655  *
16656  * Drops small or large coefficients if coefrange is too large, if this can be done by relaxing the cut.
16657  * Scales coefficients and side up to reach minimal violation, if possible.
16658  * Scaling is omitted if violation is very small (ROWPREP_SCALEUP_VIOLNONZERO) or
16659  * maximal coefficient would become huge (ROWPREP_SCALEUP_MAXMAXCOEF).
16660  * Scales coefficients and side down if they are large and if the minimal violation is still reached.
16661  * Rounds coefficients close to integral values to integrals, if this can be done by relaxing the cut.
16662  * Rounds side within epsilon of 0 to 0.0 or +/-1.1*epsilon, whichever relaxes the cut least.
16663  *
16664  * After return, the terms in the rowprep will be sorted by absolute value of coefficient, in decreasing order.
16665  */
16667  SCIP* scip, /**< SCIP data structure */
16668  SCIP_ROWPREP* rowprep, /**< rowprep to be cleaned */
16669  SCIP_SOL* sol, /**< solution that we try to cut off, or NULL for LP solution */
16670  SCIP_Real maxcoefrange, /**< maximal allowed coefficients range */
16671  SCIP_Real minviol, /**< minimal absolute violation the row should achieve (w.r.t. sol) */
16672  SCIP_Real* coefrange, /**< buffer to store coefrange of cleaned up cut, or NULL if not of interest */
16673  SCIP_Real* viol /**< buffer to store absolute violation of cleaned up cut in sol, or NULL if not of interest */
16674  )
16675 {
16676  SCIP_Real myviol;
16677 #ifdef SCIP_DEBUG
16678  SCIP_Real mincoef = 1.0;
16679  SCIP_Real maxcoef = 1.0;
16680 #endif
16681 
16682  assert(maxcoefrange > 1.0); /* not much interesting otherwise */
16683 
16684  /* sort term by absolute value of coef. */
16685  SCIP_CALL( rowprepCleanupSortTerms(scip, rowprep) );
16686 
16687 #ifdef SCIP_DEBUG
16688  if( rowprep->nvars > 0 )
16689  {
16690  maxcoef = REALABS(rowprep->coefs[0]);
16691  mincoef = REALABS(rowprep->coefs[rowprep->nvars-1]);
16692  }
16693 
16694  SCIPinfoMessage(scip, NULL, "starting cleanup, coefrange %g: ", maxcoef/mincoef);
16695  SCIPprintRowprep(scip, rowprep, NULL);
16696 #endif
16697 
16698  /* improve coefficient range by aggregating out variables */
16699  rowprepCleanupImproveCoefrange(scip, rowprep, sol, maxcoefrange);
16700 
16701  /* get current violation in sol */
16702  myviol = SCIPgetRowprepViolation(scip, rowprep, sol);
16703  assert(myviol >= 0.0);
16704 
16705 #ifdef SCIP_DEBUG
16706  if( rowprep->nvars > 0 )
16707  {
16708  maxcoef = REALABS(rowprep->coefs[0]);
16709  mincoef = REALABS(rowprep->coefs[rowprep->nvars-1]);
16710  }
16711 
16712  SCIPinfoMessage(scip, NULL, "improved coefrange to %g, viol %g: ", maxcoef / mincoef, myviol);
16713  SCIPprintRowprep(scip, rowprep, NULL);
16714 #endif
16715 
16716  /* if there is interest in achieving some minimal violation, then possibly scale up to increase violation, updates myviol */
16717  if( minviol > 0.0 )
16718  {
16719  /* first, try to achieve scip's minefficacy (typically 1e-4) */
16720  if( SCIPgetSepaMinEfficacy(scip) > minviol )
16721  rowprepCleanupScaleup(scip, rowprep, &myviol, SCIPgetSepaMinEfficacy(scip));
16722  /* in case scip minefficacy could not be reached or was smaller than minviol, try with the given minviol */
16723  rowprepCleanupScaleup(scip, rowprep, &myviol, minviol);
16724  }
16725 
16726  /* scale down to improve numerics, updates myviol */
16727  rowprepCleanupScaledown(scip, rowprep, &myviol, MAX(SCIPgetSepaMinEfficacy(scip), minviol)); /*lint !e666*/
16728 
16729 #ifdef SCIP_DEBUG
16730  SCIPinfoMessage(scip, NULL, "applied scaling, viol %g: ", myviol);
16731  SCIPprintRowprep(scip, rowprep, NULL);
16732 #endif
16733 
16734  /* turn almost-integral coefs to integral values, may set myviol to SCIP_INVALID */
16735  rowprepCleanupIntegralCoefs(scip, rowprep, &myviol);
16736 
16737  /* relax almost-zero side, may set myviol to SCIP_INVALID */
16738  rowprepCleanupSide(scip, rowprep, &myviol);
16739 
16740 #ifdef SCIP_DEBUG
16741  SCIPinfoMessage(scip, NULL, "adjusted almost-integral coefs and sides, viol %g: ", myviol);
16742  SCIPprintRowprep(scip, rowprep, NULL);
16743 #endif
16744 
16745  /* compute final coefrange, if requested by caller */
16746  if( coefrange != NULL )
16747  {
16748  if( rowprep->nvars > 0 )
16749  *coefrange = REALABS(rowprep->coefs[0]) / REALABS(rowprep->coefs[rowprep->nvars-1]);
16750  else
16751  *coefrange = 1.0;
16752  }
16753 
16754  /* If we updated myviol correctly, then it should coincide with freshly computed violation.
16755  * I leave this assert off for now, since getting the tolerance in the EQ correctly is not trivial. We recompute viol below anyway.
16756  */
16757  /* assert(myviol == SCIP_INVALID || SCIPisEQ(scip, myviol, SCIPgetRowprepViolation(scip, rowprep, sol))); */
16758 
16759  /* compute final violation, if requested by caller */
16760  if( viol != NULL ) /*lint --e{777} */
16761  *viol = myviol == SCIP_INVALID ? SCIPgetRowprepViolation(scip, rowprep, sol) : myviol;
16762 
16763  return SCIP_OKAY;
16764 }
16765 
16766 /** scales a rowprep
16767  *
16768  * @return Exponent of actually applied scaling factor, if written as 2^x.
16769  */
16770 int SCIPscaleRowprep(
16771  SCIP_ROWPREP* rowprep, /**< rowprep to be scaled */
16772  SCIP_Real factor /**< suggested scale factor */
16773  )
16774 {
16775  double v;
16776  int expon;
16777  int i;
16778 
16779  assert(rowprep != NULL);
16780  assert(factor > 0.0);
16781 
16782  /* write factor as v*2^expon with v in [0.5,1) */
16783  v = frexp(factor, &expon);
16784  /* adjust to v'*2^expon with v' in (0.5,1] by v'=v if v > 0.5, v'=1 if v=0.5 */
16785  if( v == 0.5 )
16786  --expon;
16787 
16788  /* multiply each coefficient by 2^expon */
16789  for( i = 0; i < rowprep->nvars; ++i )
16790  rowprep->coefs[i] = ldexp(rowprep->coefs[i], expon);
16791 
16792  /* multiply side by 2^expon */
16793  rowprep->side = ldexp(rowprep->side, expon);
16794 
16795  return expon;
16796 }
16797 
16798 /** generates a SCIP_ROW from a rowprep */
16800  SCIP* scip, /**< SCIP data structure */
16801  SCIP_ROW** row, /**< buffer to store pointer to new row */
16802  SCIP_ROWPREP* rowprep, /**< rowprep to be turned into a row */
16803  SCIP_CONSHDLR* conshdlr /**< constraint handler */
16804  )
16805 {
16806  assert(scip != NULL);
16807  assert(row != NULL);
16808  assert(rowprep != NULL);
16809 
16810  SCIP_CALL( SCIPcreateEmptyRowCons(scip, row, conshdlr, rowprep->name,
16811  rowprep->sidetype == SCIP_SIDETYPE_LEFT ? rowprep->side : -SCIPinfinity(scip),
16812  rowprep->sidetype == SCIP_SIDETYPE_RIGHT ? rowprep->side : SCIPinfinity(scip),
16813  rowprep->local && (SCIPgetDepth(scip) > 0), FALSE, TRUE) );
16814 
16815  SCIP_CALL( SCIPaddVarsToRow(scip, *row, rowprep->nvars, rowprep->vars, rowprep->coefs) );
16816 
16817  return SCIP_OKAY;
16818 }
16819 
16820 /** generates a SCIP_ROW from a rowprep */
16822  SCIP* scip, /**< SCIP data structure */
16823  SCIP_ROW** row, /**< buffer to store pointer to new row */
16824  SCIP_ROWPREP* rowprep, /**< rowprep to be turned into a row */
16825  SCIP_SEPA* sepa /**< separator */
16826  )
16827 {
16828  assert(scip != NULL);
16829  assert(row != NULL);
16830  assert(rowprep != NULL);
16831 
16832  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, row, sepa, rowprep->name,
16833  rowprep->sidetype == SCIP_SIDETYPE_LEFT ? rowprep->side : -SCIPinfinity(scip),
16834  rowprep->sidetype == SCIP_SIDETYPE_RIGHT ? rowprep->side : SCIPinfinity(scip),
16835  rowprep->local && (SCIPgetDepth(scip) > 0), FALSE, TRUE) );
16836 
16837  SCIP_CALL( SCIPaddVarsToRow(scip, *row, rowprep->nvars, rowprep->vars, rowprep->coefs) );
16838 
16839  return SCIP_OKAY;
16840 }
SCIP_RETCODE SCIPaddLinearCoefsToNlRow(SCIP *scip, SCIP_NLROW *nlrow, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip_nlp.c:1465
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:52
static void rowprepCleanupImproveCoefrange(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Real maxcoefrange)
SCIP_VAR ** SCIPgetLinearVarsQuadratic(SCIP *scip, SCIP_CONS *cons)
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:116
SCIP_RETCODE SCIPchgSquareCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_RETCODE SCIPincludeConshdlrQuadratic(SCIP *scip)
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
void SCIPintervalDivScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
int SCIPgetNIntVars(SCIP *scip)
Definition: scip_prob.c:2134
SCIP_RETCODE SCIPchgBilinCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Real coef)
static SCIP_Bool conshdlrdataHasUpgrade(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), const char *conshdlrname)
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisIpoptAvailableIpopt(void)
#define ROWPREP_SCALEUP_VIOLNONZERO
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:105
static SCIP_RETCODE mergeAndCleanLinearVars(SCIP *scip, SCIP_CONS *cons)
static SCIP_Bool generateCutLTIgenMulCoeff(SCIP *scip, SCIP_Real x1, SCIP_Real y1_, SCIP_Real x2, SCIP_Real y2, SCIP_Bool whichuse, SCIP_Real *cx, SCIP_Real *cy, SCIP_Real *cw)
SCIP_Real SCIPvarGetWorstBoundLocal(SCIP_VAR *var)
Definition: var.c:17442
void SCIPintervalMulSup(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSDATA **consdata, SCIP_Real lhs, SCIP_Real rhs, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadvars, SCIP_QUADVARTERM *quadvarterms, int nbilinterms, SCIP_BILINTERM *bilinterms, SCIP_Bool capturevars)
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip_cons.c:640
static volatile int nterms
Definition: interrupt.c:37
void * SCIPhashmapEntryGetImage(SCIP_HASHMAPENTRY *entry)
Definition: misc.c:3172
static SCIP_RETCODE propagateBoundsQuadVar(SCIP *scip, SCIP_CONS *cons, SCIP_Real intervalinfty, SCIP_VAR *var, SCIP_Real a, SCIP_INTERVAL b, SCIP_INTERVAL rhs, SCIP_RESULT *result, int *nchgbds)
static SCIP_RETCODE freeAllBilinearTerms(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **conss, int nconss)
SCIP_EXPRGRAPH * SCIPgetExprgraphNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr)
static SCIP_DECL_CONSENFOPS(consEnfopsQuadratic)
SCIP_RETCODE SCIPincludeNonlinconsUpgrade(SCIP *scip, SCIP_DECL_NONLINCONSUPGD((*nonlinconsupgd)), SCIP_DECL_EXPRGRAPHNODEREFORM((*nodereform)), int priority, SCIP_Bool active, const char *conshdlrname)
#define NULL
Definition: def.h:239
#define ROWPREP_SCALEDOWN_MINCOEF
static void consdataMoveLinearVar(SCIP_CONSDATA *consdata, int oldpos, int newpos)
SCIP_Real SCIPfeastol(SCIP *scip)
SCIP_Bool SCIPconsIsEnabled(SCIP_CONS *cons)
Definition: cons.c:8173
SCIP_Bool SCIPintervalIsEmpty(SCIP_Real infinity, SCIP_INTERVAL operand)
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:99
static SCIP_RETCODE consdataSortBilinTerms(SCIP *scip, SCIP_CONSDATA *consdata)
primal heuristic that tries a given solution
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition: scip_nlp.c:284
SCIP_RETCODE SCIPaddQuadVarQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real lincoef, SCIP_Real sqrcoef)
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5120
SCIP_VAR * var2
static void rowprepCleanupScaleup(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_Real *viol, SCIP_Real minviol)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
public methods for SCIP parameter handling
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3176
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition: scip_tree.c:158
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:412
#define MAXDNOM
#define SCIP_EVENTTYPE_VARFIXED
Definition: type_event.h:58
#define GAUGESCALE
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8335
SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition: var.c:17135
SCIP_RETCODE SCIPincSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real incval)
Definition: scip_sol.c:1367
static SCIP_RETCODE separatePoint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_Real minefficacy, SCIP_Bool inenforcement, SCIP_RESULT *result, SCIP_Real *bestefficacy)
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip_cons.c:663
public methods for branch and bound tree
#define CONSHDLR_PRESOLTIMING
static SCIP_DECL_CONSSEPASOL(consSepasolQuadratic)
void SCIPaddConstantQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_Real constant)
static SCIP_RETCODE consdataEnsureQuadVarTermsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num)
static SCIP_DECL_CONSINITSOL(consInitsolQuadratic)
Constraint handler for variable bound constraints .
SCIP_Bool SCIPisRelEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int SCIPgetNAllBilinearTermsQuadratic(SCIP *scip)
SCIP_RETCODE SCIPaddSquareCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
static SCIP_RETCODE propagateBoundsBilinearTerm(SCIP *scip, SCIP_CONS *cons, SCIP_Real intervalinfty, SCIP_VAR *x, SCIP_Real xsqrcoef, SCIP_Real xlincoef, SCIP_VAR *y, SCIP_Real ysqrcoef, SCIP_Real ylincoef, SCIP_Real bilincoef, SCIP_INTERVAL rhs, SCIP_RESULT *result, int *nchgbds)
public methods for memory management
#define ROWPREP_SCALEDOWN_MINMAXCOEF
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:422
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:954
SCIP_RETCODE SCIPchgRhsQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_Real rhs)
int SCIPexprgraphGetNodeNChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12967
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition: scip_mem.h:132
SCIP_Real SCIPintervalNegateReal(SCIP_Real x)
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17343
SCIP_RETCODE SCIPincludeQuadconsUpgrade(SCIP *scip, SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), int priority, SCIP_Bool active, const char *conshdlrname)
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip_cons.c:893
static SCIP_DECL_SORTINDCOMP(quadVarTermComp)
#define SCIP_MAXSTRLEN
Definition: def.h:260
static SCIP_RETCODE replaceQuadVarTermPos(SCIP *scip, SCIP_CONS *cons, int pos, SCIP_VAR *var, SCIP_Real coef, SCIP_Real offset)
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3233
#define SCIP_DECL_CONSINITPRE(x)
Definition: type_cons.h:141
#define CONSHDLR_DELAYPROP
SCIP_Bool SCIPvarIsInitial(SCIP_VAR *var)
Definition: var.c:16930
SCIP_VAR * var1
void SCIPsortPtrPtrReal(void **ptrarray1, void **ptrarray2, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPaddRowprepTerms(SCIP *scip, SCIP_ROWPREP *rowprep, int nvars, SCIP_VAR **vars, SCIP_Real *coefs)
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip_cons.c:385
#define SCIPallocClearBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:103
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1826
static SCIP_RETCODE getImpliedBounds(SCIP *scip, SCIP_VAR *x, SCIP_Bool xval, SCIP_VAR *y, SCIP_INTERVAL *resultant)
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2895
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:210
SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
Definition: var.c:17123
int SCIProwGetNNonz(SCIP_ROW *row)
Definition: lp.c:16790
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 SQR(x)
Definition: def.h:191
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisSumRelEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define INTERIOR_EPS
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17399
static SCIP_DECL_CONSSEPALP(consSepalpQuadratic)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
internal methods for NLPI solver interfaces
SCIP_RETCODE SCIPaddRowprepTerm(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_VAR *var, SCIP_Real coef)
public solving methods
static SCIP_RETCODE lockLinearVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_Bool local
SCIP_Bool SCIPconsIsAdded(SCIP_CONS *cons)
Definition: cons.c:8505
SCIP_RETCODE SCIPnlpiCreateProblem(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM **problem, const char *name)
Definition: nlpi.c:211
static SCIP_RETCODE catchVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons)
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip_event.c:172
SCIP_NLPSOLSTAT SCIPgetNLPSolstat(SCIP *scip)
Definition: scip_nlp.c:667
const char * SCIProwGetName(SCIP_ROW *row)
Definition: lp.c:16928
SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
Definition: scip_var.c:1442
static void consdataUpdateLinearActivityUbChange(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real coef, SCIP_Real oldbnd, SCIP_Real newbnd)
static SCIP_RETCODE dropLinearVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons, int linvarpos)
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1251
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:16909
static SCIP_RETCODE addQuadVarTerm(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real lincoef, SCIP_Real sqrcoef)
#define RESTRICT
Definition: def.h:251
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPnlpiGetSolution(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem, SCIP_Real **primalvalues, SCIP_Real **consdualvalues, SCIP_Real **varlbdualvalues, SCIP_Real **varubdualvalues, SCIP_Real *objval)
Definition: nlpi.c:537
SCIP_Real SCIPvarGetBestBoundLocal(SCIP_VAR *var)
Definition: var.c:17429
SCIP_Real SCIPdualfeastol(SCIP *scip)
static SCIP_DECL_CONSENABLE(consEnableQuadratic)
static SCIP_RETCODE generateCut(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Real *ref, SCIP_SOL *sol, SCIP_SIDETYPE violside, SCIP_ROW **row, SCIP_Real *efficacy, SCIP_Bool checkcurvmultivar, SCIP_Real minefficacy)
static void consdataUpdateLinearActivityLbChange(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real coef, SCIP_Real oldbnd, SCIP_Real newbnd)
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_DECL_NONLINCONSUPGD(nonlinconsUpgdQuadratic)
#define CONSHDLR_MAXPREROUNDS
SCIP_RETCODE SCIPchgLinearCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
void SCIPintervalSetRoundingMode(SCIP_ROUNDMODE roundmode)
SCIP_SIDETYPE sidetype
static SCIP_DECL_CONSEXITPRE(consExitpreQuadratic)
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4563
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:16869
#define FALSE
Definition: def.h:65
SCIP_Real SCIPadjustedVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real ub)
Definition: scip_var.c:4582
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:2793
#define INITLPMAXVARVAL
static SCIP_RETCODE evaluateGauge(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *refsol, SCIP_Real *gaugeval, SCIP_Bool *success)
static SCIP_RETCODE storeAllBilinearTerms(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **conss, int nconss)
static SCIP_RETCODE presolveSolve(SCIP *scip, SCIP_CONS *cons, SCIP_RESULT *result, SCIP_Bool *redundant, int *naggrvars)
SCIP_RETCODE SCIPnlpiAddConstraints(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem, int nconss, const SCIP_Real *lhss, const SCIP_Real *rhss, const int *nlininds, int *const *lininds, SCIP_Real *const *linvals, const int *nquadelems, SCIP_QUADELEM *const *quadelems, int *const *exprvaridxs, SCIP_EXPRTREE *const *exprtrees, const char **names)
Definition: nlpi.c:268
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:10325
int SCIPgetSubscipDepth(SCIP *scip)
Definition: scip_copy.c:2354
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:243
SCIP_Real * SCIPgetLinearCoefsNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPinfinity(SCIP *scip)
#define CONSHDLR_SEPAPRIORITY
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10017
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
#define TRUE
Definition: def.h:64
#define SCIPdebug(x)
Definition: pub_message.h:74
SCIP_RETCODE SCIPunmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:2056
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
SCIP_RETCODE SCIPsolveNLP(SCIP *scip)
Definition: scip_nlp.c:644
static SCIP_RETCODE generateCutConvex(SCIP *scip, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_Real *ref, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8355
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition: type_timing.h:45
static void consdataFindUnlockedLinearVar(SCIP *scip, SCIP_CONSDATA *consdata)
static void checkCurvatureEasy(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *determined, SCIP_Bool checkmultivariate)
void SCIPintervalSetBounds(SCIP_INTERVAL *resultant, SCIP_Real inf, SCIP_Real sup)
SCIP_Real SCIPgetRhsNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8385
SCIP_RETCODE SCIPcreateConsBasicQuadratic2(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadvarterms, SCIP_QUADVARTERM *quadvarterms, int nbilinterms, SCIP_BILINTERM *bilinterms, SCIP_Real lhs, SCIP_Real rhs)
void SCIPsortDownIntInt(int *intarray1, int *intarray2, int len)
public methods for problem variables
static GRAPHNODE ** active
void SCIPswapReals(SCIP_Real *value1, SCIP_Real *value2)
Definition: misc.c:9632
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5236
static SCIP_RETCODE removeBilinearTermsPos(SCIP *scip, SCIP_CONS *cons, int nterms, int *termposs)
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:114
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)
#define SCIPdebugMessage
Definition: pub_message.h:77
SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
Definition: scip_cons.c:297
SCIP_Real SCIPselectSimpleValue(SCIP_Real lb, SCIP_Real ub, SCIP_Longint maxdnom)
Definition: misc.c:9132
static SCIP_RETCODE presolveTryAddAND(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *naddconss)
SCIP_EVENTHDLR * SCIPfindEventhdlr(SCIP *scip, const char *name)
Definition: scip_event.c:302
Constraint handler for AND constraints, .
SCIP_RETCODE SCIPwriteVarsPolynomial(SCIP *scip, FILE *file, SCIP_VAR ***monomialvars, SCIP_Real **monomialexps, SCIP_Real *monomialcoefs, int *monomialnvars, int nmonomials, SCIP_Bool type)
Definition: scip_var.c:394
static SCIP_RETCODE mergeAndCleanBilinearTerms(SCIP *scip, SCIP_CONS *cons)
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2931
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE chgLinearCoefPos(SCIP *scip, SCIP_CONS *cons, int pos, SCIP_Real newcoef)
static SCIP_RETCODE propagateBoundsCons(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_RESULT *result, int *nchgbds, SCIP_Bool *redundant)
SCIP_RETCODE SCIPcreateLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip_sol.c:419
static SCIP_DECL_CONSENFOLP(consEnfolpQuadratic)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:142
SCIP_Real SCIPadjustedVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real lb)
Definition: scip_var.c:4550
SCIP_Bool SCIPvarIsRemovable(SCIP_VAR *var)
Definition: var.c:16940
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:97
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:83
public methods for SCIP variables
static SCIP_RETCODE dropQuadVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons, int quadvarpos)
SCIP_RETCODE SCIPcreateConsBasicQuadratic(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadterms, SCIP_VAR **quadvars1, SCIP_VAR **quadvars2, SCIP_Real *quadcoefs, SCIP_Real lhs, SCIP_Real rhs)
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8345
#define SCIP_EVENTTYPE_BOUNDCHANGED
Definition: type_event.h:108
void SCIPcomputeBilinEnvelope2(SCIP *scip, SCIP_Real bilincoef, SCIP_Real lbx, SCIP_Real ubx, SCIP_Real refpointx, SCIP_Real lby, SCIP_Real uby, SCIP_Real refpointy, SCIP_Bool overestimate, SCIP_Real xcoef1, SCIP_Real ycoef1, SCIP_Real constant1, SCIP_Real xcoef2, SCIP_Real ycoef2, SCIP_Real constant2, SCIP_Real *RESTRICT lincoefx, SCIP_Real *RESTRICT lincoefy, SCIP_Real *RESTRICT linconstant, SCIP_Bool *RESTRICT success)
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip_cons.c:686
static SCIP_RETCODE registerBranchingCandidatesViolation(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, int *nnotify)
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip_message.c:203
#define SCIPdebugMsgPrint
Definition: scip_message.h:89
#define ROWPREP_SCALEUP_MAXMAXCOEF
#define SCIPdebugMsg
Definition: scip_message.h:88
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:155
static void consdataUpdateLinearActivity(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real intervalinfty)
public methods for separator plugins
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip_cons.c:870
SCIP_Real SCIPgetLhsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_VAR ** x
Definition: circlepacking.c:54
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8137
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:279
int SCIPgetNContVars(SCIP *scip)
Definition: scip_prob.c:2224
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:1011
SCIP_Real SCIPepsilon(SCIP *scip)
static SCIP_RETCODE lockQuadraticVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
#define SCIP_PRESOLTIMING_FAST
Definition: type_timing.h:43
SCIP_RETCODE SCIPaddLinearVarQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
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)
public methods for numerical tolerances
static SCIP_RETCODE unlockQuadraticVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
SCIP_Bool SCIPisRelGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int SCIPgetNQuadVarTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPconsIsOriginal(SCIP_CONS *cons)
Definition: cons.c:8375
int SCIPnlrowGetNQuadElems(SCIP_NLROW *nlrow)
Definition: nlp.c:3323
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:104
public methods for querying solving statistics
SCIP_Bool SCIPisRelLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE generateCutNonConvex(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_Real *ref, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
const char * SCIPgetProbName(SCIP *scip)
Definition: scip_prob.c:1123
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3025
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition: scip_var.c:4199
static SCIP_RETCODE registerBranchingCandidatesGap(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, int *nnotify)
SCIP_RETCODE SCIPaddBilinearIneqQuadratic(SCIP *scip, SCIP_VAR *x, SCIP_VAR *y, int idx, SCIP_Real xcoef, SCIP_Real ycoef, SCIP_Real constant, SCIP_Bool *success)
int SCIPgetNBilinTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPnlpiSolve(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem)
Definition: nlpi.c:497
public methods for the branch-and-bound tree
SCIP_RETCODE SCIPheurPassSolTrySol(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *sol)
Definition: heur_trysol.c:242
SCIP_EXPROP SCIPexprgraphGetNodeOperator(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13027
static SCIP_RETCODE consdataSortQuadVarTerms(SCIP *scip, SCIP_CONSDATA *consdata)
#define CONSHDLR_EAGERFREQ
SCIP_RETCODE SCIPnlpiAddVars(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem, int nvars, const SCIP_Real *lbs, const SCIP_Real *ubs, const char **varnames)
Definition: nlpi.c:250
SCIP_RETCODE SCIPchgVarType(SCIP *scip, SCIP_VAR *var, SCIP_VARTYPE vartype, SCIP_Bool *infeasible)
Definition: scip_var.c:8072
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17353
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)
SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITSOL((*consinitsol)))
Definition: scip_cons.c:506
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip_mem.h:111
SCIP_Bool SCIPisConcaveQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Real coef
Definition: type_expr.h:104
public methods for managing constraints
#define SCIP_EVENTTYPE_SOLFOUND
Definition: type_event.h:127
void SCIPfreeRowprep(SCIP *scip, SCIP_ROWPREP **rowprep)
SCIP_Real inf
Definition: intervalarith.h:39
SCIP_RETCODE SCIPchgLhsQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_Real lhs)
static SCIP_RETCODE checkCurvature(SCIP *scip, SCIP_CONS *cons, SCIP_Bool checkmultivariate)
SCIP_Real SCIPeventGetNewbound(SCIP_EVENT *event)
Definition: event.c:1198
SCIP_RETCODE SCIPcreateSolCopy(SCIP *scip, SCIP_SOL **sol, SCIP_SOL *sourcesol)
Definition: scip_sol.c:667
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
Definition: scip_general.c:648
SCIP_Bool SCIPconsIsLocked(SCIP_CONS *cons)
Definition: cons.c:8415
SCIP_VAR ** SCIPnlrowGetQuadVars(SCIP_NLROW *nlrow)
Definition: nlp.c:3286
static SCIP_RETCODE presolveTryAddLinearReform(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *naddconss)
static SCIP_RETCODE generateCutFactorableDo(SCIP *scip, SCIP_CONS *cons, SCIP_Real *ref, SCIP_Real multleft, SCIP_Real *coefleft, SCIP_Real multright, SCIP_Real *coefright, SCIP_Real rightminactivity, SCIP_Real rightmaxactivity, SCIP_Real rhs, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
void SCIPmarkRowNotRemovableLocal(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1769
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip_cons.c:409
SCIP_RETCODE SCIPaddLinearConsToNlpHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_Bool addcombconss, SCIP_Bool addcontconss)
Definition: heur_subnlp.c:2417
static SCIP_DECL_CONSEXIT(consExitQuadratic)
const char * SCIPheurGetName(SCIP_HEUR *heur)
Definition: heur.c:1254
struct SCIP_QuadVarEventData SCIP_QUADVAREVENTDATA
SCIP_Bool SCIPintervalIsEntire(SCIP_Real infinity, SCIP_INTERVAL operand)
SCIP_Bool SCIPisRelGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static void getIneqViol(SCIP_VAR *x, SCIP_VAR *y, SCIP_Real xcoef, SCIP_Real ycoef, SCIP_Real constant, SCIP_Real *viol1, SCIP_Real *viol2)
void SCIPaddBilinMcCormick(SCIP *scip, SCIP_Real bilincoef, SCIP_Real lbx, SCIP_Real ubx, SCIP_Real refpointx, SCIP_Real lby, SCIP_Real uby, SCIP_Real refpointy, SCIP_Bool overestimate, SCIP_Real *lincoefx, SCIP_Real *lincoefy, SCIP_Real *linconstant, SCIP_Bool *success)
SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
Definition: scip_heur.c:328
SCIP_RETCODE SCIPfindQuadVarTermQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, int *pos)
SCIP_RETCODE SCIPensureRowprepSize(SCIP *scip, SCIP_ROWPREP *rowprep, int size)
static void propagateBoundsGetQuadActivity(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real intervalinfty, SCIP_Real *minquadactivity, SCIP_Real *maxquadactivity, int *minactivityinf, int *maxactivityinf, SCIP_INTERVAL *quadactcontr)
static SCIP_RETCODE addLinearizationCuts(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *ref, SCIP_Bool *separatedlpsol, SCIP_Real minefficacy)
SCIP_RETCODE SCIPcreateConsAnd(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *resvar, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: cons_and.c:5003
#define SCIPerrorMessage
Definition: pub_message.h:45
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4191
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2822
interval arithmetics for provable bounds
static SCIP_RETCODE removeFixedVariables(SCIP *scip, SCIP_CONS *cons)
int SCIPhashmapGetNEntries(SCIP_HASHMAP *hashmap)
Definition: misc.c:3143
void SCIPintervalSetEmpty(SCIP_INTERVAL *resultant)
SCIP_RETCODE SCIPgetAllBilinearTermsQuadratic(SCIP *scip, SCIP_VAR **RESTRICT x, SCIP_VAR **RESTRICT y, int *RESTRICT nbilinterms, int *RESTRICT nunderests, int *RESTRICT noverests, SCIP_Real *maxnonconvexity)
SCIP_Real SCIPgetRowprepViolation(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol)
SCIP_HASHMAPENTRY * SCIPhashmapGetEntry(SCIP_HASHMAP *hashmap, int entryidx)
Definition: misc.c:3151
void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPaddConsLocal(SCIP *scip, SCIP_CONS *cons, SCIP_NODE *validnode)
Definition: scip_prob.c:3446
SCIP_RETCODE SCIPaddNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition: scip_nlp.c:535
SCIP_VAR ** vars
enum SCIP_NlpSolStat SCIP_NLPSOLSTAT
Definition: type_nlpi.h:69
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3527
public methods for event handler plugins and event handlers
SCIP_Real SCIPintervalGetInf(SCIP_INTERVAL interval)
public methods for nonlinear functions
#define COPYSIGN
Definition: def.h:230
static SCIP_RETCODE computeViolation(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *solviolbounds)
static SCIP_DECL_CONSDELETE(consDeleteQuadratic)
static SCIP_DECL_CONSPARSE(consParseQuadratic)
SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
Definition: lp.c:16978
SCIP_RETCODE SCIPreleaseNlRow(SCIP *scip, SCIP_NLROW **nlrow)
Definition: scip_nlp.c:1350
static SCIP_RETCODE presolveUpgrade(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Bool *upgraded, int *nupgdconss, int *naddconss, SCIP_PRESOLTIMING presoltiming)
static SCIP_RETCODE presolveDisaggregateMarkComponent(SCIP *scip, SCIP_CONSDATA *consdata, int quadvaridx, SCIP_HASHMAP *var2component, int componentnr, int *componentsize)
SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: scip_var.c:1796
static SCIP_RETCODE catchQuadVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons, int quadvarpos)
SCIP_Real * SCIPgetCoefsLinearVarsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIPInterval sqrt(const SCIPInterval &x)
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip_mem.h:143
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:128
int SCIPgetLinvarMayDecreaseQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcheckCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool checkintegrality, SCIP_Bool checklprows, SCIP_Bool printreason, SCIP_RESULT *result)
Definition: scip_cons.c:2149
SCIP_Bool SCIPsortedvecFindPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void *val, int len, int *pos)
void SCIPhashmapEntrySetImage(SCIP_HASHMAPENTRY *entry, void *image)
Definition: misc.c:3192
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4375
static SCIP_DECL_CONSCHECK(consCheckQuadratic)
#define MAX3(x, y, z)
Definition: def.h:213
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8076
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8295
#define SCIP_EVENTTYPE_IMPLADDED
Definition: type_event.h:71
static SCIP_DECL_CONSPRESOL(consPresolQuadratic)
void SCIPaddRowprepSide(SCIP_ROWPREP *rowprep, SCIP_Real side)
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:155
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16729
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip_cons.c:434
static SCIP_DECL_CONSTRANS(consTransQuadratic)
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:2826
constraint handler for quadratic constraints
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4211
SCIP_RETCODE SCIPcreateRowprep(SCIP *scip, SCIP_ROWPREP **rowprep, SCIP_SIDETYPE sidetype, SCIP_Bool local)
#define CONSHDLR_CHECKPRIORITY
SCIP_RETCODE SCIPmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:2028
static SCIP_RETCODE registerBranchingCandidates(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, int *nnotify)
SCIP_HEUR * SCIPsolGetHeur(SCIP_SOL *sol)
Definition: sol.c:2553
SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1540
int SCIPgetNNlpis(SCIP *scip)
Definition: scip_nlp.c:206
#define REALABS(x)
Definition: def.h:174
SCIP_RETCODE SCIPsetNLPInitialGuessSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip_nlp.c:612
SCIP_RETCODE SCIPgetNlRowQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_NLROW **nlrow)
SCIP_RETCODE SCIPcreateChild(SCIP *scip, SCIP_NODE **node, SCIP_Real nodeselprio, SCIP_Real estimate)
Definition: scip_branch.c:959
SCIP_QUADELEM * SCIPnlrowGetQuadElems(SCIP_NLROW *nlrow)
Definition: nlp.c:3333
public methods for problem copies
public methods for primal CIP solutions
SCIP_Real SCIPgetSepaMinEfficacy(SCIP *scip)
Definition: scip_sepa.c:376
#define SCIP_CALL(x)
Definition: def.h:351
unsigned int SCIP_PRESOLTIMING
Definition: type_timing.h:52
#define CONSHDLR_ENFOPRIORITY
SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
Definition: var.c:17147
SCIP_VAR * h
Definition: circlepacking.c:59
SCIP_Real sup
Definition: intervalarith.h:40
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
void SCIPintervalSet(SCIP_INTERVAL *resultant, SCIP_Real value)
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:16879
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip_message.c:296
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8315
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:294
static void rowprepCleanupScaledown(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_Real *viol, SCIP_Real minviol)
#define SCIPdebugGetSolVal(scip, var, val)
Definition: debug.h:268
static SCIP_RETCODE rowprepCleanupSortTerms(SCIP *scip, SCIP_ROWPREP *rowprep)
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:51
SCIP_BILINTERM * SCIPgetBilinTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
#define SCIP_EVENTTYPE_BOUNDTIGHTENED
Definition: type_event.h:106
SCIP_RETCODE LapackDsyev(SCIP_Bool computeeigenvectors, int N, SCIP_Real *a, SCIP_Real *w)
SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
Definition: lp.c:16815
SCIP_NLPSOLSTAT SCIPnlpiGetSolstat(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem)
Definition: nlpi.c:511
SCIP_RETCODE SCIPnlpiSetObjective(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem, int nlins, const int *lininds, const SCIP_Real *linvals, int nquadelems, const SCIP_QUADELEM *quadelems, const int *exprvaridxs, const SCIP_EXPRTREE *exprtree, const SCIP_Real constant)
Definition: nlpi.c:300
public methods for primal heuristic plugins and divesets
#define SCIP_EVENTTYPE_UBCHANGED
Definition: type_event.h:105
SCIP_Bool SCIPhasPrimalRay(SCIP *scip)
Definition: scip_sol.c:3571
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)
int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4593
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_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
static SCIP_RETCODE proposeFeasibleSolution(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool *success)
SCIP_Real SCIPgetRhsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPexprgraphGetNodeQuadraticConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13130
SCIP_RETCODE SCIPgetViolationQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *violation)
SCIP_Bool SCIPvarIsOriginal(SCIP_VAR *var)
Definition: var.c:16858
SCIP_RETCODE SCIPaddBilinTermQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Real coef)
SCIP_RETCODE SCIPnlpiFreeProblem(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM **problem)
Definition: nlpi.c:224
Ipopt NLP interface.
static SCIP_RETCODE computeInteriorPoint(SCIP *scip, SCIP_CONS *cons, char method, SCIP_Bool *success)
static SCIP_RETCODE propagateBoundsTightenVarUb(SCIP *scip, SCIP_CONS *cons, SCIP_Real intervalinfty, SCIP_VAR *var, SCIP_Real bnd, SCIP_RESULT *result, int *nchgbds)
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:130
SCIP_Real * SCIProwGetVals(SCIP_ROW *row)
Definition: lp.c:16825
public data structures and miscellaneous methods
SCIP_BOUNDTYPE * SCIPvarGetImplTypes(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17653
#define CONSHDLR_NEEDSCONS
static unsigned int nextPowerOf2(unsigned int v)
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:1018
static SCIP_DECL_CONSINITLP(consInitlpQuadratic)
SCIP_Real side
#define SCIP_Bool
Definition: def.h:62
static SCIP_DECL_CONSFREE(consFreeQuadratic)
SCIP_RETCODE SCIPcatchEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:354
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip_lp.c:226
static SCIP_RETCODE presolveDisaggregate(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *naddconss)
SCIP_Bool SCIPexprgraphAreAllNodeChildrenVars(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14631
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)
static SCIP_RETCODE registerBranchingCandidatesCentrality(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, int *nnotify)
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:995
static SCIP_RETCODE computeGauge(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons)
static SCIP_RETCODE generateCutFactorable(SCIP *scip, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_Real *ref, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1336
SCIP_Real SCIPgetLhsNonlinear(SCIP *scip, SCIP_CONS *cons)
#define NONLINCONSUPGD_PRIORITY
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:715
SCIP_RETCODE SCIPnlpiSetIntPar(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem, SCIP_NLPPARAM type, int ival)
Definition: nlpi.c:636
SCIP_Real SCIPlpfeastol(SCIP *scip)
constraint handler for nonlinear constraints
int SCIPvarGetNImpls(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17621
void SCIPintervalSolveBivariateQuadExpressionAllScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_Real ax, SCIP_Real ay, SCIP_Real axy, SCIP_Real bx, SCIP_Real by, SCIP_INTERVAL rhs, SCIP_INTERVAL xbnds, SCIP_INTERVAL ybnds)
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip_cons.c:2550
void SCIPmergeRowprepTerms(SCIP *scip, SCIP_ROWPREP *rowprep)
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:10118
SCIP_NLPTERMSTAT SCIPnlpiGetTermstat(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem)
Definition: nlpi.c:523
static SCIP_RETCODE sortAllBilinTerms(SCIP *scip, SCIP_BILINTERM *bilinterms, int nbilinterms, SCIP_CONS **bilinconss, int *bilinposs)
static SCIP_DECL_CONSEXITSOL(consExitsolQuadratic)
static SCIP_RETCODE replaceByLinearConstraints(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool *addedcons, SCIP_Bool *reduceddom, SCIP_Bool *infeasible)
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition: scip_cut.c:405
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8096
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11422
#define MIN(x, y)
Definition: def.h:209
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)
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:1365
static void consdataSortLinearVars(SCIP_CONSDATA *consdata)
SCIP_RETCODE SCIPsetConshdlrDisable(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDISABLE((*consdisable)))
Definition: scip_cons.c:801
SCIP_RETCODE SCIPdropEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:388
public methods for cuts and aggregation rows
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip_sol.c:1034
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8275
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8245
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17191
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:468
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:104
SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
Definition: scip_branch.c:654
void SCIPintervalAdd(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_Real SCIPintervalGetSup(SCIP_INTERVAL interval)
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:116
#define ROWPREP_SCALEUP_MAXSIDE
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4290
static SCIP_Real getInteriority(SCIP *scip, SCIP_Real lbx, SCIP_Real ubx, SCIP_Real refx, SCIP_Real lby, SCIP_Real uby, SCIP_Real refy)
SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1493
#define infty2infty(infty1, infty2, val)
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip_cons.c:847
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata)
Constraint handler for linear constraints in their most general form, .
static SCIP_RETCODE createNlRow(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisCutApplicable(SCIP *scip, SCIP_ROW *cut)
Definition: scip_cut.c:251
int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition: var.c:17111
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Real * SCIPvarGetImplBounds(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17667
#define CONSHDLR_NAME
#define BMSclearMemory(ptr)
Definition: memory.h:111
#define SCIP_EVENTTYPE_GBDCHANGED
Definition: type_event.h:103
static SCIP_Bool consdataCheckBilinTermsSort(SCIP_CONSDATA *consdata)
SCIP_RETCODE SCIPgetRowprepRowCons(SCIP *scip, SCIP_ROW **row, SCIP_ROWPREP *rowprep, SCIP_CONSHDLR *conshdlr)
char name[SCIP_MAXSTRLEN]
SCIP_RETCODE SCIPsetConshdlrEnable(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENABLE((*consenable)))
Definition: scip_cons.c:778
void * SCIPexprgraphGetNodeVar(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13059
int SCIPgetNBinVars(SCIP *scip)
Definition: scip_prob.c:2089
SCIP_Bool SCIPisLinearLocalQuadratic(SCIP *scip, SCIP_CONS *cons)
static void generateCutLTIcomputeCoefs(SCIP *scip, SCIP_Real xl, SCIP_Real xu, SCIP_Real x0, SCIP_Real yl, SCIP_Real yu, SCIP_Real y0_, SCIP_Real wl, SCIP_Real wu, SCIP_Real w0, SCIP_Real *cx, SCIP_Real *cy, SCIP_Real *cw, SCIP_Real *c0, SCIP_Bool *success)
static SCIP_DECL_CONSENFORELAX(consEnforelaxQuadratic)
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:152
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:13142
#define ROWPREP_SCALEUP_MINVIOLFACTOR
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:2044
SCIP_RETCODE SCIPcheckCurvatureQuadratic(SCIP *scip, SCIP_CONS *cons)
public methods for nonlinear relaxations
SCIP_Real SCIPnodeGetEstimate(SCIP_NODE *node)
Definition: tree.c:7374
void SCIPenableNLP(SCIP *scip)
Definition: scip_nlp.c:269
SCIP_Bool SCIPinDive(SCIP *scip)
Definition: scip_lp.c:2657
static SCIP_RETCODE registerLargeRelaxValueVariableForBranching(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_VAR **brvar)
methods for sorting joint arrays of various types
SCIP_QUADVAREVENTDATA * eventdata
SCIP_Bool SCIPconsIsLockedType(SCIP_CONS *cons, SCIP_LOCKTYPE locktype)
Definition: cons.c:8469
SCIP_VAR ** SCIPvarGetImplVars(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17638
SCIP_RETCODE SCIPcreateConsLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip_cons.c:578
#define SQRT(x)
Definition: def.h:192
enum SCIP_ExprCurv SCIP_EXPRCURV
Definition: type_expr.h:95
public methods for branching rule plugins and branching
SCIP_VAR ** b
Definition: circlepacking.c:56
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1474
int SCIPgetLinvarMayIncreaseQuadratic(SCIP *scip, SCIP_CONS *cons)
int SCIPgetNLinearVarsQuadratic(SCIP *scip, SCIP_CONS *cons)
public methods for managing events
static SCIP_RETCODE addBilinearTerm(SCIP *scip, SCIP_CONS *cons, int var1pos, int var2pos, SCIP_Real coef)
general public methods
#define MAX(x, y)
Definition: def.h:208
SCIP_RETCODE SCIPcreateNLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip_sol.c:447
static void consdataMoveQuadVarTerm(SCIP_CONSDATA *consdata, int oldpos, int newpos)
void SCIPsort(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
Definition: misc.c:5081
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPcopyRowprep(SCIP *scip, SCIP_ROWPREP **target, SCIP_ROWPREP *source)
static SCIP_RETCODE consdataCreateEmpty(SCIP *scip, SCIP_CONSDATA **consdata)
static SCIP_DECL_CONSGETNVARS(consGetNVarsQuadratic)
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
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:239
SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
Definition: lp.c:16639
int SCIPgetNLinearVarsNonlinear(SCIP *scip, SCIP_CONS *cons)
public methods for solutions
void SCIPfreeParseVarsPolynomialData(SCIP *scip, SCIP_VAR ****monomialvars, SCIP_Real ***monomialexps, SCIP_Real **monomialcoefs, int **monomialnvars, int nmonomials)
Definition: scip_var.c:1161
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:737
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_prob.c:1724
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8106
#define CONSHDLR_DESC
SCIP_RETCODE SCIPsetConshdlrInit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINIT((*consinit)))
Definition: scip_cons.c:458
SCIP_Real SCIPintervalQuadUpperBound(SCIP_Real infinity, SCIP_Real a, SCIP_INTERVAL b_, SCIP_INTERVAL x)
SCIP_RETCODE SCIPsetConshdlrExit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXIT((*consexit)))
Definition: scip_cons.c:482
static SCIP_RETCODE dropVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons)
static SCIP_DECL_CONSGETVARS(consGetVarsQuadratic)
#define SCIP_EVENTTYPE_FORMAT
Definition: type_event.h:135
public methods for the probing mode
static void rowprepCleanupSide(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_Real *viol)
static SCIP_DECL_CONSCOPY(consCopyQuadratic)
static SCIP_DECL_CONSINIT(consInitQuadratic)
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1187
static SCIP_RETCODE unlockLinearVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
void SCIPintervalSetRoundingModeUpwards(void)
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_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip_cons.c:602
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)
void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition: scip_sol.c:322
SCIP_Real SCIPgetRowLPFeasibility(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1911
SCIP_RETCODE SCIPgetFeasibilityQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *feasibility)
SCIP_RETCODE SCIPsortQuadVarTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPeventGetOldbound(SCIP_EVENT *event)
Definition: event.c:1174
SCIP_VAR * a
Definition: circlepacking.c:57
int SCIPscaleRowprep(SCIP_ROWPREP *rowprep, SCIP_Real factor)
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
void SCIPsortDownRealRealPtr(SCIP_Real *realarray1, SCIP_Real *realarray2, void **ptrarray, int len)
SCIP_RETCODE SCIPgetNLPFracVars(SCIP *scip, SCIP_VAR ***fracvars, SCIP_Real **fracvarssol, SCIP_Real **fracvarsfrac, int *nfracvars, int *npriofracvars)
Definition: scip_nlp.c:787
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:16848
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:8277
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1217
#define SCIP_Real
Definition: def.h:150
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8325
SCIP_RETCODE SCIPaddVarsToRow(SCIP *scip, SCIP_ROW *row, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip_lp.c:1628
SCIP_RETCODE SCIPaddToNlpiProblemQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *nlpiprob, SCIP_HASHMAP *scipvar2nlpivar, SCIP_Bool names)
SCIP_VAR ** SCIPgetLinearVarsNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:739
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip_cons.c:916
void SCIPintervalMulScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
SCIP_VAR ** y
Definition: circlepacking.c:55
SCIP_Bool SCIPhaveVarsCommonClique(SCIP *scip, SCIP_VAR *var1, SCIP_Bool value1, SCIP_VAR *var2, SCIP_Bool value2, SCIP_Bool regardimplics)
Definition: scip_var.c:7557
static SCIP_RETCODE computeReferencePointGauge(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *refsol, SCIP_Real *ref, SCIP_Bool *success)
public methods for message handling
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8265
static SCIP_RETCODE checkFactorable(SCIP *scip, SCIP_CONS *cons)
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12977
#define SCIP_INVALID
Definition: def.h:170
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8255
void SCIPsortPtrReal(void **ptrarray, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2094
void SCIPsortInt(int *intarray, int len)
static SCIP_RETCODE propagateBoundsTightenVarLb(SCIP *scip, SCIP_CONS *cons, SCIP_Real intervalinfty, SCIP_VAR *var, SCIP_Real bnd, SCIP_RESULT *result, int *nchgbds)
SCIP_RETCODE SCIPcreateConsQuadratic2(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadvarterms, SCIP_QUADVARTERM *quadvarterms, int nbilinterms, SCIP_BILINTERM *bilinterms, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable)
static SCIP_RETCODE delLinearCoefPos(SCIP *scip, SCIP_CONS *cons, int pos)
#define SCIP_Longint
Definition: def.h:135
static SCIP_RETCODE consdataEnsureBilinSize(SCIP *scip, SCIP_CONSDATA *consdata, int num)
SCIP_RETCODE SCIPaddQuadVarLinearCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_BOUNDTYPE SCIPvarGetBestBoundType(SCIP_VAR *var)
Definition: var.c:17455
SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1239
#define SCIPdebugAddSolVal(scip, var, val)
Definition: debug.h:267
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:16894
static SCIP_DECL_CONSLOCK(consLockQuadratic)
SCIP_RETCODE SCIPcreateConsBounddisjunction(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_BOUNDTYPE *boundtypes, SCIP_Real *bounds, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPparseVarsPolynomial(SCIP *scip, const char *str, SCIP_VAR ****monomialvars, SCIP_Real ***monomialexps, SCIP_Real **monomialcoefs, int **monomialnvars, int *nmonomials, char **endptr, SCIP_Bool *success)
Definition: scip_var.c:809
int SCIP_ROUNDMODE
Definition: intervalarith.h:46
void SCIPintervalMulInf(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
void SCIPintervalSub(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Real ineqoverest[6]
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:50
static SCIP_DECL_EVENTEXEC(processVarEvent)
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17409
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:117
static SCIP_RETCODE addLinearCoef(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
static SCIP_RETCODE presolveDisaggregateMergeComponents(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_HASHMAP *var2component, int nvars, int *ncomponents, int *componentssize)
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:16871
SCIP_RETCODE SCIPupdateStartpointHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *solcand, SCIP_Real violation)
Definition: heur_subnlp.c:2451
SCIP_Bool SCIPconsIsMarkedPropagate(SCIP_CONS *cons)
Definition: cons.c:8285
#define CONSHDLR_PROP_TIMING
#define SCIP_DECL_QUADCONSUPGD(x)
static SCIP_DECL_CONSPROP(consPropQuadratic)
SCIP_Real * coefs
SCIP_NLPI ** SCIPgetNlpis(SCIP *scip)
Definition: scip_nlp.c:193
static SCIP_RETCODE delQuadVarTermPos(SCIP *scip, SCIP_CONS *cons, int pos)
SCIP_Real SCIPgetUpperbound(SCIP *scip)
static SCIP_DECL_CONSPRINT(consPrintQuadratic)
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:2874
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:112
SCIP_Bool SCIPisSumLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
public methods for primal heuristics
#define ROWPREP_SCALEUP_MAXMINCOEF
#define CONSHDLR_SEPAFREQ
static SCIP_RETCODE computeED(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons)
SCIP_QUADVARTERM * SCIPgetQuadVarTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcreateNlRow(SCIP *scip, SCIP_NLROW **nlrow, const char *name, SCIP_Real constant, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadvars, SCIP_VAR **quadvars, int nquadelems, SCIP_QUADELEM *quadelems, SCIP_EXPRTREE *expression, SCIP_Real lhs, SCIP_Real rhs, SCIP_EXPRCURV curvature)
Definition: scip_nlp.c:1242
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:13166
SCIP_EXPRGRAPHNODE * SCIPgetExprgraphNodeNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
void SCIPprintRowprep(SCIP *scip, SCIP_ROWPREP *rowprep, FILE *file)
constraint handler for bound disjunction constraints
void SCIPintervalAddScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip_cons.c:530
SCIP_Longint SCIPgetNLPs(SCIP *scip)
#define SCIPABORT()
Definition: def.h:323
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
SCIP_Real SCIPround(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:16920
static SCIP_RETCODE consdataFindQuadVarTerm(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR *var, int *pos)
SCIP_ROUNDMODE SCIPintervalGetRoundingMode(void)
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition: misc.c:8454
SCIP_RETCODE SCIPgetRowprepRowSepa(SCIP *scip, SCIP_ROW **row, SCIP_ROWPREP *rowprep, SCIP_SEPA *sepa)
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1410
static SCIP_RETCODE mergeAndCleanQuadVarTerms(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisInRestart(SCIP *scip)
Definition: scip_solve.c:3571
SCIP_SOL * SCIPeventGetSol(SCIP_EVENT *event)
Definition: event.c:1259
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:211
#define SCIPduplicateBlockMemory(scip, ptr, source)
Definition: scip_mem.h:109
SCIP_Bool SCIPisRelLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE consdataEnsureLinearVarsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num)
static SCIP_RETCODE enforceConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_Bool solinfeasible, SCIP_RESULT *result)
void SCIPintervalSetRoundingModeDownwards(void)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
static SCIP_RETCODE computeViolations(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool *solviolbounds, SCIP_CONS **maxviolcon)
#define ABS(x)
Definition: def.h:204
SCIP_Bool SCIPisConvexQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPgetPrimalRayVal(SCIP *scip, SCIP_VAR *var)
Definition: scip_sol.c:3589
static SCIP_DECL_CONSDISABLE(consDisableQuadratic)
SCIP_RETCODE SCIPgetActivityQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *activity)
static SCIP_Bool hasQuadvarHpProperty(SCIP *scip, SCIP_CONSDATA *consdata, int idx)
SCIP_Bool SCIPintervalIsSubsetEQ(SCIP_Real infinity, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:129
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)
int SCIPgetNSepaRounds(SCIP *scip)
static SCIP_RETCODE catchLinearVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons, int linvarpos)
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:17016
void SCIPaddSquareLinearization(SCIP *scip, SCIP_Real sqrcoef, SCIP_Real refpoint, SCIP_Bool isint, SCIP_Real *lincoef, SCIP_Real *linconstant, SCIP_Bool *success)
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:134
uint64_t SCIP_EVENTTYPE
Definition: type_event.h:134
SCIP_RETCODE SCIPnlpiSetRealPar(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem, SCIP_NLPPARAM type, SCIP_Real dval)
Definition: nlpi.c:671
void SCIPaddRowprepConstant(SCIP_ROWPREP *rowprep, SCIP_Real constant)
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip_cons.c:343
static SCIP_RETCODE generateCutUnboundedLP(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_ROW **row, SCIP_Real *rowrayprod, SCIP_Bool checkcurvmultivar)
void SCIPintervalQuad(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_Real sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL xrng)
memory allocation routines
enum SCIP_SideType SCIP_SIDETYPE
Definition: type_lp.h:58
SCIP_QUADELEM * SCIPexprgraphGetNodeQuadraticQuadElements(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13154