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-2017 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file cons_quadratic.c
17  * @brief constraint handler for quadratic constraints \f$\textrm{lhs} \leq \sum_{i,j=1}^n a_{i,j} x_i x_j + \sum_{i=1}^n b_i x_i \leq \textrm{rhs}\f$
18  * @author Stefan Vigerske
19  * @author Benjamin Mueller
20  * @author Felipe Serrano
21  *
22  * @todo SCIP might fix linear variables on +/- infinity; remove them in presolve and take care later
23  * @todo round constraint sides to integers if all coefficients and variables are (impl.) integer
24  * @todo constraints in one variable should be replaced by linear or bounddisjunction constraint
25  * @todo check if some quadratic terms appear in several constraints and try to simplify (e.g., nous1)
26  * @todo skip separation in enfolp if for current LP (check LP id) was already separated
27  * @todo watch unbounded variables to enable/disable propagation
28  * @todo sort order in bilinvar1/bilinvar2 such that the var which is involved in more terms is in bilinvar1, and use this info propagate and AddLinearReform
29  * @todo underestimate for multivariate concave quadratic terms as in cons_nonlinear
30  */
31 
32 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
33 
34 #include <assert.h>
35 #include <string.h> /* for strcmp */
36 #include <ctype.h> /* for isspace */
37 #include <math.h>
38 
39 #define SCIP_PRIVATE_ROWPREP
40 
41 #include "scip/cons_nonlinear.h"
42 #include "scip/cons_quadratic.h"
43 #include "scip/cons_linear.h"
44 #include "scip/cons_and.h"
45 #include "scip/cons_varbound.h"
47 #include "scip/intervalarith.h"
48 #include "scip/heur_subnlp.h"
49 #include "scip/heur_trysol.h"
50 #include "scip/debug.h"
51 #include "nlpi/nlpi.h"
52 #include "nlpi/nlpi_ipopt.h"
53 
54 /* constraint handler properties */
55 #define CONSHDLR_NAME "quadratic"
56 #define CONSHDLR_DESC "quadratic constraints of the form lhs <= b' x + x' A x <= rhs"
57 #define CONSHDLR_SEPAPRIORITY 10 /**< priority of the constraint handler for separation */
58 #define CONSHDLR_ENFOPRIORITY -50 /**< priority of the constraint handler for constraint enforcing */
59 #define CONSHDLR_CHECKPRIORITY -4000000 /**< priority of the constraint handler for checking feasibility */
60 #define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
61 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
62 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
63  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
64 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
65 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
66 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
67 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
68 
69 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP /**< propagation timing mask of the constraint handler */
70 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS /**< presolving timing of the constraint handler (fast, medium, or exhaustive) */
71 
72 #define MAXDNOM 10000LL /**< maximal denominator for simple rational fixed values */
73 #define NONLINCONSUPGD_PRIORITY 40000 /**< priority of upgrading nonlinear constraints */
74 #define INITLPMAXVARVAL 1000.0 /**< maximal absolute value of variable for still generating a linearization cut at that point in initlp */
75 
76 /* Activating this define enables reformulation of bilinear terms x*y with implications from x to y into linear terms.
77  * However, implications are not enforced by SCIP. Thus, if, e.g., the used implication was derived from this constraint and we then reformulate the constraint,
78  * then the implication may not be enforced in a solution.
79  * This issue need to be fixed before this feature can be enabled.
80  */
81 /* #define CHECKIMPLINBILINEAR */
82 
83 /* enable new propagation for bivariate quadratic terms */
84 #define PROPBILINNEW
85 
86 /* epsilon for differentiating between a boundary and interior point */
87 #define INTERIOR_EPS 1e-1
88 
89 /* scaling factor for gauge function */
90 #define GAUGESCALE 0.99999
91 
92 #define ROWPREP_SCALEUP_VIOLNONZERO (10.0*SCIPepsilon(scip)) /**< minimal violation for considering up-scaling of rowprep (we want to avoid upscaling very small violations) */
93 #define ROWPREP_SCALEUP_MINVIOLFACTOR 2.0 /**< scale up will target a violation of ~MINVIOLFACTOR*minviol, where minviol is given by caller */
94 #define ROWPREP_SCALEUP_MAXMINCOEF (1.0 / SCIPfeastol(scip)) /**< scale up only if min. coef is below this number (before scaling) */
95 #define ROWPREP_SCALEUP_MAXMAXCOEF SCIPgetHugeValue(scip) /**< scale up only if max. coef will not exceed this number by scaling */
96 #define ROWPREP_SCALEUP_MAXSIDE SCIPgetHugeValue(scip) /**< scale up only if side will not exceed this number by scaling */
97 #define ROWPREP_SCALEDOWN_MINMAXCOEF (1.0 / SCIPfeastol(scip)) /**< scale down if max. coef is at least this number (before scaling) */
98 #define ROWPREP_SCALEDOWN_MINCOEF SCIPfeastol(scip) /**< scale down only if min. coef does not drop below this number by scaling */
99 
100 /*
101  * Data structures
102  */
103 
104 /** eventdata for variable bound change events in quadratic constraints */
105 struct SCIP_QuadVarEventData
106 {
107  SCIP_CONS* cons; /**< the constraint */
108  int varidx; /**< the index of the variable which bound change is caught, positive for linear variables, negative for quadratic variables */
109  int filterpos; /**< position of eventdata in SCIP's event filter */
110 };
111 
112 /** Data of a quadratic constraint. */
113 struct SCIP_ConsData
114 {
115  SCIP_Real lhs; /**< left hand side of constraint */
116  SCIP_Real rhs; /**< right hand side of constraint */
117 
118  int nlinvars; /**< number of linear variables */
119  int linvarssize; /**< length of linear variable arrays */
120  SCIP_VAR** linvars; /**< linear variables */
121  SCIP_Real* lincoefs; /**< coefficients of linear variables */
122  SCIP_QUADVAREVENTDATA** lineventdata; /**< eventdata for bound change of linear variable */
123 
124  int nquadvars; /**< number of variables in quadratic terms */
125  int quadvarssize; /**< length of quadratic variable terms arrays */
126  SCIP_QUADVARTERM* quadvarterms; /**< array with quadratic variable terms */
127 
128  int nbilinterms; /**< number of bilinear terms */
129  int bilintermssize; /**< length of bilinear term arrays */
130  SCIP_BILINTERM* bilinterms; /**< bilinear terms array */
131 
132  SCIP_NLROW* nlrow; /**< a nonlinear row representation of this constraint */
133 
134  unsigned int linvarssorted:1; /**< are the linear variables already sorted? */
135  unsigned int linvarsmerged:1; /**< are equal linear variables already merged? */
136  unsigned int quadvarssorted:1; /**< are the quadratic variables already sorted? */
137  unsigned int quadvarsmerged:1; /**< are equal quadratic variables already merged? */
138  unsigned int bilinsorted:1; /**< are the bilinear terms already sorted? */
139  unsigned int bilinmerged:1; /**< are equal bilinear terms (and bilinear terms with zero coefficient) already merged? */
140 
141  unsigned int isconvex:1; /**< is quadratic function is convex ? */
142  unsigned int isconcave:1; /**< is quadratic function is concave ? */
143  unsigned int iscurvchecked:1; /**< is quadratic function checked on convexity or concavity ? */
144  unsigned int isremovedfixings:1; /**< did we removed fixed/aggr/multiaggr variables ? */
145  unsigned int ispropagated:1; /**< was the constraint propagated with respect to the current bounds ? */
146  unsigned int ispresolved:1; /**< did we checked for possibilities of upgrading or implicit integer variables ? */
147  unsigned int initialmerge:1; /**< did we perform an initial merge and clean in presolving yet ? */
148 #ifdef CHECKIMPLINBILINEAR
149  unsigned int isimpladded:1; /**< has there been an implication added for a binary variable in a bilinear term? */
150 #endif
151  unsigned int isgaugeavailable:1; /**< is the gauge function computed? */
152  unsigned int isedavailable:1; /**< is the eigen decomposition of A available? */
153 
154  SCIP_Real minlinactivity; /**< sum of minimal activities of all linear terms with finite minimal activity */
155  SCIP_Real maxlinactivity; /**< sum of maximal activities of all linear terms with finite maximal activity */
156  int minlinactivityinf; /**< number of linear terms with infinite minimal activity */
157  int maxlinactivityinf; /**< number of linear terms with infinity maximal activity */
158  SCIP_INTERVAL quadactivitybounds; /**< bounds on the activity of the quadratic term, if up to date, otherwise empty interval */
159  SCIP_Real activity; /**< activity of quadratic function w.r.t. current solution */
160  SCIP_Real lhsviol; /**< violation of lower bound by current solution (used temporarily inside constraint handler) */
161  SCIP_Real rhsviol; /**< violation of lower bound by current solution (used temporarily inside constraint handler) */
162 
163  int linvar_maydecrease; /**< index of a variable in linvars that may be decreased without making any other constraint infeasible, or -1 if none */
164  int linvar_mayincrease; /**< index of a variable in linvars that may be increased without making any other constraint infeasible, or -1 if none */
165 
166  SCIP_VAR** sepaquadvars; /**< variables corresponding to quadvarterms to use in separation, only available in solving stage */
167  int* sepabilinvar2pos; /**< position of second variable in bilinear terms to use in separation, only available in solving stage */
168  SCIP_Real lincoefsmin; /**< minimal absolute value of coefficients in linear part, only available in solving stage */
169  SCIP_Real lincoefsmax; /**< maximal absolute value of coefficients in linear part, only available in solving stage */
170 
171  SCIP_Real* factorleft; /**< coefficients of left factor if constraint function is factorable */
172  SCIP_Real* factorright; /**< coefficients of right factor if constraint function is factorable */
173 
174  SCIP_Real* gaugecoefs; /**< coefficients of the gauge function */
175  SCIP_Real gaugeconst; /**< constant of the gauge function */
176  SCIP_Real* interiorpoint; /**< interior point of the region defined by the convex function */
177  SCIP_Real interiorpointval; /**< function value at interior point */
178 
179  SCIP_Real* eigenvalues; /**< eigenvalues of A */
180  SCIP_Real* eigenvectors; /**< orthonormal eigenvectors of A; if A = P D P^T, then eigenvectors is P^T */
181  SCIP_Real* bp; /**< stores b * P where b are the linear coefficients of the quadratic vars */
182 };
183 
184 /** quadratic constraint update method */
186 {
187  SCIP_DECL_QUADCONSUPGD((*quadconsupgd)); /**< method to call for upgrading quadratic constraint */
188  int priority; /**< priority of upgrading method */
189  SCIP_Bool active; /**< is upgrading enabled */
190 };
191 typedef struct SCIP_QuadConsUpgrade SCIP_QUADCONSUPGRADE; /**< quadratic constraint update method */
193 /** constraint handler data */
194 struct SCIP_ConshdlrData
195 {
196  int replacebinaryprodlength; /**< length of linear term which when multiplied with a binary variable is replaced by an auxiliary variable and an equivalent linear formulation */
197  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 */
198  SCIP_Bool binreforminitial; /**< whether to make constraints added due to replacing products with binary variables initial */
199  SCIP_Real binreformmaxcoef; /**< factor on 1/feastol to limit coefficients and coef range in linear constraints created by binary reformulation */
200  SCIP_Real mincutefficacysepa; /**< minimal efficacy of a cut in order to add it to relaxation during separation */
201  SCIP_Real mincutefficacyenfofac; /**< minimal target efficacy of a cut in order to add it to relaxation during enforcement as factor of feasibility tolerance (may be ignored) */
202  char scaling; /**< scaling method of constraints in feasibility check */
203  SCIP_Real cutmaxrange; /**< maximal range (maximal coef / minimal coef) of a cut in order to be added to LP */
204  SCIP_Bool linearizeheursol; /**< whether linearizations of convex quadratic constraints should be added to cutpool when some heuristics finds a new solution */
205  SCIP_Bool checkcurvature; /**< whether functions should be checked for convexity/concavity */
206  SCIP_Bool checkfactorable; /**< whether functions should be checked to be factorable */
207  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) */
208  SCIP_Bool linfeasshift; /**< whether to make solutions in check feasible if possible */
209  SCIP_Bool disaggregate; /**< whether to disaggregate quadratic constraints */
210  int maxproprounds; /**< limit on number of propagation rounds for a single constraint within one round of SCIP propagation during solve */
211  int maxproproundspresolve; /**< limit on number of propagation rounds for a single constraint within one presolving round */
212  SCIP_Real sepanlpmincont; /**< minimal required fraction of continuous variables in problem to use solution of NLP relaxation in root for separation */
213  SCIP_Bool enfocutsremovable; /**< are cuts added during enforcement removable from the LP in the same node? */
214  SCIP_Bool gaugecuts; /**< should convex quadratics generated strong cuts via gauge function? */
215  SCIP_Bool projectedcuts; /**< should convex quadratics generated strong cuts via projections? */
216  char interiorcomputation;/**< how the interior point should be computed: 'a'ny point per constraint,
217  * 'm'ost interior per constraint
218  */
219  char branchscoring; /**< method to use to compute score of branching candidates */
220  int enfolplimit; /**< maximum number of enforcement round before declaring the LP relaxation
221  * infeasible (-1: no limit); WARNING: if this parameter is not set to -1,
222  * SCIP might declare sub-optimal solutions optimal or feasible instances
223  * infeasible; thus, the result returned by SCIP might be incorrect!
224  */
225  SCIP_HEUR* subnlpheur; /**< a pointer to the subnlp heuristic, if available */
226  SCIP_HEUR* trysolheur; /**< a pointer to the trysol heuristic, if available */
227  SCIP_EVENTHDLR* eventhdlr; /**< our handler for variable bound change events */
228  int newsoleventfilterpos; /**< filter position of new solution event handler, if caught */
229  SCIP_Bool sepanlp; /**< where linearization of the NLP relaxation solution added? */
230  SCIP_NODE* lastenfonode; /**< the node for which enforcement was called the last time (and some constraint was violated) */
231  int nenforounds; /**< counter on number of enforcement rounds for the current node */
232  SCIP_QUADCONSUPGRADE** quadconsupgrades; /**< quadratic constraint upgrade methods for specializing quadratic constraints */
233  int quadconsupgradessize; /**< size of quadconsupgrade array */
234  int nquadconsupgrades; /**< number of quadratic constraint upgrade methods */
235 };
236 
237 
238 /*
239  * local methods for managing quadratic constraint update methods
240  */
241 
242 
243 /** checks whether a quadratic constraint upgrade method has already be registered */
244 static
246  SCIP* scip, /**< SCIP data structure */
247  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
248  SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), /**< method to call for upgrading quadratic constraint */
249  const char* conshdlrname /**< name of the constraint handler */
250  )
251 {
252  int i;
253 
254  assert(scip != NULL);
255  assert(conshdlrdata != NULL);
256  assert(quadconsupgd != NULL);
257  assert(conshdlrname != NULL);
258 
259  for( i = conshdlrdata->nquadconsupgrades - 1; i >= 0; --i )
260  {
261  if( conshdlrdata->quadconsupgrades[i]->quadconsupgd == quadconsupgd )
262  {
263  SCIPwarningMessage(scip, "Try to add already known upgrade message for constraint handler <%s>.\n", conshdlrname);
264  return TRUE;
265  }
266  }
267 
268  return FALSE;
269 }
270 
271 /*
272  * Local methods
273  */
274 
275 /** translate from one value of infinity to another
276  *
277  * if val is >= infty1, then give infty2, else give val
278  */
279 #define infty2infty(infty1, infty2, val) ((val) >= (infty1) ? (infty2) : (val))
281 /** catches variable bound change events on a linear variable in a quadratic constraint */
282 static
284  SCIP* scip, /**< SCIP data structure */
285  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
286  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
287  int linvarpos /**< position of variable in linear variables array */
288  )
289 {
290  SCIP_CONSDATA* consdata;
291  SCIP_QUADVAREVENTDATA* eventdata;
292  SCIP_EVENTTYPE eventtype;
293 
294  assert(scip != NULL);
295  assert(eventhdlr != NULL);
296  assert(cons != NULL);
297 
298  consdata = SCIPconsGetData(cons);
299  assert(consdata != NULL);
300 
301  assert(linvarpos >= 0);
302  assert(linvarpos < consdata->nlinvars);
303  assert(consdata->lineventdata != NULL);
304 
305  SCIP_CALL( SCIPallocBlockMemory(scip, &eventdata) );
306 
307  eventdata->cons = cons;
308  eventdata->varidx = linvarpos;
309 
310  eventtype = SCIP_EVENTTYPE_VARFIXED;
311  if( !SCIPisInfinity(scip, consdata->rhs) )
312  {
313  /* if right hand side is finite, then a tightening in the lower bound of coef*linvar is of interest
314  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
315  if( consdata->lincoefs[linvarpos] > 0.0 )
316  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
317  else
318  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
319  }
320  if( !SCIPisInfinity(scip, -consdata->lhs) )
321  {
322  /* if left hand side is finite, then a tightening in the upper bound of coef*linvar is of interest
323  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
324  if( consdata->lincoefs[linvarpos] > 0.0 )
325  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
326  else
327  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
328  }
329 
330  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->linvars[linvarpos], eventtype, eventhdlr, (SCIP_EVENTDATA*)eventdata, &eventdata->filterpos) );
331 
332  consdata->lineventdata[linvarpos] = eventdata;
333 
334  /* invalidate activity information
335  * NOTE: It could happen that a constraint gets temporary deactivated and some variable bounds change. In this case
336  * we do not recognize those bound changes with the variable events and thus we have to recompute the activities.
337  */
338  consdata->minlinactivity = SCIP_INVALID;
339  consdata->maxlinactivity = SCIP_INVALID;
340  consdata->minlinactivityinf = -1;
341  consdata->maxlinactivityinf = -1;
342 
343  return SCIP_OKAY;
344 }
345 
346 /** drops variable bound change events on a linear variable in a quadratic constraint */
347 static
349  SCIP* scip, /**< SCIP data structure */
350  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
351  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
352  int linvarpos /**< position of variable in linear variables array */
353  )
354 {
355  SCIP_CONSDATA* consdata;
356  SCIP_EVENTTYPE eventtype;
357 
358  assert(scip != NULL);
359  assert(eventhdlr != NULL);
360  assert(cons != NULL);
361 
362  consdata = SCIPconsGetData(cons);
363  assert(consdata != NULL);
364 
365  assert(linvarpos >= 0);
366  assert(linvarpos < consdata->nlinvars);
367  assert(consdata->lineventdata != NULL);
368  assert(consdata->lineventdata[linvarpos] != NULL);
369  assert(consdata->lineventdata[linvarpos]->cons == cons);
370  assert(consdata->lineventdata[linvarpos]->varidx == linvarpos);
371  assert(consdata->lineventdata[linvarpos]->filterpos >= 0);
372 
373  eventtype = SCIP_EVENTTYPE_VARFIXED;
374  if( !SCIPisInfinity(scip, consdata->rhs) )
375  {
376  /* if right hand side is finite, then a tightening in the lower bound of coef*linvar is of interest
377  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
378  if( consdata->lincoefs[linvarpos] > 0.0 )
379  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
380  else
381  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
382  }
383  if( !SCIPisInfinity(scip, -consdata->lhs) )
384  {
385  /* if left hand side is finite, then a tightening in the upper bound of coef*linvar is of interest
386  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
387  if( consdata->lincoefs[linvarpos] > 0.0 )
388  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
389  else
390  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
391  }
392 
393  SCIP_CALL( SCIPdropVarEvent(scip, consdata->linvars[linvarpos], eventtype, eventhdlr, (SCIP_EVENTDATA*)consdata->lineventdata[linvarpos], consdata->lineventdata[linvarpos]->filterpos) );
394 
395  SCIPfreeBlockMemory(scip, &consdata->lineventdata[linvarpos]); /*lint !e866 */
396 
397  return SCIP_OKAY;
398 }
399 
400 /** catches variable bound change events on a quadratic variable in a quadratic constraint */
401 static
403  SCIP* scip, /**< SCIP data structure */
404  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
405  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
406  int quadvarpos /**< position of variable in quadratic variables array */
407  )
408 {
409  SCIP_CONSDATA* consdata;
410  SCIP_QUADVAREVENTDATA* eventdata;
411  SCIP_EVENTTYPE eventtype;
412 
413  assert(scip != NULL);
414  assert(eventhdlr != NULL);
415  assert(cons != NULL);
416 
417  consdata = SCIPconsGetData(cons);
418  assert(consdata != NULL);
419 
420  assert(quadvarpos >= 0);
421  assert(quadvarpos < consdata->nquadvars);
422  assert(consdata->quadvarterms[quadvarpos].eventdata == NULL);
423 
424  SCIP_CALL( SCIPallocBlockMemory(scip, &eventdata) );
425 
427 #ifdef CHECKIMPLINBILINEAR
428  eventtype |= SCIP_EVENTTYPE_IMPLADDED;
429 #endif
430  eventdata->cons = cons;
431  eventdata->varidx = -quadvarpos-1;
432  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->quadvarterms[quadvarpos].var, eventtype, eventhdlr, (SCIP_EVENTDATA*)eventdata, &eventdata->filterpos) );
433 
434  consdata->quadvarterms[quadvarpos].eventdata = eventdata;
435 
436  /* invalidate activity information
437  * NOTE: It could happen that a constraint gets temporary deactivated and some variable bounds change. In this case
438  * we do not recognize those bound changes with the variable events and thus we have to recompute the activities.
439  */
440  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
441 
442  return SCIP_OKAY;
443 }
444 
445 /** catches variable bound change events on a quadratic variable in a quadratic constraint */
446 static
448  SCIP* scip, /**< SCIP data structure */
449  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
450  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
451  int quadvarpos /**< position of variable in quadratic variables array */
452  )
453 {
454  SCIP_CONSDATA* consdata;
455  SCIP_EVENTTYPE eventtype;
456 
457  assert(scip != NULL);
458  assert(eventhdlr != NULL);
459  assert(cons != NULL);
460 
461  consdata = SCIPconsGetData(cons);
462  assert(consdata != NULL);
463 
464  assert(quadvarpos >= 0);
465  assert(quadvarpos < consdata->nquadvars);
466  assert(consdata->quadvarterms[quadvarpos].eventdata != NULL);
467  assert(consdata->quadvarterms[quadvarpos].eventdata->cons == cons);
468  assert(consdata->quadvarterms[quadvarpos].eventdata->varidx == -quadvarpos-1);
469  assert(consdata->quadvarterms[quadvarpos].eventdata->filterpos >= 0);
470 
472 #ifdef CHECKIMPLINBILINEAR
473  eventtype |= SCIP_EVENTTYPE_IMPLADDED;
474 #endif
475 
476  SCIP_CALL( SCIPdropVarEvent(scip, consdata->quadvarterms[quadvarpos].var, eventtype, eventhdlr, (SCIP_EVENTDATA*)consdata->quadvarterms[quadvarpos].eventdata, consdata->quadvarterms[quadvarpos].eventdata->filterpos) );
477 
478  SCIPfreeBlockMemory(scip, &consdata->quadvarterms[quadvarpos].eventdata);
479 
480  return SCIP_OKAY;
481 }
482 
483 /** catch variable events */
484 static
486  SCIP* scip, /**< SCIP data structure */
487  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
488  SCIP_CONS* cons /**< constraint for which to catch bound change events */
489  )
490 {
491  SCIP_CONSDATA* consdata;
492  SCIP_VAR* var;
493  int i;
494 
495  assert(scip != NULL);
496  assert(cons != NULL);
497  assert(eventhdlr != NULL);
498 
499  consdata = SCIPconsGetData(cons);
500  assert(consdata != NULL);
501  assert(consdata->lineventdata == NULL);
502 
503  /* we will update isremovedfixings, so reset it to TRUE first */
504  consdata->isremovedfixings = TRUE;
505 
506  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize) );
507  for( i = 0; i < consdata->nlinvars; ++i )
508  {
509  SCIP_CALL( catchLinearVarEvents(scip, eventhdlr, cons, i) );
510 
511  var = consdata->linvars[i];
512  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var)
513  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
514  }
515 
516  for( i = 0; i < consdata->nquadvars; ++i )
517  {
518  assert(consdata->quadvarterms[i].eventdata == NULL);
519 
520  SCIP_CALL( catchQuadVarEvents(scip, eventhdlr, cons, i) );
521 
522  var = consdata->quadvarterms[i].var;
523  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var)
524  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
525  }
526 
527  consdata->ispropagated = FALSE;
528 
529  return SCIP_OKAY;
530 }
531 
532 /** drop variable events */
533 static
535  SCIP* scip, /**< SCIP data structure */
536  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
537  SCIP_CONS* cons /**< constraint for which to drop bound change events */
538  )
539 {
540  SCIP_CONSDATA* consdata;
541  int i;
542 
543  assert(scip != NULL);
544  assert(eventhdlr != NULL);
545  assert(cons != NULL);
546 
547  consdata = SCIPconsGetData(cons);
548  assert(consdata != NULL);
549 
550  if( consdata->lineventdata != NULL )
551  {
552  for( i = 0; i < consdata->nlinvars; ++i )
553  {
554  if( consdata->lineventdata[i] != NULL )
555  {
556  SCIP_CALL( dropLinearVarEvents(scip, eventhdlr, cons, i) );
557  }
558  }
559  SCIPfreeBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize);
560  }
561 
562  for( i = 0; i < consdata->nquadvars; ++i )
563  {
564  if( consdata->quadvarterms[i].eventdata != NULL )
565  {
566  SCIP_CALL( dropQuadVarEvents(scip, eventhdlr, cons, i) );
567  }
568  }
569 
570  return SCIP_OKAY;
571 }
572 
573 /** locks a linear variable in a constraint */
574 static
576  SCIP* scip, /**< SCIP data structure */
577  SCIP_CONS* cons, /**< constraint where to lock a variable */
578  SCIP_VAR* var, /**< variable to lock */
579  SCIP_Real coef /**< coefficient of variable in constraint */
580  )
581 {
582  SCIP_CONSDATA* consdata;
583 
584  assert(scip != NULL);
585  assert(cons != NULL);
586  assert(var != NULL);
587  assert(coef != 0.0);
588 
589  consdata = SCIPconsGetData(cons);
590  assert(consdata != NULL);
591 
592  if( coef > 0.0 )
593  {
594  SCIP_CALL( SCIPlockVarCons(scip, var, cons, !SCIPisInfinity(scip, -consdata->lhs), !SCIPisInfinity(scip, consdata->rhs)) );
595  }
596  else
597  {
598  SCIP_CALL( SCIPlockVarCons(scip, var, cons, !SCIPisInfinity(scip, consdata->rhs), !SCIPisInfinity(scip, -consdata->lhs)) );
599  }
600 
601  return SCIP_OKAY;
602 }
603 
604 /** unlocks a linear variable in a constraint */
605 static
607  SCIP* scip, /**< SCIP data structure */
608  SCIP_CONS* cons, /**< constraint where to unlock a variable */
609  SCIP_VAR* var, /**< variable to unlock */
610  SCIP_Real coef /**< coefficient of variable in constraint */
611  )
612 {
613  SCIP_CONSDATA* consdata;
614 
615  assert(scip != NULL);
616  assert(cons != NULL);
617  assert(var != NULL);
618  assert(coef != 0.0);
619 
620  consdata = SCIPconsGetData(cons);
621  assert(consdata != NULL);
622 
623  if( coef > 0.0 )
624  {
625  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, !SCIPisInfinity(scip, -consdata->lhs), !SCIPisInfinity(scip, consdata->rhs)) );
626  }
627  else
628  {
629  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, !SCIPisInfinity(scip, consdata->rhs), !SCIPisInfinity(scip, -consdata->lhs)) );
630  }
631 
632  return SCIP_OKAY;
633 }
634 
635 /** locks a quadratic 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  )
642 {
643  SCIP_CALL( SCIPlockVarCons(scip, var, cons, TRUE, TRUE) );
644 
645  return SCIP_OKAY;
646 }
647 
648 /** unlocks a quadratic variable in a constraint */
649 static
651  SCIP* scip, /**< SCIP data structure */
652  SCIP_CONS* cons, /**< constraint where to unlock a variable */
653  SCIP_VAR* var /**< variable to unlock */
654  )
655 {
656  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, TRUE) );
657 
658  return SCIP_OKAY;
659 }
660 
661 /** computes the minimal and maximal activity for the linear part in a constraint data
662  *
663  * Only sums up terms that contribute finite values.
664  * Gives the number of terms that contribute infinite values.
665  * Only computes those activities where the corresponding side of the constraint is finite.
666  */
667 static
669  SCIP* scip, /**< SCIP data structure */
670  SCIP_CONSDATA* consdata, /**< constraint data */
671  SCIP_Real intervalinfty /**< infinity value used in interval operations */
672  )
673 { /*lint --e{666}*/
674  SCIP_ROUNDMODE prevroundmode;
675  int i;
676  SCIP_Real bnd;
677 
678  assert(scip != NULL);
679  assert(consdata != NULL);
680 
681  /* if variable bounds are not strictly consistent, then the activity update methods may yield inconsistent activities
682  * in this case, we also recompute the activities
683  */
684  if( consdata->minlinactivity != SCIP_INVALID && consdata->maxlinactivity != SCIP_INVALID && /*lint !e777 */
685  (consdata->minlinactivityinf > 0 || consdata->maxlinactivityinf > 0 || consdata->minlinactivity <= consdata->maxlinactivity) )
686  {
687  /* activities should be up-to-date */
688  assert(consdata->minlinactivityinf >= 0);
689  assert(consdata->maxlinactivityinf >= 0);
690  return;
691  }
692 
693  consdata->minlinactivityinf = 0;
694  consdata->maxlinactivityinf = 0;
695 
696  /* if lhs is -infinite, then we do not compute a maximal activity, so we set it to infinity
697  * if rhs is infinite, then we do not compute a minimal activity, so we set it to -infinity
698  */
699  consdata->minlinactivity = SCIPisInfinity(scip, consdata->rhs) ? -intervalinfty : 0.0;
700  consdata->maxlinactivity = SCIPisInfinity(scip, -consdata->lhs) ? intervalinfty : 0.0;
701 
702  if( consdata->nlinvars == 0 )
703  return;
704 
705  /* if the activities computed here should be still up-to-date after bound changes,
706  * variable events need to be caught */
707  assert(consdata->lineventdata != NULL);
708 
709  prevroundmode = SCIPintervalGetRoundingMode();
710 
711  if( !SCIPisInfinity(scip, consdata->rhs) )
712  {
713  /* compute minimal activity only if there is a finite right hand side */
715 
716  for( i = 0; i < consdata->nlinvars; ++i )
717  {
718  assert(consdata->lineventdata[i] != NULL);
719  if( consdata->lincoefs[i] >= 0.0 )
720  {
721  bnd = MIN(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
722  if( SCIPisInfinity(scip, -bnd) )
723  {
724  ++consdata->minlinactivityinf;
725  continue;
726  }
727  assert(!SCIPisInfinity(scip, bnd)); /* do not like variables that are fixed at +infinity */
728  }
729  else
730  {
731  bnd = MAX(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
732  if( SCIPisInfinity(scip, bnd) )
733  {
734  ++consdata->minlinactivityinf;
735  continue;
736  }
737  assert(!SCIPisInfinity(scip, -bnd)); /* do not like variables that are fixed at -infinity */
738  }
739  consdata->minlinactivity += consdata->lincoefs[i] * bnd;
740  }
741  }
742 
743  if( !SCIPisInfinity(scip, -consdata->lhs) )
744  {
745  /* compute maximal activity only if there is a finite left hand side */
747 
748  for( i = 0; i < consdata->nlinvars; ++i )
749  {
750  assert(consdata->lineventdata[i] != NULL);
751  if( consdata->lincoefs[i] >= 0.0 )
752  {
753  bnd = MAX(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
754  if( SCIPisInfinity(scip, bnd) )
755  {
756  ++consdata->maxlinactivityinf;
757  continue;
758  }
759  assert(!SCIPisInfinity(scip, -bnd)); /* do not like variables that are fixed at -infinity */
760  }
761  else
762  {
763  bnd = MIN(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
764  if( SCIPisInfinity(scip, -bnd) )
765  {
766  ++consdata->maxlinactivityinf;
767  continue;
768  }
769  assert(!SCIPisInfinity(scip, bnd)); /* do not like variables that are fixed at +infinity */
770  }
771  consdata->maxlinactivity += consdata->lincoefs[i] * bnd;
772  }
773  }
774 
775  SCIPintervalSetRoundingMode(prevroundmode);
776 
777  assert(consdata->minlinactivityinf > 0 || consdata->maxlinactivityinf > 0 || consdata->minlinactivity <= consdata->maxlinactivity);
778 }
779 
780 /** update the linear activities after a change in the lower bound of a variable */
781 static
783  SCIP* scip, /**< SCIP data structure */
784  SCIP_CONSDATA* consdata, /**< constraint data */
785  SCIP_Real coef, /**< coefficient of variable in constraint */
786  SCIP_Real oldbnd, /**< previous lower bound of variable */
787  SCIP_Real newbnd /**< new lower bound of variable */
788  )
789 {
790  SCIP_ROUNDMODE prevroundmode;
791 
792  assert(scip != NULL);
793  assert(consdata != NULL);
794  /* we can't deal with lower bounds at infinity */
795  assert(!SCIPisInfinity(scip, oldbnd));
796  assert(!SCIPisInfinity(scip, newbnd));
797 
798  /* @todo since we check the linear activity for consistency later anyway, we may skip changing the rounding mode here */
799 
800  /* assume lhs <= a*x + y <= rhs, then the following bound changes can be deduced:
801  * a > 0: y <= rhs - a*lb(x), y >= lhs - a*ub(x)
802  * a < 0: y <= rhs - a*ub(x), y >= lhs - a*lb(x)
803  */
804 
805  if( coef > 0.0 )
806  {
807  /* we should only be called if rhs is finite */
808  assert(!SCIPisInfinity(scip, consdata->rhs));
809 
810  /* we have no min activities computed so far, so cannot update */
811  if( consdata->minlinactivity == SCIP_INVALID ) /*lint !e777 */
812  return;
813 
814  prevroundmode = SCIPintervalGetRoundingMode();
816 
817  /* update min activity */
818  if( SCIPisInfinity(scip, -oldbnd) )
819  {
820  --consdata->minlinactivityinf;
821  assert(consdata->minlinactivityinf >= 0);
822  }
823  else
824  {
825  SCIP_Real minuscoef;
826  minuscoef = -coef;
827  consdata->minlinactivity += minuscoef * oldbnd;
828  }
829 
830  if( SCIPisInfinity(scip, -newbnd) )
831  {
832  ++consdata->minlinactivityinf;
833  }
834  else
835  {
836  consdata->minlinactivity += coef * newbnd;
837  }
838 
839  SCIPintervalSetRoundingMode(prevroundmode);
840  }
841  else
842  {
843  /* we should only be called if lhs is finite */
844  assert(!SCIPisInfinity(scip, -consdata->lhs));
845 
846  /* we have no max activities computed so far, so cannot update */
847  if( consdata->maxlinactivity == SCIP_INVALID ) /*lint !e777 */
848  return;
849 
850  prevroundmode = SCIPintervalGetRoundingMode();
852 
853  /* update max activity */
854  if( SCIPisInfinity(scip, -oldbnd) )
855  {
856  --consdata->maxlinactivityinf;
857  assert(consdata->maxlinactivityinf >= 0);
858  }
859  else
860  {
861  SCIP_Real minuscoef;
862  minuscoef = -coef;
863  consdata->maxlinactivity += minuscoef * oldbnd;
864  }
865 
866  if( SCIPisInfinity(scip, -newbnd) )
867  {
868  ++consdata->maxlinactivityinf;
869  }
870  else
871  {
872  consdata->maxlinactivity += coef * newbnd;
873  }
874 
875  SCIPintervalSetRoundingMode(prevroundmode);
876  }
877 }
878 
879 /** update the linear activities after a change in the upper bound of a variable */
880 static
882  SCIP* scip, /**< SCIP data structure */
883  SCIP_CONSDATA* consdata, /**< constraint data */
884  SCIP_Real coef, /**< coefficient of variable in constraint */
885  SCIP_Real oldbnd, /**< previous lower bound of variable */
886  SCIP_Real newbnd /**< new lower bound of variable */
887  )
888 {
889  SCIP_ROUNDMODE prevroundmode;
890 
891  assert(scip != NULL);
892  assert(consdata != NULL);
893  /* we can't deal with upper bounds at -infinity */
894  assert(!SCIPisInfinity(scip, -oldbnd));
895  assert(!SCIPisInfinity(scip, -newbnd));
896 
897  /* @todo since we check the linear activity for consistency later anyway, we may skip changing the rounding mode here */
898 
899  /* assume lhs <= a*x + y <= rhs, then the following bound changes can be deduced:
900  * a > 0: y <= rhs - a*lb(x), y >= lhs - a*ub(x)
901  * a < 0: y <= rhs - a*ub(x), y >= lhs - a*lb(x)
902  */
903 
904  if( coef > 0.0 )
905  {
906  /* we should only be called if lhs is finite */
907  assert(!SCIPisInfinity(scip, -consdata->lhs));
908 
909  /* we have no max activities computed so far, so cannot update */
910  if( consdata->maxlinactivity == SCIP_INVALID ) /*lint !e777 */
911  return;
912 
913  prevroundmode = SCIPintervalGetRoundingMode();
915 
916  /* update max activity */
917  if( SCIPisInfinity(scip, oldbnd) )
918  {
919  --consdata->maxlinactivityinf;
920  assert(consdata->maxlinactivityinf >= 0);
921  }
922  else
923  {
924  SCIP_Real minuscoef;
925  minuscoef = -coef;
926  consdata->maxlinactivity += minuscoef * oldbnd;
927  }
928 
929  if( SCIPisInfinity(scip, newbnd) )
930  {
931  ++consdata->maxlinactivityinf;
932  }
933  else
934  {
935  consdata->maxlinactivity += coef * newbnd;
936  }
937 
938  SCIPintervalSetRoundingMode(prevroundmode);
939  }
940  else
941  {
942  /* we should only be called if rhs is finite */
943  assert(!SCIPisInfinity(scip, consdata->rhs));
944 
945  /* we have no min activities computed so far, so cannot update */
946  if( consdata->minlinactivity == SCIP_INVALID ) /*lint !e777 */
947  return;
948 
949  prevroundmode = SCIPintervalGetRoundingMode();
951 
952  /* update min activity */
953  if( SCIPisInfinity(scip, oldbnd) )
954  {
955  --consdata->minlinactivityinf;
956  assert(consdata->minlinactivityinf >= 0);
957  }
958  else
959  {
960  SCIP_Real minuscoef;
961  minuscoef = -coef;
962  consdata->minlinactivity += minuscoef * oldbnd;
963  }
964 
965  if( SCIPisInfinity(scip, newbnd) )
966  {
967  ++consdata->minlinactivityinf;
968  }
969  else
970  {
971  consdata->minlinactivity += coef * newbnd;
972  }
973 
974  SCIPintervalSetRoundingMode(prevroundmode);
975  }
976 }
977 
978 /** returns whether a quadratic variable domain can be reduced to its lower or upper bound; this is the case if the
979  * quadratic variable is in just one single quadratic constraint and (sqrcoef > 0 and LHS = -infinity), or
980  * (sqrcoef < 0 and RHS = +infinity) hold
981  */
982 static
984  SCIP* scip, /**< SCIP data structure */
985  SCIP_CONSDATA* consdata, /**< constraint data */
986  int idx /**< index of quadratic variable */
987  )
988 {
989  SCIP_VAR* var;
990  SCIP_Real quadcoef;
991  SCIP_Bool haslhs;
992  SCIP_Bool hasrhs;
993 
994  assert(scip != NULL);
995  assert(consdata != NULL);
996  assert(idx >= 0 && idx < consdata->nquadvars);
997 
998  var = consdata->quadvarterms[idx].var;
999  assert(var != NULL);
1000 
1001  quadcoef = consdata->quadvarterms[idx].sqrcoef;
1002  haslhs = !SCIPisInfinity(scip, -consdata->lhs);
1003  hasrhs = !SCIPisInfinity(scip, consdata->rhs);
1004 
1005  return SCIPvarGetNLocksDown(var) == 1 && SCIPvarGetNLocksUp(var) == 1 && SCIPisZero(scip, SCIPvarGetObj(var))
1006  && SCIPvarGetType(var) != SCIP_VARTYPE_BINARY && ((quadcoef < 0.0 && !haslhs) || (quadcoef > 0.0 && !hasrhs));
1007 }
1008 
1009 /** processes variable fixing or bound change event */
1010 static
1011 SCIP_DECL_EVENTEXEC(processVarEvent)
1013  SCIP_CONS* cons;
1014  SCIP_CONSDATA* consdata;
1015  SCIP_EVENTTYPE eventtype;
1016  int varidx;
1017 
1018  assert(scip != NULL);
1019  assert(event != NULL);
1020  assert(eventdata != NULL);
1021  assert(eventhdlr != NULL);
1022 
1023  cons = ((SCIP_QUADVAREVENTDATA*)eventdata)->cons;
1024  assert(cons != NULL);
1025  consdata = SCIPconsGetData(cons);
1026  assert(consdata != NULL);
1027 
1028  varidx = ((SCIP_QUADVAREVENTDATA*)eventdata)->varidx;
1029  assert(varidx < 0 || varidx < consdata->nlinvars);
1030  assert(varidx >= 0 || -varidx-1 < consdata->nquadvars);
1031 
1032  eventtype = SCIPeventGetType(event);
1033 
1034  if( eventtype & SCIP_EVENTTYPE_BOUNDCHANGED )
1035  {
1036  if( varidx < 0 )
1037  {
1038  SCIP_QUADVARTERM* quadvarterm;
1039  SCIP_VAR* var;
1040 
1041  quadvarterm = &consdata->quadvarterms[-varidx-1];
1042  var = quadvarterm->var;
1043 
1044  /* 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()
1045  * we currently do this only if the binary variable does not show up in any bilinear terms
1046  * unfortunately, SCIP does not have an eventtype for vartype changes (nor do they always count as presolve reductions) and the bounds are
1047  * not updated yet when this event is processed, so we cannot use SCIPvarIsBinary here to check if the tightened integer variable will be binary
1048  */
1049  if( SCIPgetStage(scip) < SCIP_STAGE_SOLVING && SCIPvarGetType(var) == SCIP_VARTYPE_INTEGER && quadvarterm->sqrcoef != 0.0 && quadvarterm->nadjbilin == 0 &&
1050  ( ((eventtype & SCIP_EVENTTYPE_LBTIGHTENED) && SCIPeventGetNewbound(event) > -0.5 && SCIPvarGetUbGlobal(var) < 1.5) ||
1051  ((eventtype & SCIP_EVENTTYPE_UBTIGHTENED) && SCIPeventGetNewbound(event) < 1.5 && SCIPvarGetLbGlobal(var) > -0.5) ) )
1052  {
1053  consdata->quadvarsmerged = FALSE;
1054  consdata->initialmerge = FALSE;
1055  }
1056 
1057  /* mark activity bounds for quad term as not up to date anymore */
1058  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
1059  }
1060  else
1061  {
1062  /* update activity bounds for linear terms */
1063  if( eventtype & SCIP_EVENTTYPE_LBCHANGED )
1064  consdataUpdateLinearActivityLbChange(scip, consdata, consdata->lincoefs[varidx], SCIPeventGetOldbound(event), SCIPeventGetNewbound(event));
1065  else
1066  consdataUpdateLinearActivityUbChange(scip, consdata, consdata->lincoefs[varidx], SCIPeventGetOldbound(event), SCIPeventGetNewbound(event));
1067  }
1068 
1069  if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
1070  {
1071  SCIP_VAR* var;
1072 
1073  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
1074  consdata->ispropagated = FALSE;
1075 
1076  var = varidx < 0 ? consdata->quadvarterms[-varidx-1].var : consdata->linvars[varidx];
1077  assert(var != NULL);
1078 
1079  if( SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
1080  consdata->isremovedfixings = FALSE;
1081  }
1082  }
1083 
1084  if( eventtype & SCIP_EVENTTYPE_VARFIXED )
1085  {
1086  consdata->isremovedfixings = FALSE;
1087  }
1088 
1089 #ifdef CHECKIMPLINBILINEAR
1090  if( eventtype & SCIP_EVENTTYPE_IMPLADDED )
1091  {
1092  assert(varidx < 0); /* we catch impladded events only for quadratic variables */
1093  /* 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 */
1094  if( SCIPvarIsBinary(SCIPeventGetVar(event)) && consdata->quadvarterms[-varidx-1].nadjbilin > 0 )
1095  consdata->isimpladded = TRUE;
1096  }
1097 #endif
1098 
1099  return SCIP_OKAY;
1100 }
1101 
1102 /** ensures, that linear vars and coefs arrays can store at least num entries */
1103 static
1105  SCIP* scip, /**< SCIP data structure */
1106  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1107  int num /**< minimum number of entries to store */
1108  )
1109 {
1110  assert(scip != NULL);
1111  assert(consdata != NULL);
1112  assert(consdata->nlinvars <= consdata->linvarssize);
1113 
1114  if( num > consdata->linvarssize )
1115  {
1116  int newsize;
1117 
1118  newsize = SCIPcalcMemGrowSize(scip, num);
1119  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->linvars, consdata->linvarssize, newsize) );
1120  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->lincoefs, consdata->linvarssize, newsize) );
1121  if( consdata->lineventdata != NULL )
1122  {
1123  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize, newsize) );
1124  }
1125  consdata->linvarssize = newsize;
1126  }
1127  assert(num <= consdata->linvarssize);
1128 
1129  return SCIP_OKAY;
1130 }
1131 
1132 /** ensures, that quadratic variable terms array can store at least num entries */
1133 static
1135  SCIP* scip, /**< SCIP data structure */
1136  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1137  int num /**< minimum number of entries to store */
1138  )
1139 {
1140  assert(scip != NULL);
1141  assert(consdata != NULL);
1142  assert(consdata->nquadvars <= consdata->quadvarssize);
1143 
1144  if( num > consdata->quadvarssize )
1145  {
1146  int newsize;
1147 
1148  newsize = SCIPcalcMemGrowSize(scip, num);
1149  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->quadvarterms, consdata->quadvarssize, newsize) );
1150  consdata->quadvarssize = newsize;
1151  }
1152  assert(num <= consdata->quadvarssize);
1153 
1154  return SCIP_OKAY;
1155 }
1156 
1157 /** ensures, that adjacency array can store at least num entries */
1158 static
1160  SCIP* scip, /**< SCIP data structure */
1161  SCIP_QUADVARTERM* quadvarterm, /**< quadratic variable term */
1162  int num /**< minimum number of entries to store */
1163  )
1164 {
1165  assert(scip != NULL);
1166  assert(quadvarterm != NULL);
1167  assert(quadvarterm->nadjbilin <= quadvarterm->adjbilinsize);
1168 
1169  if( num > quadvarterm->adjbilinsize )
1170  {
1171  int newsize;
1172 
1173  newsize = SCIPcalcMemGrowSize(scip, num);
1174  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &quadvarterm->adjbilin, quadvarterm->adjbilinsize, newsize) );
1175  quadvarterm->adjbilinsize = newsize;
1176  }
1177  assert(num <= quadvarterm->adjbilinsize);
1178 
1179  return SCIP_OKAY;
1180 }
1181 
1182 /** ensures, that bilinear term arrays can store at least num entries */
1183 static
1185  SCIP* scip, /**< SCIP data structure */
1186  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1187  int num /**< minimum number of entries to store */
1188  )
1189 {
1190  assert(scip != NULL);
1191  assert(consdata != NULL);
1192  assert(consdata->nbilinterms <= consdata->bilintermssize);
1193 
1194  if( num > consdata->bilintermssize )
1195  {
1196  int newsize;
1197 
1198  newsize = SCIPcalcMemGrowSize(scip, num);
1199  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->bilinterms, consdata->bilintermssize, newsize) );
1200  consdata->bilintermssize = newsize;
1201  }
1202  assert(num <= consdata->bilintermssize);
1203 
1204  return SCIP_OKAY;
1205 }
1206 
1207 /** creates empty constraint data structure */
1208 static
1210  SCIP* scip, /**< SCIP data structure */
1211  SCIP_CONSDATA** consdata /**< a buffer to store pointer to new constraint data */
1212  )
1213 {
1214  assert(scip != NULL);
1215  assert(consdata != NULL);
1216 
1217  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1218  BMSclearMemory(*consdata);
1219 
1220  (*consdata)->lhs = -SCIPinfinity(scip);
1221  (*consdata)->rhs = SCIPinfinity(scip);
1222 
1223  (*consdata)->linvarssorted = TRUE;
1224  (*consdata)->linvarsmerged = TRUE;
1225  (*consdata)->quadvarssorted = TRUE;
1226  (*consdata)->quadvarsmerged = TRUE;
1227  (*consdata)->bilinsorted = TRUE;
1228  (*consdata)->bilinmerged = TRUE;
1229 
1230  (*consdata)->isremovedfixings = TRUE;
1231  (*consdata)->ispropagated = TRUE;
1232  (*consdata)->initialmerge = FALSE;
1233 
1234  (*consdata)->linvar_maydecrease = -1;
1235  (*consdata)->linvar_mayincrease = -1;
1236 
1237  (*consdata)->minlinactivity = SCIP_INVALID;
1238  (*consdata)->maxlinactivity = SCIP_INVALID;
1239  (*consdata)->minlinactivityinf = -1;
1240  (*consdata)->maxlinactivityinf = -1;
1241 
1242  (*consdata)->isgaugeavailable = FALSE;
1243  (*consdata)->isedavailable = FALSE;
1244 
1245  return SCIP_OKAY;
1246 }
1247 
1248 /** creates constraint data structure */
1249 static
1251  SCIP* scip, /**< SCIP data structure */
1252  SCIP_CONSDATA** consdata, /**< a buffer to store pointer to new constraint data */
1253  SCIP_Real lhs, /**< left hand side of constraint */
1254  SCIP_Real rhs, /**< right hand side of constraint */
1255  int nlinvars, /**< number of linear variables */
1256  SCIP_VAR** linvars, /**< array of linear variables */
1257  SCIP_Real* lincoefs, /**< array of coefficients of linear variables */
1258  int nquadvars, /**< number of quadratic variables */
1259  SCIP_QUADVARTERM* quadvarterms, /**< array of quadratic variable terms */
1260  int nbilinterms, /**< number of bilinear terms */
1261  SCIP_BILINTERM* bilinterms, /**< array of bilinear terms */
1262  SCIP_Bool capturevars /**< whether we should capture variables */
1263  )
1264 {
1265  int i;
1266 
1267  assert(scip != NULL);
1268  assert(consdata != NULL);
1269 
1270  assert(nlinvars == 0 || linvars != NULL);
1271  assert(nlinvars == 0 || lincoefs != NULL);
1272  assert(nquadvars == 0 || quadvarterms != NULL);
1273  assert(nbilinterms == 0 || bilinterms != NULL);
1274 
1275  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1276  BMSclearMemory(*consdata);
1277 
1278  (*consdata)->minlinactivity = SCIP_INVALID;
1279  (*consdata)->maxlinactivity = SCIP_INVALID;
1280  (*consdata)->minlinactivityinf = -1;
1281  (*consdata)->maxlinactivityinf = -1;
1282 
1283  (*consdata)->lhs = lhs;
1284  (*consdata)->rhs = rhs;
1285 
1286  if( nlinvars > 0 )
1287  {
1288  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->linvars, linvars, nlinvars) );
1289  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->lincoefs, lincoefs, nlinvars) );
1290  (*consdata)->nlinvars = nlinvars;
1291  (*consdata)->linvarssize = nlinvars;
1292 
1293  if( capturevars )
1294  for( i = 0; i < nlinvars; ++i )
1295  {
1296  SCIP_CALL( SCIPcaptureVar(scip, linvars[i]) );
1297  }
1298  }
1299  else
1300  {
1301  (*consdata)->linvarssorted = TRUE;
1302  (*consdata)->linvarsmerged = TRUE;
1303  (*consdata)->minlinactivity = 0.0;
1304  (*consdata)->maxlinactivity = 0.0;
1305  (*consdata)->minlinactivityinf = 0;
1306  (*consdata)->maxlinactivityinf = 0;
1307  }
1308 
1309  if( nquadvars > 0 )
1310  {
1311  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->quadvarterms, quadvarterms, nquadvars) );
1312 
1313  for( i = 0; i < nquadvars; ++i )
1314  {
1315  (*consdata)->quadvarterms[i].eventdata = NULL;
1316  if( quadvarterms[i].nadjbilin )
1317  {
1318  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->quadvarterms[i].adjbilin, quadvarterms[i].adjbilin, quadvarterms[i].nadjbilin) );
1319  (*consdata)->quadvarterms[i].adjbilinsize = quadvarterms[i].nadjbilin;
1320  }
1321  else
1322  {
1323  assert((*consdata)->quadvarterms[i].nadjbilin == 0);
1324  (*consdata)->quadvarterms[i].adjbilin = NULL;
1325  (*consdata)->quadvarterms[i].adjbilinsize = 0;
1326  }
1327  if( capturevars )
1328  {
1329  SCIP_CALL( SCIPcaptureVar(scip, quadvarterms[i].var) );
1330  }
1331  }
1332 
1333  (*consdata)->nquadvars = nquadvars;
1334  (*consdata)->quadvarssize = nquadvars;
1335  SCIPintervalSetEmpty(&(*consdata)->quadactivitybounds);
1336  }
1337  else
1338  {
1339  (*consdata)->quadvarssorted = TRUE;
1340  (*consdata)->quadvarsmerged = TRUE;
1341  SCIPintervalSet(&(*consdata)->quadactivitybounds, 0.0);
1342  }
1343 
1344  if( nbilinterms > 0 )
1345  {
1346  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->bilinterms, bilinterms, nbilinterms) );
1347  (*consdata)->nbilinterms = nbilinterms;
1348  (*consdata)->bilintermssize = nbilinterms;
1349  }
1350  else
1351  {
1352  (*consdata)->bilinsorted = TRUE;
1353  (*consdata)->bilinmerged = TRUE;
1354  }
1355 
1356  (*consdata)->linvar_maydecrease = -1;
1357  (*consdata)->linvar_mayincrease = -1;
1358 
1359  (*consdata)->activity = SCIP_INVALID;
1360  (*consdata)->lhsviol = SCIPisInfinity(scip, -lhs) ? 0.0 : SCIP_INVALID;
1361  (*consdata)->rhsviol = SCIPisInfinity(scip, rhs) ? 0.0 : SCIP_INVALID;
1362 
1363  (*consdata)->isgaugeavailable = FALSE;
1364 
1365  return SCIP_OKAY;
1366 }
1367 
1368 /** frees constraint data structure */
1369 static
1371  SCIP* scip, /**< SCIP data structure */
1372  SCIP_CONSDATA** consdata /**< pointer to constraint data to free */
1373  )
1374 {
1375  int i;
1376 
1377  assert(scip != NULL);
1378  assert(consdata != NULL);
1379  assert(*consdata != NULL);
1380 
1381  /* free sepa arrays, may exists if constraint is deleted in solving stage */
1382  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->sepaquadvars, (*consdata)->nquadvars);
1383  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->sepabilinvar2pos, (*consdata)->nbilinterms);
1384 
1385  /* release linear variables and free linear part */
1386  if( (*consdata)->linvarssize > 0 )
1387  {
1388  for( i = 0; i < (*consdata)->nlinvars; ++i )
1389  {
1390  assert((*consdata)->lineventdata == NULL || (*consdata)->lineventdata[i] == NULL); /* variable events should have been dropped earlier */
1391  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->linvars[i]) );
1392  }
1393  SCIPfreeBlockMemoryArray(scip, &(*consdata)->linvars, (*consdata)->linvarssize);
1394  SCIPfreeBlockMemoryArray(scip, &(*consdata)->lincoefs, (*consdata)->linvarssize);
1395  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->lineventdata, (*consdata)->linvarssize);
1396  }
1397  assert((*consdata)->linvars == NULL);
1398  assert((*consdata)->lincoefs == NULL);
1399  assert((*consdata)->lineventdata == NULL);
1400 
1401  /* release quadratic variables and free quadratic variable term part */
1402  for( i = 0; i < (*consdata)->nquadvars; ++i )
1403  {
1404  assert((*consdata)->quadvarterms[i].eventdata == NULL); /* variable events should have been dropped earlier */
1405  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->quadvarterms[i].adjbilin, (*consdata)->quadvarterms[i].adjbilinsize);
1406  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->quadvarterms[i].var) );
1407  }
1408  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->quadvarterms, (*consdata)->quadvarssize);
1409 
1410  /* free bilinear terms */
1411  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bilinterms, (*consdata)->bilintermssize);
1412 
1413  /* free nonlinear row representation */
1414  if( (*consdata)->nlrow != NULL )
1415  {
1416  SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
1417  }
1418 
1419  /* free interior point information, may exists if constraint is deleted in solving stage */
1420  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->interiorpoint, (*consdata)->nquadvars);
1421  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->gaugecoefs, (*consdata)->nquadvars);
1422 
1423  /* free eigen decomposition information */
1424  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->eigenvalues, (*consdata)->nquadvars);
1425  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->eigenvectors, (int)((*consdata)->nquadvars*(*consdata)->nquadvars));
1426  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bp, (*consdata)->nquadvars);
1427 
1428  SCIPfreeBlockMemory(scip, consdata);
1429  *consdata = NULL;
1430 
1431  return SCIP_OKAY;
1432 }
1433 
1434 /** sorts linear part of constraint data */
1435 static
1437  SCIP_CONSDATA* consdata /**< quadratic constraint data */
1438  )
1439 {
1440  assert(consdata != NULL);
1441 
1442  if( consdata->linvarssorted )
1443  return;
1444 
1445  if( consdata->nlinvars <= 1 )
1446  {
1447  consdata->linvarssorted = TRUE;
1448  return;
1449  }
1450 
1451  if( consdata->lineventdata == NULL )
1452  {
1453  SCIPsortPtrReal((void**)consdata->linvars, consdata->lincoefs, SCIPvarComp, consdata->nlinvars);
1454  }
1455  else
1456  {
1457  int i;
1458 
1459  SCIPsortPtrPtrReal((void**)consdata->linvars, (void**)consdata->lineventdata, consdata->lincoefs, SCIPvarComp, consdata->nlinvars);
1460 
1461  /* update variable indices in event data */
1462  for( i = 0; i < consdata->nlinvars; ++i )
1463  if( consdata->lineventdata[i] != NULL )
1464  consdata->lineventdata[i]->varidx = i;
1465  }
1466 
1467  consdata->linvarssorted = TRUE;
1468 }
1469 
1470 #ifdef SCIP_DISABLED_CODE /* no-one needs this routine currently */
1471 /** returns the position of variable in the linear coefficients array of a constraint, or -1 if not found */
1472 static
1473 int consdataFindLinearVar(
1474  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1475  SCIP_VAR* var /**< variable to search for */
1476  )
1477 {
1478  int pos;
1479 
1480  assert(consdata != NULL);
1481  assert(var != NULL);
1482 
1483  if( consdata->nlinvars == 0 )
1484  return -1;
1485 
1486  consdataSortLinearVars(consdata);
1487 
1488  if( !SCIPsortedvecFindPtr((void**)consdata->linvars, SCIPvarComp, (void*)var, consdata->nlinvars, &pos) )
1489  pos = -1;
1490 
1491  return pos;
1492 }
1493 #endif
1494 
1495 /** index comparison method for quadratic variable terms: compares two indices of the quadratic variable set in the quadratic constraint */
1496 static
1497 SCIP_DECL_SORTINDCOMP(quadVarTermComp)
1498 { /*lint --e{715}*/
1499  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
1500 
1501  assert(consdata != NULL);
1502  assert(0 <= ind1 && ind1 < consdata->nquadvars);
1503  assert(0 <= ind2 && ind2 < consdata->nquadvars);
1504 
1505  return SCIPvarCompare(consdata->quadvarterms[ind1].var, consdata->quadvarterms[ind2].var);
1506 }
1507 
1508 /** sorting of quadratic variable terms */
1509 static
1511  SCIP* scip, /**< SCIP data structure */
1512  SCIP_CONSDATA* consdata /**< quadratic constraint data */
1513  )
1514 {
1515  int* perm;
1516  int i;
1517  int nexti;
1518  int v;
1519  SCIP_QUADVARTERM quadterm;
1520 
1521  assert(scip != NULL);
1522  assert(consdata != NULL);
1523 
1524  if( consdata->quadvarssorted )
1525  return SCIP_OKAY;
1526 
1527  if( consdata->nquadvars == 0 )
1528  {
1529  consdata->quadvarssorted = TRUE;
1530  return SCIP_OKAY;
1531  }
1532 
1533  /* get temporary memory to store the sorted permutation */
1534  SCIP_CALL( SCIPallocBufferArray(scip, &perm, consdata->nquadvars) );
1535 
1536  /* call bubble sort */
1537  SCIPsort(perm, quadVarTermComp, (void*)consdata, consdata->nquadvars);
1538 
1539  /* permute the quadratic variable terms according to the resulting permutation */
1540  for( v = 0; v < consdata->nquadvars; ++v )
1541  {
1542  if( perm[v] != v )
1543  {
1544  quadterm = consdata->quadvarterms[v];
1545 
1546  i = v;
1547  do
1548  {
1549  assert(0 <= perm[i] && perm[i] < consdata->nquadvars);
1550  assert(perm[i] != i);
1551  consdata->quadvarterms[i] = consdata->quadvarterms[perm[i]];
1552  if( consdata->quadvarterms[i].eventdata != NULL )
1553  {
1554  consdata->quadvarterms[i].eventdata->varidx = -i-1;
1555  }
1556  nexti = perm[i];
1557  perm[i] = i;
1558  i = nexti;
1559  }
1560  while( perm[i] != v );
1561  consdata->quadvarterms[i] = quadterm;
1562  if( consdata->quadvarterms[i].eventdata != NULL )
1563  {
1564  consdata->quadvarterms[i].eventdata->varidx = -i-1;
1565  }
1566  perm[i] = i;
1567  }
1568  }
1569  consdata->quadvarssorted = TRUE;
1570 
1571  /* free temporary memory */
1572  SCIPfreeBufferArray(scip, &perm);
1573 
1574  return SCIP_OKAY;
1575 }
1576 
1577 /** returns the position of variable in the quadratic variable terms array of a constraint, or -1 if not found */
1578 static
1580  SCIP* scip, /**< SCIP data structure */
1581  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1582  SCIP_VAR* var, /**< variable to search for */
1583  int* pos /**< buffer where to store position of var in quadvarterms array, or -1 if not found */
1584  )
1585 {
1586  int left;
1587  int right;
1588  int cmpres;
1589 
1590  assert(consdata != NULL);
1591  assert(var != NULL);
1592  assert(pos != NULL);
1593 
1594  if( consdata->nquadvars == 0 )
1595  {
1596  *pos = -1;
1597  return SCIP_OKAY;
1598  }
1599 
1600  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
1601 
1602  left = 0;
1603  right = consdata->nquadvars - 1;
1604  while( left <= right )
1605  {
1606  int middle;
1607 
1608  middle = (left+right)/2;
1609  assert(0 <= middle && middle < consdata->nquadvars);
1610 
1611  cmpres = SCIPvarCompare(var, consdata->quadvarterms[middle].var);
1612 
1613  if( cmpres < 0 )
1614  right = middle - 1;
1615  else if( cmpres > 0 )
1616  left = middle + 1;
1617  else
1618  {
1619  *pos = middle;
1620  return SCIP_OKAY;
1621  }
1622  }
1623  assert(left == right+1);
1624 
1625  *pos = -1;
1626 
1627  return SCIP_OKAY;
1628 }
1629 
1630 /** index comparison method for bilinear terms: compares two index pairs of the bilinear term set in the quadratic constraint */
1631 static
1632 SCIP_DECL_SORTINDCOMP(bilinTermComp)
1633 { /*lint --e{715}*/
1634  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
1635  int var1cmp;
1636 
1637  assert(consdata != NULL);
1638  assert(0 <= ind1 && ind1 < consdata->nbilinterms);
1639  assert(0 <= ind2 && ind2 < consdata->nbilinterms);
1640 
1641  var1cmp = SCIPvarCompare(consdata->bilinterms[ind1].var1, consdata->bilinterms[ind2].var1);
1642  if( var1cmp != 0 )
1643  return var1cmp;
1644 
1645  return SCIPvarCompare(consdata->bilinterms[ind1].var2, consdata->bilinterms[ind2].var2);
1646 }
1647 
1648 #ifndef NDEBUG
1649 /** checks if all bilinear terms are sorted correctly */
1650 static
1652  SCIP_CONSDATA* consdata
1653  )
1654 {
1655  int i;
1656 
1657  assert(consdata != NULL);
1658 
1659  /* nothing to check if the bilinear terms have not been sorted yet */
1660  if( !consdata->bilinsorted )
1661  return TRUE;
1662 
1663  for( i = 0; i < consdata->nbilinterms - 1; ++i )
1664  {
1665  if( bilinTermComp(consdata, i, i+1) > 0 )
1666  return FALSE;
1667  }
1668  return TRUE;
1669 }
1670 #endif
1671 
1672 /** sorting of bilinear terms */
1673 static
1675  SCIP* scip, /**< SCIP data structure */
1676  SCIP_CONSDATA* consdata /**< quadratic constraint data */
1677  )
1678 {
1679  int* perm;
1680  int* invperm;
1681  int i;
1682  int nexti;
1683  int v;
1684  SCIP_BILINTERM bilinterm;
1685 
1686  assert(scip != NULL);
1687  assert(consdata != NULL);
1688 
1689  if( consdata->bilinsorted )
1690  return SCIP_OKAY;
1691 
1692  if( consdata->nbilinterms == 0 )
1693  {
1694  consdata->bilinsorted = TRUE;
1695  return SCIP_OKAY;
1696  }
1697 
1698  /* get temporary memory to store the sorted permutation and the inverse permutation */
1699  SCIP_CALL( SCIPallocBufferArray(scip, &perm, consdata->nbilinterms) );
1700  SCIP_CALL( SCIPallocBufferArray(scip, &invperm, consdata->nbilinterms) );
1701 
1702  /* call bubble sort */
1703  SCIPsort(perm, bilinTermComp, (void*)consdata, consdata->nbilinterms);
1704 
1705  /* compute inverted permutation */
1706  for( v = 0; v < consdata->nbilinterms; ++v )
1707  {
1708  assert(0 <= perm[v] && perm[v] < consdata->nbilinterms);
1709  invperm[perm[v]] = v;
1710  }
1711 
1712  /* permute the bilinear terms according to the resulting permutation */
1713  for( v = 0; v < consdata->nbilinterms; ++v )
1714  {
1715  if( perm[v] != v )
1716  {
1717  bilinterm = consdata->bilinterms[v];
1718 
1719  i = v;
1720  do
1721  {
1722  assert(0 <= perm[i] && perm[i] < consdata->nbilinterms);
1723  assert(perm[i] != i);
1724  consdata->bilinterms[i] = consdata->bilinterms[perm[i]];
1725  nexti = perm[i];
1726  perm[i] = i;
1727  i = nexti;
1728  }
1729  while( perm[i] != v );
1730  consdata->bilinterms[i] = bilinterm;
1731  perm[i] = i;
1732  }
1733  }
1734 
1735  /* update the adjacency information in the quadratic variable terms */
1736  for( v = 0; v < consdata->nquadvars; ++v )
1737  for( i = 0; i < consdata->quadvarterms[v].nadjbilin; ++i )
1738  consdata->quadvarterms[v].adjbilin[i] = invperm[consdata->quadvarterms[v].adjbilin[i]];
1739 
1740  consdata->bilinsorted = TRUE;
1741  assert(consdataCheckBilinTermsSort(consdata));
1742 
1743  /* free temporary memory */
1744  SCIPfreeBufferArray(scip, &invperm);
1745  SCIPfreeBufferArray(scip, &perm);
1746 
1747  return SCIP_OKAY;
1748 }
1749 
1750 /** moves a linear variable from one position to another */
1751 static
1753  SCIP_CONSDATA* consdata, /**< constraint data */
1754  int oldpos, /**< position of variable that shall be moved */
1755  int newpos /**< new position of variable */
1756  )
1757 {
1758  assert(consdata != NULL);
1759  assert(oldpos >= 0);
1760  assert(oldpos < consdata->nlinvars);
1761  assert(newpos >= 0);
1762  assert(newpos < consdata->linvarssize);
1763 
1764  if( newpos == oldpos )
1765  return;
1766 
1767  consdata->linvars [newpos] = consdata->linvars [oldpos];
1768  consdata->lincoefs[newpos] = consdata->lincoefs[oldpos];
1769 
1770  if( consdata->lineventdata != NULL )
1771  {
1772  assert(newpos >= consdata->nlinvars || consdata->lineventdata[newpos] == NULL);
1773 
1774  consdata->lineventdata[newpos] = consdata->lineventdata[oldpos];
1775  consdata->lineventdata[newpos]->varidx = newpos;
1776 
1777  consdata->lineventdata[oldpos] = NULL;
1778  }
1779 
1780  consdata->linvarssorted = FALSE;
1781 }
1782 
1783 /** moves a quadratic variable from one position to another */
1784 static
1786  SCIP_CONSDATA* consdata, /**< constraint data */
1787  int oldpos, /**< position of variable that shall be moved */
1788  int newpos /**< new position of variable */
1789  )
1790 {
1791  assert(consdata != NULL);
1792  assert(oldpos >= 0);
1793  assert(oldpos < consdata->nquadvars);
1794  assert(newpos >= 0);
1795  assert(newpos < consdata->quadvarssize);
1796 
1797  if( newpos == oldpos )
1798  return;
1799 
1800  assert(newpos >= consdata->nquadvars || consdata->quadvarterms[newpos].eventdata == NULL);
1801 
1802  consdata->quadvarterms[newpos] = consdata->quadvarterms[oldpos];
1803 
1804  if( consdata->quadvarterms[newpos].eventdata != NULL )
1805  {
1806  consdata->quadvarterms[newpos].eventdata->varidx = -newpos-1;
1807  consdata->quadvarterms[oldpos].eventdata = NULL;
1808  }
1809 
1810  consdata->quadvarssorted = FALSE;
1811 }
1812 
1813 /** adds linear coefficient in quadratic constraint */
1814 static
1816  SCIP* scip, /**< SCIP data structure */
1817  SCIP_CONS* cons, /**< quadratic constraint */
1818  SCIP_VAR* var, /**< variable of constraint entry */
1819  SCIP_Real coef /**< coefficient of constraint entry */
1820  )
1821 {
1822  SCIP_CONSDATA* consdata;
1823  SCIP_Bool transformed;
1824 
1825  assert(scip != NULL);
1826  assert(cons != NULL);
1827  assert(var != NULL);
1828 
1829  /* ignore coefficient if it is nearly zero */
1830  if( SCIPisZero(scip, coef) )
1831  return SCIP_OKAY;
1832 
1833  consdata = SCIPconsGetData(cons);
1834  assert(consdata != NULL);
1835 
1836  /* are we in the transformed problem? */
1837  transformed = SCIPconsIsTransformed(cons);
1838 
1839  /* always use transformed variables in transformed constraints */
1840  if( transformed )
1841  {
1842  SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
1843  }
1844  assert(var != NULL);
1845  assert(transformed == SCIPvarIsTransformed(var));
1846 
1847  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars+1) );
1848  consdata->linvars [consdata->nlinvars] = var;
1849  consdata->lincoefs[consdata->nlinvars] = coef;
1850 
1851  ++consdata->nlinvars;
1852 
1853  /* catch variable events */
1854  if( SCIPconsIsEnabled(cons) )
1855  {
1856  SCIP_CONSHDLR* conshdlr;
1857  SCIP_CONSHDLRDATA* conshdlrdata;
1858 
1859  /* get event handler */
1860  conshdlr = SCIPconsGetHdlr(cons);
1861  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1862  assert(conshdlrdata != NULL);
1863  assert(conshdlrdata->eventhdlr != NULL);
1864 
1865  assert(consdata->lineventdata != NULL);
1866  consdata->lineventdata[consdata->nlinvars-1] = NULL;
1867 
1868  /* catch bound change events of variable */
1869  SCIP_CALL( catchLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, consdata->nlinvars-1) );
1870  }
1871 
1872  /* invalidate activity information */
1873  consdata->activity = SCIP_INVALID;
1874  consdata->minlinactivity = SCIP_INVALID;
1875  consdata->maxlinactivity = SCIP_INVALID;
1876  consdata->minlinactivityinf = -1;
1877  consdata->maxlinactivityinf = -1;
1878 
1879  /* invalidate nonlinear row */
1880  if( consdata->nlrow != NULL )
1881  {
1882  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1883  }
1884 
1885  /* install rounding locks for new variable */
1886  SCIP_CALL( lockLinearVariable(scip, cons, var, coef) );
1887 
1888  /* capture new variable */
1889  SCIP_CALL( SCIPcaptureVar(scip, var) );
1890 
1891  consdata->ispropagated = FALSE;
1892  consdata->ispresolved = FALSE;
1893  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var)
1894  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
1895  if( consdata->nlinvars == 1 )
1896  consdata->linvarssorted = TRUE;
1897  else
1898  consdata->linvarssorted = consdata->linvarssorted && (SCIPvarCompare(consdata->linvars[consdata->nlinvars-2], consdata->linvars[consdata->nlinvars-1]) == -1);
1899  /* always set too FALSE since the new linear variable should be checked if already existing as quad var term */
1900  consdata->linvarsmerged = FALSE;
1901 
1902  return SCIP_OKAY;
1903 }
1904 
1905 /** deletes linear coefficient at given position from quadratic constraint data */
1906 static
1908  SCIP* scip, /**< SCIP data structure */
1909  SCIP_CONS* cons, /**< quadratic constraint */
1910  int pos /**< position of coefficient to delete */
1911  )
1912 {
1913  SCIP_CONSDATA* consdata;
1914  SCIP_VAR* var;
1915  SCIP_Real coef;
1916 
1917  assert(scip != NULL);
1918  assert(cons != NULL);
1919 
1920  consdata = SCIPconsGetData(cons);
1921  assert(consdata != NULL);
1922  assert(0 <= pos && pos < consdata->nlinvars);
1923 
1924  var = consdata->linvars[pos];
1925  coef = consdata->lincoefs[pos];
1926  assert(var != NULL);
1927 
1928  /* remove rounding locks for deleted variable */
1929  SCIP_CALL( unlockLinearVariable(scip, cons, var, coef) );
1930 
1931  /* if we catch variable events, drop the events on the variable */
1932  if( consdata->lineventdata != NULL )
1933  {
1934  SCIP_CONSHDLR* conshdlr;
1935  SCIP_CONSHDLRDATA* conshdlrdata;
1936 
1937  /* get event handler */
1938  conshdlr = SCIPconsGetHdlr(cons);
1939  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1940  assert(conshdlrdata != NULL);
1941  assert(conshdlrdata->eventhdlr != NULL);
1942 
1943  /* drop bound change events of variable */
1944  SCIP_CALL( dropLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
1945  }
1946 
1947  /* release variable */
1948  SCIP_CALL( SCIPreleaseVar(scip, &consdata->linvars[pos]) );
1949 
1950  /* move the last variable to the free slot */
1951  consdataMoveLinearVar(consdata, consdata->nlinvars-1, pos);
1952 
1953  --consdata->nlinvars;
1954 
1955  /* invalidate activity */
1956  consdata->activity = SCIP_INVALID;
1957  consdata->minlinactivity = SCIP_INVALID;
1958  consdata->maxlinactivity = SCIP_INVALID;
1959  consdata->minlinactivityinf = -1;
1960  consdata->maxlinactivityinf = -1;
1961 
1962  /* invalidate nonlinear row */
1963  if( consdata->nlrow != NULL )
1964  {
1965  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1966  }
1967 
1968  consdata->ispropagated = FALSE;
1969  consdata->ispresolved = FALSE;
1970 
1971  return SCIP_OKAY;
1972 }
1973 
1974 /** changes linear coefficient value at given position of quadratic constraint */
1975 static
1977  SCIP* scip, /**< SCIP data structure */
1978  SCIP_CONS* cons, /**< quadratic constraint */
1979  int pos, /**< position of linear coefficient to change */
1980  SCIP_Real newcoef /**< new value of linear coefficient */
1981  )
1982 {
1983  SCIP_CONSHDLR* conshdlr;
1984  SCIP_CONSHDLRDATA* conshdlrdata;
1985  SCIP_CONSDATA* consdata;
1986  SCIP_VAR* var;
1987  SCIP_Real coef;
1988 
1989  assert(scip != NULL);
1990  assert(cons != NULL);
1991  assert(!SCIPisZero(scip, newcoef));
1992 
1993  conshdlrdata = NULL;
1994 
1995  consdata = SCIPconsGetData(cons);
1996  assert(consdata != NULL);
1997  assert(0 <= pos);
1998  assert(pos < consdata->nlinvars);
1999  assert(!SCIPisZero(scip, newcoef));
2000 
2001  var = consdata->linvars[pos];
2002  coef = consdata->lincoefs[pos];
2003  assert(var != NULL);
2004  assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
2005 
2006  /* invalidate activity */
2007  consdata->activity = SCIP_INVALID;
2008  consdata->minlinactivity = SCIP_INVALID;
2009  consdata->maxlinactivity = SCIP_INVALID;
2010  consdata->minlinactivityinf = -1;
2011  consdata->maxlinactivityinf = -1;
2012 
2013  /* invalidate nonlinear row */
2014  if( consdata->nlrow != NULL )
2015  {
2016  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2017  }
2018 
2019  /* if necessary, remove the rounding locks and event catching of the variable */
2020  if( newcoef * coef < 0.0 )
2021  {
2022  if( SCIPconsIsLocked(cons) )
2023  {
2024  assert(SCIPconsIsTransformed(cons));
2025 
2026  /* remove rounding locks for variable with old coefficient */
2027  SCIP_CALL( unlockLinearVariable(scip, cons, var, coef) );
2028  }
2029 
2030  if( consdata->lineventdata[pos] != NULL )
2031  {
2032  /* get event handler */
2033  conshdlr = SCIPconsGetHdlr(cons);
2034  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2035  assert(conshdlrdata != NULL);
2036  assert(conshdlrdata->eventhdlr != NULL);
2037 
2038  /* drop bound change events of variable */
2039  SCIP_CALL( dropLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
2040  }
2041  }
2042 
2043  /* change the coefficient */
2044  consdata->lincoefs[pos] = newcoef;
2045 
2046  /* if necessary, install the rounding locks and event catching of the variable again */
2047  if( newcoef * coef < 0.0 )
2048  {
2049  if( SCIPconsIsLocked(cons) )
2050  {
2051  /* install rounding locks for variable with new coefficient */
2052  SCIP_CALL( lockLinearVariable(scip, cons, var, newcoef) );
2053  }
2054 
2055  if( conshdlrdata != NULL )
2056  {
2057  assert(SCIPconsIsEnabled(cons));
2058 
2059  /* catch bound change events of variable */
2060  SCIP_CALL( catchLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
2061  }
2062  }
2063 
2064  consdata->ispropagated = FALSE;
2065  consdata->ispresolved = FALSE;
2066 
2067  return SCIP_OKAY;
2068 }
2069 
2070 /** adds quadratic variable term to quadratic constraint */
2071 static
2073  SCIP* scip, /**< SCIP data structure */
2074  SCIP_CONS* cons, /**< quadratic constraint */
2075  SCIP_VAR* var, /**< variable to add */
2076  SCIP_Real lincoef, /**< linear coefficient of variable */
2077  SCIP_Real sqrcoef /**< square coefficient of variable */
2078  )
2079 {
2080  SCIP_CONSDATA* consdata;
2081  SCIP_Bool transformed;
2082  SCIP_QUADVARTERM* quadvarterm;
2083 
2084  assert(scip != NULL);
2085  assert(cons != NULL);
2086  assert(var != NULL);
2087 
2088  consdata = SCIPconsGetData(cons);
2089  assert(consdata != NULL);
2090 
2091  /* are we in the transformed problem? */
2092  transformed = SCIPconsIsTransformed(cons);
2093 
2094  /* always use transformed variables in transformed constraints */
2095  if( transformed )
2096  {
2097  SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
2098  }
2099  assert(var != NULL);
2100  assert(transformed == SCIPvarIsTransformed(var));
2101 
2102  SCIP_CALL( consdataEnsureQuadVarTermsSize(scip, consdata, consdata->nquadvars+1) );
2103 
2104  quadvarterm = &consdata->quadvarterms[consdata->nquadvars];
2105  quadvarterm->var = var;
2106  quadvarterm->lincoef = lincoef;
2107  quadvarterm->sqrcoef = sqrcoef;
2108  quadvarterm->adjbilinsize = 0;
2109  quadvarterm->nadjbilin = 0;
2110  quadvarterm->adjbilin = NULL;
2111  quadvarterm->eventdata = NULL;
2112 
2113  ++consdata->nquadvars;
2114 
2115  /* capture variable */
2116  SCIP_CALL( SCIPcaptureVar(scip, var) );
2117 
2118  /* catch variable events, if we do so */
2119  if( SCIPconsIsEnabled(cons) )
2120  {
2121  SCIP_CONSHDLR* conshdlr;
2122  SCIP_CONSHDLRDATA* conshdlrdata;
2123 
2124  /* get event handler */
2125  conshdlr = SCIPconsGetHdlr(cons);
2126  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2127  assert(conshdlrdata != NULL);
2128  assert(conshdlrdata->eventhdlr != NULL);
2129 
2130  /* catch bound change events of variable */
2131  SCIP_CALL( catchQuadVarEvents(scip, conshdlrdata->eventhdlr, cons, consdata->nquadvars-1) );
2132  }
2133 
2134  /* invalidate activity information */
2135  consdata->activity = SCIP_INVALID;
2136  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2137 
2138  /* invalidate nonlinear row */
2139  if( consdata->nlrow != NULL )
2140  {
2141  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2142  }
2143 
2144  /* install rounding locks for new variable */
2145  SCIP_CALL( lockQuadraticVariable(scip, cons, var) );
2146 
2147  consdata->ispropagated = FALSE;
2148  consdata->ispresolved = FALSE;
2149  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var)
2150  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
2151  if( consdata->nquadvars == 1 )
2152  consdata->quadvarssorted = TRUE;
2153  else
2154  consdata->quadvarssorted = consdata->quadvarssorted &&
2155  (SCIPvarCompare(consdata->quadvarterms[consdata->nquadvars-2].var, consdata->quadvarterms[consdata->nquadvars-1].var) == -1);
2156  /* also set to FALSE if nquadvars == 1, since the new variable should be checked for linearity and other stuff in mergeAndClean ... */
2157  consdata->quadvarsmerged = FALSE;
2158 
2159  consdata->iscurvchecked = FALSE;
2160 
2161  return SCIP_OKAY;
2162 }
2163 
2164 /** deletes quadratic variable term at given position from quadratic constraint data */
2165 static
2167  SCIP* scip, /**< SCIP data structure */
2168  SCIP_CONS* cons, /**< quadratic constraint */
2169  int pos /**< position of term to delete */
2170  )
2171 {
2172  SCIP_CONSDATA* consdata;
2173  SCIP_VAR* var;
2174 
2175  assert(scip != NULL);
2176  assert(cons != NULL);
2177 
2178  consdata = SCIPconsGetData(cons);
2179  assert(consdata != NULL);
2180  assert(0 <= pos && pos < consdata->nquadvars);
2181 
2182  var = consdata->quadvarterms[pos].var;
2183  assert(var != NULL);
2184  assert(consdata->quadvarterms[pos].nadjbilin == 0);
2185 
2186  /* remove rounding locks for deleted variable */
2187  SCIP_CALL( unlockQuadraticVariable(scip, cons, var) );
2188 
2189  /* if we catch variable events, drop the events on the variable */
2190  if( consdata->quadvarterms[pos].eventdata != NULL )
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  /* drop bound change events of variable */
2202  SCIP_CALL( dropQuadVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
2203  }
2204 
2205  /* release variable */
2206  SCIP_CALL( SCIPreleaseVar(scip, &consdata->quadvarterms[pos].var) );
2207 
2208  /* free adjacency array */
2209  SCIPfreeBlockMemoryArrayNull(scip, &consdata->quadvarterms[pos].adjbilin, consdata->quadvarterms[pos].adjbilinsize);
2210 
2211  /* move the last variable term to the free slot */
2212  consdataMoveQuadVarTerm(consdata, consdata->nquadvars-1, pos);
2213 
2214  --consdata->nquadvars;
2215 
2216  /* invalidate activity */
2217  consdata->activity = SCIP_INVALID;
2218  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2219 
2220  /* invalidate nonlinear row */
2221  if( consdata->nlrow != NULL )
2222  {
2223  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2224  }
2225 
2226  consdata->ispropagated = FALSE;
2227  consdata->ispresolved = FALSE;
2228  consdata->iscurvchecked = FALSE;
2229 
2230  return SCIP_OKAY;
2231 }
2232 
2233 /** replace variable in quadratic variable term at given position of quadratic constraint data
2234  *
2235  * Allows to replace x by coef*y+offset, thereby maintaining linear and square coefficients and bilinear terms.
2236  */
2237 static
2239  SCIP* scip, /**< SCIP data structure */
2240  SCIP_CONS* cons, /**< quadratic constraint */
2241  int pos, /**< position of term to replace */
2242  SCIP_VAR* var, /**< new variable */
2243  SCIP_Real coef, /**< linear coefficient of new variable */
2244  SCIP_Real offset /**< offset of new variable */
2245  )
2246 {
2247  SCIP_CONSDATA* consdata;
2248  SCIP_QUADVARTERM* quadvarterm;
2249  SCIP_EVENTHDLR* eventhdlr;
2250  SCIP_BILINTERM* bilinterm;
2251  SCIP_Real constant;
2252 
2253  int i;
2254  SCIP_VAR* var2;
2255 
2256  consdata = SCIPconsGetData(cons);
2257  assert(consdata != NULL);
2258  assert(pos >= 0);
2259  assert(pos < consdata->nquadvars);
2260 
2261  quadvarterm = &consdata->quadvarterms[pos];
2262 
2263  /* remove rounding locks for old variable */
2264  SCIP_CALL( unlockQuadraticVariable(scip, cons, quadvarterm->var) );
2265 
2266  /* if we catch variable events, drop the events on the old variable */
2267  if( quadvarterm->eventdata != NULL )
2268  {
2269  SCIP_CONSHDLR* conshdlr;
2270  SCIP_CONSHDLRDATA* conshdlrdata;
2271 
2272  /* get event handler */
2273  conshdlr = SCIPconsGetHdlr(cons);
2274  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2275  assert(conshdlrdata != NULL);
2276  assert(conshdlrdata->eventhdlr != NULL);
2277 
2278  eventhdlr = conshdlrdata->eventhdlr;
2279 
2280  /* drop bound change events of variable */
2281  SCIP_CALL( dropQuadVarEvents(scip, eventhdlr, cons, pos) );
2282  }
2283  else
2284  {
2285  eventhdlr = NULL;
2286  }
2287 
2288  /* compute constant and put into lhs/rhs */
2289  constant = quadvarterm->lincoef * offset + quadvarterm->sqrcoef * offset * offset;
2290  if( constant != 0.0 )
2291  {
2292  /* maintain constant part */
2293  if( !SCIPisInfinity(scip, -consdata->lhs) )
2294  consdata->lhs -= constant;
2295  if( !SCIPisInfinity(scip, consdata->rhs) )
2296  consdata->rhs -= constant;
2297  }
2298 
2299  /* update linear and square coefficient */
2300  quadvarterm->lincoef *= coef;
2301  quadvarterm->lincoef += 2.0 * quadvarterm->sqrcoef * coef * offset;
2302  quadvarterm->sqrcoef *= coef * coef;
2303 
2304  /* update bilinear terms */
2305  for( i = 0; i < quadvarterm->nadjbilin; ++i )
2306  {
2307  bilinterm = &consdata->bilinterms[quadvarterm->adjbilin[i]];
2308 
2309  if( bilinterm->var1 == quadvarterm->var )
2310  {
2311  bilinterm->var1 = var;
2312  var2 = bilinterm->var2;
2313  }
2314  else
2315  {
2316  assert(bilinterm->var2 == quadvarterm->var);
2317  bilinterm->var2 = var;
2318  var2 = bilinterm->var1;
2319  }
2320 
2321  if( var == var2 )
2322  {
2323  /* looks like we actually have a square term here */
2324  quadvarterm->lincoef += bilinterm->coef * offset;
2325  quadvarterm->sqrcoef += bilinterm->coef * coef;
2326  /* deleting bilinear terms is expensive, since it requires updating adjacency information
2327  * thus, for now we just set the coefficient to 0.0 and clear in later when the bilinear terms are merged */
2328  bilinterm->coef = 0.0;
2329  continue;
2330  }
2331 
2332  /* swap var1 and var2 if they are in wrong order */
2333  if( SCIPvarCompare(bilinterm->var1, bilinterm->var2) > 0 )
2334  {
2335  SCIP_VAR* tmp;
2336  tmp = bilinterm->var1;
2337  bilinterm->var1 = bilinterm->var2;
2338  bilinterm->var2 = tmp;
2339  }
2340  assert(SCIPvarCompare(bilinterm->var1, bilinterm->var2) == -1);
2341 
2342  if( offset != 0.0 )
2343  {
2344  /* need to find var2 and add offset*bilinterm->coef to linear coefficient */
2345  int var2pos;
2346 
2347  var2pos = 0;
2348  while( consdata->quadvarterms[var2pos].var != var2 )
2349  {
2350  ++var2pos;
2351  assert(var2pos < consdata->nquadvars);
2352  }
2353 
2354  consdata->quadvarterms[var2pos].lincoef += bilinterm->coef * offset;
2355  }
2356 
2357  bilinterm->coef *= coef;
2358  }
2359 
2360  /* release old variable */
2361  SCIP_CALL( SCIPreleaseVar(scip, &quadvarterm->var) );
2362 
2363  /* set new variable */
2364  quadvarterm->var = var;
2365 
2366  /* capture new variable */
2367  SCIP_CALL( SCIPcaptureVar(scip, quadvarterm->var) );
2368 
2369  /* catch variable events, if we do so */
2370  if( eventhdlr != NULL )
2371  {
2372  assert(SCIPconsIsEnabled(cons));
2373 
2374  /* catch bound change events of variable */
2375  SCIP_CALL( catchQuadVarEvents(scip, eventhdlr, cons, pos) );
2376  }
2377 
2378  /* invalidate activity information */
2379  consdata->activity = SCIP_INVALID;
2380  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2381 
2382  /* invalidate nonlinear row */
2383  if( consdata->nlrow != NULL )
2384  {
2385  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2386  }
2387 
2388  /* install rounding locks for new variable */
2389  SCIP_CALL( lockQuadraticVariable(scip, cons, var) );
2390 
2391  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var)
2392  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
2393  consdata->quadvarssorted = (consdata->nquadvars == 1);
2394  consdata->quadvarsmerged = FALSE;
2395  consdata->bilinsorted &= (quadvarterm->nadjbilin == 0); /*lint !e514*/
2396  consdata->bilinmerged &= (quadvarterm->nadjbilin == 0); /*lint !e514*/
2397 
2398  consdata->ispropagated = FALSE;
2399  consdata->ispresolved = FALSE;
2400  consdata->iscurvchecked = FALSE;
2401 
2402  return SCIP_OKAY;
2403 }
2404 
2405 /** adds a bilinear term to quadratic constraint */
2406 static
2408  SCIP* scip, /**< SCIP data structure */
2409  SCIP_CONS* cons, /**< quadratic constraint */
2410  int var1pos, /**< position of first variable in quadratic variables array */
2411  int var2pos, /**< position of second variable in quadratic variables array */
2412  SCIP_Real coef /**< coefficient of bilinear term */
2413  )
2414 {
2415  SCIP_CONSDATA* consdata;
2416  SCIP_BILINTERM* bilinterm;
2417 
2418  assert(scip != NULL);
2419  assert(cons != NULL);
2420 
2421  if( var1pos == var2pos )
2422  {
2423  SCIPerrorMessage("tried to add bilinear term where both variables are the same\n");
2424  return SCIP_INVALIDDATA;
2425  }
2426 
2427  consdata = SCIPconsGetData(cons);
2428  assert(consdata != NULL);
2429 
2430  /* check if the bilinear terms are sorted */
2431  assert(consdataCheckBilinTermsSort(consdata));
2432 
2433  assert(var1pos >= 0);
2434  assert(var1pos < consdata->nquadvars);
2435  assert(var2pos >= 0);
2436  assert(var2pos < consdata->nquadvars);
2437 
2438  SCIP_CALL( consdataEnsureBilinSize(scip, consdata, consdata->nbilinterms + 1) );
2439 
2440  bilinterm = &consdata->bilinterms[consdata->nbilinterms];
2441  if( SCIPvarCompare(consdata->quadvarterms[var1pos].var, consdata->quadvarterms[var2pos].var) < 0 )
2442  {
2443  bilinterm->var1 = consdata->quadvarterms[var1pos].var;
2444  bilinterm->var2 = consdata->quadvarterms[var2pos].var;
2445  }
2446  else
2447  {
2448  bilinterm->var1 = consdata->quadvarterms[var2pos].var;
2449  bilinterm->var2 = consdata->quadvarterms[var1pos].var;
2450  }
2451  bilinterm->coef = coef;
2452 
2453  if( bilinterm->var1 == bilinterm->var2 )
2454  {
2455  SCIPerrorMessage("tried to add bilinear term where both variables are the same, but appear at different positions in quadvarterms array\n");
2456  return SCIP_INVALIDDATA;
2457  }
2458  assert(SCIPvarCompare(bilinterm->var1, bilinterm->var2) == -1);
2459 
2460  SCIP_CALL( consdataEnsureAdjBilinSize(scip, &consdata->quadvarterms[var1pos], consdata->quadvarterms[var1pos].nadjbilin + 1) );
2461  SCIP_CALL( consdataEnsureAdjBilinSize(scip, &consdata->quadvarterms[var2pos], consdata->quadvarterms[var2pos].nadjbilin + 1) );
2462 
2463  consdata->quadvarterms[var1pos].adjbilin[consdata->quadvarterms[var1pos].nadjbilin] = consdata->nbilinterms;
2464  consdata->quadvarterms[var2pos].adjbilin[consdata->quadvarterms[var2pos].nadjbilin] = consdata->nbilinterms;
2465  ++consdata->quadvarterms[var1pos].nadjbilin;
2466  ++consdata->quadvarterms[var2pos].nadjbilin;
2467 
2468  ++consdata->nbilinterms;
2469 
2470  /* invalidate activity information */
2471  consdata->activity = SCIP_INVALID;
2472  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2473 
2474  /* invalidate nonlinear row */
2475  if( consdata->nlrow != NULL )
2476  {
2477  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2478  }
2479 
2480  consdata->ispropagated = FALSE;
2481  consdata->ispresolved = FALSE;
2482  if( consdata->nbilinterms == 1 )
2483  {
2484  consdata->bilinsorted = TRUE;
2485 
2486  /* we have to take care of the bilinear term in mergeAndCleanBilinearTerms() if the coefficient is zero */
2487  consdata->bilinmerged = !SCIPisZero(scip, consdata->bilinterms[0].coef);
2488  }
2489  else
2490  {
2491  consdata->bilinsorted = consdata->bilinsorted
2492  && (bilinTermComp(consdata, consdata->nbilinterms-2, consdata->nbilinterms-1) <= 0);
2493  consdata->bilinmerged = FALSE;
2494  }
2495 
2496  consdata->iscurvchecked = FALSE;
2497 
2498  /* check if the bilinear terms are sorted */
2499  assert(consdataCheckBilinTermsSort(consdata));
2500 
2501  return SCIP_OKAY;
2502 }
2503 
2504 /** removes a set of bilinear terms and updates adjacency information in quad var terms
2505  *
2506  * Note: this function sorts the given array termposs.
2507  */
2508 static
2510  SCIP* scip, /**< SCIP data structure */
2511  SCIP_CONS* cons, /**< quadratic constraint */
2512  int nterms, /**< number of terms to delete */
2513  int* termposs /**< indices of terms to delete */
2514  )
2515 {
2516  SCIP_CONSDATA* consdata;
2517  int* newpos;
2518  int i;
2519  int j;
2520  int offset;
2521 
2522  assert(scip != NULL);
2523  assert(cons != NULL);
2524  assert(nterms == 0 || termposs != NULL);
2525 
2526  if( nterms == 0 )
2527  return SCIP_OKAY;
2528 
2529  consdata = SCIPconsGetData(cons);
2530  assert(consdata != NULL);
2531 
2532  SCIPsortInt(termposs, nterms);
2533 
2534  SCIP_CALL( SCIPallocBufferArray(scip, &newpos, consdata->nbilinterms) );
2535 
2536  i = 0;
2537  offset = 0;
2538  for( j = 0; j < consdata->nbilinterms; ++j )
2539  {
2540  /* if j'th term is deleted, increase offset and continue */
2541  if( i < nterms && j == termposs[i] )
2542  {
2543  ++offset;
2544  ++i;
2545  newpos[j] = -1;
2546  continue;
2547  }
2548 
2549  /* otherwise, move it forward and remember new position */
2550  if( offset > 0 )
2551  consdata->bilinterms[j-offset] = consdata->bilinterms[j];
2552  newpos[j] = j - offset;
2553  }
2554  assert(offset == nterms);
2555 
2556  /* update adjacency and activity information in quad var terms */
2557  for( i = 0; i < consdata->nquadvars; ++i )
2558  {
2559  offset = 0;
2560  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
2561  {
2562  assert(consdata->quadvarterms[i].adjbilin[j] < consdata->nbilinterms);
2563  if( newpos[consdata->quadvarterms[i].adjbilin[j]] == -1 )
2564  {
2565  /* corresponding bilinear term was deleted, thus increase offset */
2566  ++offset;
2567  }
2568  else
2569  {
2570  /* update index of j'th bilinear term and store at position j-offset */
2571  consdata->quadvarterms[i].adjbilin[j-offset] = newpos[consdata->quadvarterms[i].adjbilin[j]];
2572  }
2573  }
2574  consdata->quadvarterms[i].nadjbilin -= offset;
2575  /* some bilinear term was removed, so invalidate activity bounds */
2576  }
2577 
2578  consdata->nbilinterms -= nterms;
2579 
2580  SCIPfreeBufferArray(scip, &newpos);
2581 
2582  /* some quad vars may be linear now */
2583  consdata->quadvarsmerged = FALSE;
2584 
2585  consdata->ispropagated = FALSE;
2586  consdata->ispresolved = FALSE;
2587  consdata->iscurvchecked = FALSE;
2588 
2589  /* invalidate activity */
2590  consdata->activity = SCIP_INVALID;
2591  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2592 
2593  /* invalidate nonlinear row */
2594  if( consdata->nlrow != NULL )
2595  {
2596  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2597  }
2598 
2599  return SCIP_OKAY;
2600 }
2601 
2602 /** merges quad var terms that correspond to the same variable and does additional cleanup
2603  *
2604  * If a quadratic variable terms is actually linear, makes a linear term out of it
2605  * also replaces squares of binary variables by the binary variables, i.e., adds sqrcoef to lincoef.
2606  */
2607 static
2609  SCIP* scip, /**< SCIP data structure */
2610  SCIP_CONS* cons /**< quadratic constraint */
2611  )
2612 {
2613  SCIP_QUADVARTERM* quadvarterm;
2614  SCIP_CONSDATA* consdata;
2615  int i;
2616  int j;
2617 
2618  assert(scip != NULL);
2619  assert(cons != NULL);
2620 
2621  consdata = SCIPconsGetData(cons);
2622 
2623  if( consdata->quadvarsmerged )
2624  return SCIP_OKAY;
2625 
2626  if( consdata->nquadvars == 0 )
2627  {
2628  consdata->quadvarsmerged = TRUE;
2629  return SCIP_OKAY;
2630  }
2631 
2632  i = 0;
2633  while( i < consdata->nquadvars )
2634  {
2635  /* make sure quad var terms are sorted (do this in every round, since we may move variables around) */
2636  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
2637 
2638  quadvarterm = &consdata->quadvarterms[i];
2639 
2640  for( j = i+1; j < consdata->nquadvars && consdata->quadvarterms[j].var == quadvarterm->var; ++j )
2641  {
2642  /* add quad var term j to current term i */
2643  quadvarterm->lincoef += consdata->quadvarterms[j].lincoef;
2644  quadvarterm->sqrcoef += consdata->quadvarterms[j].sqrcoef;
2645  if( consdata->quadvarterms[j].nadjbilin > 0 )
2646  {
2647  /* move adjacency information from j to i */
2648  SCIP_CALL( consdataEnsureAdjBilinSize(scip, quadvarterm, quadvarterm->nadjbilin + consdata->quadvarterms[j].nadjbilin) );
2649  BMScopyMemoryArray(&quadvarterm->adjbilin[quadvarterm->nadjbilin], consdata->quadvarterms[j].adjbilin, consdata->quadvarterms[j].nadjbilin); /*lint !e866*/
2650  quadvarterm->nadjbilin += consdata->quadvarterms[j].nadjbilin;
2651  consdata->quadvarterms[j].nadjbilin = 0;
2652  }
2653  consdata->quadvarterms[j].lincoef = 0.0;
2654  consdata->quadvarterms[j].sqrcoef = 0.0;
2655  /* mark that activity information in quadvarterm is not up to date anymore */
2656  }
2657 
2658  /* remove quad var terms i+1..j-1 backwards */
2659  for( j = j-1; j > i; --j )
2660  {
2661  SCIP_CALL( delQuadVarTermPos(scip, cons, j) );
2662  }
2663 
2664  /* for binary variables, x^2 = x
2665  * however, we may destroy convexity of a quadratic term that involves also bilinear terms
2666  * thus, we do this step only if the variable does not appear in any bilinear term */
2667  if( quadvarterm->sqrcoef != 0.0 && SCIPvarIsBinary(quadvarterm->var) && quadvarterm->nadjbilin == 0 )
2668  {
2669  SCIPdebugMsg(scip, "replace square of binary variable by itself: <%s>^2 --> <%s>\n", SCIPvarGetName(quadvarterm->var), SCIPvarGetName(quadvarterm->var));
2670  quadvarterm->lincoef += quadvarterm->sqrcoef;
2671  quadvarterm->sqrcoef = 0.0;
2672 
2673  /* invalidate nonlinear row */
2674  if( consdata->nlrow != NULL )
2675  {
2676  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2677  }
2678  }
2679 
2680  /* if its 0.0 or linear, get rid of it */
2681  if( SCIPisZero(scip, quadvarterm->sqrcoef) && quadvarterm->nadjbilin == 0 )
2682  {
2683  if( !SCIPisZero(scip, quadvarterm->lincoef) )
2684  {
2685  /* seem to be a linear term now, thus add as linear term */
2686  SCIP_CALL( addLinearCoef(scip, cons, quadvarterm->var, quadvarterm->lincoef) );
2687  }
2688  /* remove term at pos i */
2689  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
2690  }
2691  else
2692  {
2693  ++i;
2694  }
2695  }
2696 
2697  consdata->quadvarsmerged = TRUE;
2698  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2699 
2700  return SCIP_OKAY;
2701 }
2702 
2703 /** merges entries with same linear variable into one entry and cleans up entries with coefficient 0.0 */
2704 static
2706  SCIP* scip, /**< SCIP data structure */
2707  SCIP_CONS* cons /**< quadratic constraint */
2708  )
2709 {
2710  SCIP_CONSDATA* consdata;
2711  SCIP_Real newcoef;
2712  int i;
2713  int j;
2714  int qvarpos;
2715 
2716  assert(scip != NULL);
2717  assert(cons != NULL);
2718 
2719  consdata = SCIPconsGetData(cons);
2720 
2721  if( consdata->linvarsmerged )
2722  return SCIP_OKAY;
2723 
2724  if( consdata->nlinvars == 0 )
2725  {
2726  consdata->linvarsmerged = TRUE;
2727  return SCIP_OKAY;
2728  }
2729 
2730  i = 0;
2731  while( i < consdata->nlinvars )
2732  {
2733  /* make sure linear variables are sorted (do this in every round, since we may move variables around) */
2734  consdataSortLinearVars(consdata);
2735 
2736  /* sum up coefficients that correspond to variable i */
2737  newcoef = consdata->lincoefs[i];
2738  for( j = i+1; j < consdata->nlinvars && consdata->linvars[i] == consdata->linvars[j]; ++j )
2739  newcoef += consdata->lincoefs[j];
2740  /* delete the additional variables in backward order */
2741  for( j = j-1; j > i; --j )
2742  {
2743  SCIP_CALL( delLinearCoefPos(scip, cons, j) );
2744  }
2745 
2746  /* check if there is already a quadratic variable term with this variable */
2747  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->linvars[i], &qvarpos) );
2748  if( qvarpos >= 0)
2749  {
2750  /* add newcoef to linear coefficient of quadratic variable and mark linear variable as to delete */
2751  assert(qvarpos < consdata->nquadvars);
2752  assert(consdata->quadvarterms[qvarpos].var == consdata->linvars[i]);
2753  consdata->quadvarterms[qvarpos].lincoef += newcoef;
2754  newcoef = 0.0;
2755  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2756  }
2757 
2758  /* delete also entry at position i, if it became zero (or was zero before) */
2759  if( SCIPisZero(scip, newcoef) )
2760  {
2761  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
2762  }
2763  else
2764  {
2765  SCIP_CALL( chgLinearCoefPos(scip, cons, i, newcoef) );
2766  ++i;
2767  }
2768  }
2769 
2770  consdata->linvarsmerged = TRUE;
2771 
2772  return SCIP_OKAY;
2773 }
2774 
2775 /** merges bilinear terms with same variables into a single term, removes bilinear terms with coefficient 0.0 */
2776 static
2778  SCIP* scip, /**< SCIP data structure */
2779  SCIP_CONS* cons /**< quadratic constraint */
2780  )
2781 {
2782  SCIP_CONSDATA* consdata;
2783  SCIP_BILINTERM* bilinterm;
2784  int i;
2785  int j;
2786  int* todelete;
2787  int ntodelete;
2788 
2789  assert(scip != NULL);
2790  assert(cons != NULL);
2791 
2792  consdata = SCIPconsGetData(cons);
2793 
2794  /* check if the bilinear terms are sorted */
2795  assert(consdataCheckBilinTermsSort(consdata));
2796 
2797  if( consdata->bilinmerged )
2798  return SCIP_OKAY;
2799 
2800  if( consdata->nbilinterms == 0 )
2801  {
2802  consdata->bilinmerged = TRUE;
2803  return SCIP_OKAY;
2804  }
2805 
2806  /* alloc memory for array of terms that need to be deleted finally */
2807  ntodelete = 0;
2808  SCIP_CALL( SCIPallocBufferArray(scip, &todelete, consdata->nbilinterms) );
2809 
2810  /* make sure bilinear terms are sorted */
2811  SCIP_CALL( consdataSortBilinTerms(scip, consdata) );
2812 
2813  i = 0;
2814  while( i < consdata->nbilinterms )
2815  {
2816  bilinterm = &consdata->bilinterms[i];
2817 
2818  /* sum up coefficients that correspond to same variables as term i */
2819  for( j = i+1; j < consdata->nbilinterms && bilinterm->var1 == consdata->bilinterms[j].var1 && bilinterm->var2 == consdata->bilinterms[j].var2; ++j )
2820  {
2821  bilinterm->coef += consdata->bilinterms[j].coef;
2822  todelete[ntodelete++] = j;
2823  }
2824 
2825  /* delete also entry at position i, if it became zero (or was zero before) */
2826  if( SCIPisZero(scip, bilinterm->coef) )
2827  {
2828  todelete[ntodelete++] = i;
2829  }
2830 
2831  /* continue with term after the current series */
2832  i = j;
2833  }
2834 
2835  /* delete bilinear terms */
2836  SCIP_CALL( removeBilinearTermsPos(scip, cons, ntodelete, todelete) );
2837 
2838  SCIPfreeBufferArray(scip, &todelete);
2839 
2840  consdata->bilinmerged = TRUE;
2841 
2842  /* check if the bilinear terms are sorted */
2843  assert(consdataCheckBilinTermsSort(consdata));
2844 
2845  return SCIP_OKAY;
2846 }
2847 
2848 /** removes fixes (or aggregated) variables from a quadratic constraint */
2849 static
2851  SCIP* scip, /**< SCIP data structure */
2852  SCIP_CONS* cons /**< quadratic constraint */
2853  )
2854 {
2855  SCIP_CONSDATA* consdata;
2856  SCIP_BILINTERM* bilinterm;
2857  SCIP_Real bilincoef;
2858  SCIP_Real coef;
2859  SCIP_Real offset;
2860  SCIP_VAR* var;
2861  SCIP_VAR* var2;
2862  int var2pos;
2863  int i;
2864  int j;
2865  int k;
2866 
2867  SCIP_Bool have_change;
2868 
2869  assert(scip != NULL);
2870  assert(cons != NULL);
2871 
2872  consdata = SCIPconsGetData(cons);
2873 
2874  have_change = FALSE;
2875  i = 0;
2876  while( i < consdata->nlinvars )
2877  {
2878  var = consdata->linvars[i];
2879 
2880  if( SCIPvarIsActive(var) && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
2881  {
2882  ++i;
2883  continue;
2884  }
2885 
2886  have_change = TRUE;
2887 
2888  coef = consdata->lincoefs[i];
2889  offset = 0.0;
2890 
2891  if( SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
2892  {
2893  offset = coef * (SCIPvarGetLbGlobal(var) + SCIPvarGetUbGlobal(var)) / 2.0;
2894  coef = 0.0;
2895  }
2896  else
2897  {
2898  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &coef, &offset) );
2899  }
2900 
2901  SCIPdebugMsg(scip, " linear term %g*<%s> is replaced by %g * <%s> + %g\n", consdata->lincoefs[i], SCIPvarGetName(consdata->linvars[i]),
2902  coef, SCIPvarGetName(var), offset);
2903 
2904  /* delete previous variable (this will move another variable to position i) */
2905  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
2906 
2907  /* put constant part into bounds */
2908  if( offset != 0.0 )
2909  {
2910  if( !SCIPisInfinity(scip, -consdata->lhs) )
2911  consdata->lhs -= offset;
2912  if( !SCIPisInfinity(scip, consdata->rhs) )
2913  consdata->rhs -= offset;
2914  }
2915 
2916  /* nothing left to do if variable had been fixed */
2917  if( coef == 0.0 )
2918  continue;
2919 
2920  /* if GetProbvar gave a linear variable, just add it
2921  * if it's a multilinear variable, add it's disaggregated variables */
2922  if( SCIPvarIsActive(var) )
2923  {
2924  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
2925  }
2926  else
2927  {
2928  int naggrs;
2929  SCIP_VAR** aggrvars;
2930  SCIP_Real* aggrscalars;
2931  SCIP_Real aggrconstant;
2932 
2933  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
2934 
2935  naggrs = SCIPvarGetMultaggrNVars(var);
2936  aggrvars = SCIPvarGetMultaggrVars(var);
2937  aggrscalars = SCIPvarGetMultaggrScalars(var);
2938  aggrconstant = SCIPvarGetMultaggrConstant(var);
2939 
2940  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars + naggrs) );
2941 
2942  for( j = 0; j < naggrs; ++j )
2943  {
2944  SCIP_CALL( addLinearCoef(scip, cons, aggrvars[j], coef * aggrscalars[j]) );
2945  }
2946 
2947  if( aggrconstant != 0.0 )
2948  {
2949  if( !SCIPisInfinity(scip, -consdata->lhs) )
2950  consdata->lhs -= coef * aggrconstant;
2951  if( !SCIPisInfinity(scip, consdata->rhs) )
2952  consdata->rhs -= coef * aggrconstant;
2953  }
2954  }
2955  }
2956 
2957  i = 0;
2958  while( i < consdata->nquadvars )
2959  {
2960  var = consdata->quadvarterms[i].var;
2961 
2962  if( SCIPvarIsActive(var) && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
2963  {
2964  ++i;
2965  continue;
2966  }
2967 
2968  have_change = TRUE;
2969 
2970  coef = 1.0;
2971  offset = 0.0;
2972 
2973  if( !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
2974  {
2975  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &coef, &offset) );
2976  }
2977  else
2978  {
2979  coef = 0.0;
2980  offset = (SCIPvarGetLbGlobal(var) + SCIPvarGetUbGlobal(var)) / 2.0;
2981  }
2982 
2983  SCIPdebugMsg(scip, " quadratic variable <%s> with status %d is replaced by %g * <%s> + %g\n", SCIPvarGetName(consdata->quadvarterms[i].var),
2984  SCIPvarGetStatus(consdata->quadvarterms[i].var), coef, SCIPvarGetName(var), offset);
2985 
2986  /* handle fixed variable */
2987  if( coef == 0.0 )
2988  {
2989  /* if not fixed to 0.0, add to linear coefs of vars in bilinear terms, and deal with linear and square term as constant */
2990  if( offset != 0.0 )
2991  {
2992  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
2993  {
2994  bilinterm = &consdata->bilinterms[consdata->quadvarterms[i].adjbilin[j]];
2995 
2996  var2 = bilinterm->var1 == consdata->quadvarterms[i].var ? bilinterm->var2 : bilinterm->var1;
2997  assert(var2 != consdata->quadvarterms[i].var);
2998 
2999  var2pos = 0;
3000  while( consdata->quadvarterms[var2pos].var != var2 )
3001  {
3002  ++var2pos;
3003  assert(var2pos < consdata->nquadvars);
3004  }
3005  consdata->quadvarterms[var2pos].lincoef += bilinterm->coef * offset;
3006  }
3007 
3008  offset = consdata->quadvarterms[i].lincoef * offset + consdata->quadvarterms[i].sqrcoef * offset * offset;
3009  if( !SCIPisInfinity(scip, -consdata->lhs) )
3010  consdata->lhs -= offset;
3011  if( !SCIPisInfinity(scip, consdata->rhs) )
3012  consdata->rhs -= offset;
3013  }
3014 
3015  /* remove bilinear terms */
3016  SCIP_CALL( removeBilinearTermsPos(scip, cons, consdata->quadvarterms[i].nadjbilin, consdata->quadvarterms[i].adjbilin) );
3017 
3018  /* delete quad. var term i */
3019  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
3020 
3021  continue;
3022  }
3023 
3024  assert(var != NULL);
3025 
3026  /* if GetProbvar gave an active variable, replace the quad var term so that it uses the new variable */
3027  if( SCIPvarIsActive(var) )
3028  {
3029  /* replace x by coef*y+offset */
3030  SCIP_CALL( replaceQuadVarTermPos(scip, cons, i, var, coef, offset) );
3031 
3032  continue;
3033  }
3034  else
3035  {
3036  /* if GetProbVar gave a multi-aggregated variable, add new quad var terms and new bilinear terms
3037  * x is replaced by coef * (sum_i a_ix_i + b) + offset
3038  * lcoef * x + scoef * x^2 + bcoef * x * y ->
3039  * (b*coef + offset) * (lcoef + (b*coef + offset) * scoef)
3040  * + sum_i a_i*coef * (lcoef + 2 (b*coef + offset) * scoef) x_i
3041  * + sum_i (a_i*coef)^2 * scoef * x_i^2
3042  * + 2 sum_{i,j, i<j} (a_i a_j coef^2 scoef) x_i x_j
3043  * + bcoef * (b*coef + offset + coef * sum_i a_ix_i) y
3044  */
3045  int naggrs;
3046  SCIP_VAR** aggrvars; /* x_i */
3047  SCIP_Real* aggrscalars; /* a_i */
3048  SCIP_Real aggrconstant; /* b */
3049  int nquadtermsold;
3050 
3051  SCIP_Real lcoef;
3052  SCIP_Real scoef;
3053 
3054  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
3055 
3056  naggrs = SCIPvarGetMultaggrNVars(var);
3057  aggrvars = SCIPvarGetMultaggrVars(var);
3058  aggrscalars = SCIPvarGetMultaggrScalars(var);
3059  aggrconstant = SCIPvarGetMultaggrConstant(var);
3060 
3061  lcoef = consdata->quadvarterms[i].lincoef;
3062  scoef = consdata->quadvarterms[i].sqrcoef;
3063 
3064  nquadtermsold = consdata->nquadvars;
3065 
3066  SCIP_CALL( consdataEnsureQuadVarTermsSize(scip, consdata, consdata->nquadvars + naggrs) );
3067 
3068  /* take care of constant part */
3069  if( aggrconstant != 0.0 || offset != 0.0 )
3070  {
3071  SCIP_Real constant;
3072  constant = (aggrconstant * coef + offset) * (lcoef + (aggrconstant * coef + offset) * scoef);
3073  if( !SCIPisInfinity(scip, -consdata->lhs) )
3074  consdata->lhs -= constant;
3075  if( !SCIPisInfinity(scip, consdata->rhs) )
3076  consdata->rhs -= constant;
3077  }
3078 
3079  /* add x_i's with linear and square coefficients */
3080  for( j = 0; j < naggrs; ++j )
3081  {
3082  SCIP_CALL( addQuadVarTerm(scip, cons, aggrvars[j],
3083  coef * aggrscalars[j] * (lcoef + 2.0 * scoef * (coef * aggrconstant + offset)),
3084  coef * coef * aggrscalars[j] * aggrscalars[j] * scoef) );
3085  }
3086 
3087  /* ensure space for bilinear terms */
3088  SCIP_CALL( consdataEnsureBilinSize(scip, consdata, consdata->nquadvars + (scoef != 0.0 ? (naggrs * (naggrs-1))/2 : 0) + consdata->quadvarterms[j].nadjbilin * naggrs) );
3089 
3090  /* add x_j*x_k's */
3091  if( scoef != 0.0 )
3092  {
3093  for( j = 0; j < naggrs; ++j )
3094  for( k = 0; k < j; ++k )
3095  {
3096  assert(aggrvars[j] != aggrvars[k]);
3097  SCIP_CALL( addBilinearTerm(scip, cons, nquadtermsold + j, nquadtermsold + k,
3098  2.0 * aggrscalars[j] * aggrscalars[k] * coef * coef * scoef) );
3099  }
3100  }
3101 
3102  /* add x_i*y's */
3103  for( k = 0; k < consdata->quadvarterms[i].nadjbilin; ++k )
3104  {
3105  bilinterm = &consdata->bilinterms[consdata->quadvarterms[i].adjbilin[k]];
3106  bilincoef = bilinterm->coef; /* copy coef, as bilinterm pointer may become invalid by realloc in addBilinearTerm() below */
3107  var2 = (bilinterm->var1 == consdata->quadvarterms[i].var) ? bilinterm->var2 : bilinterm->var1;
3108  assert(var2 != consdata->quadvarterms[i].var);
3109 
3110  /* this is not efficient, but we cannot sort the quadratic terms here, since we currently iterate over them */
3111  var2pos = 0;
3112  while( consdata->quadvarterms[var2pos].var != var2 )
3113  {
3114  ++var2pos;
3115  assert(var2pos < consdata->nquadvars);
3116  }
3117 
3118  for( j = 0; j < naggrs; ++j )
3119  {
3120  if( aggrvars[j] == var2 )
3121  { /* x_i == y, so we have a square term here */
3122  consdata->quadvarterms[var2pos].sqrcoef += bilincoef * coef * aggrscalars[j];
3123  }
3124  else
3125  { /* x_i != y, so we need to add a bilinear term here */
3126  SCIP_CALL( addBilinearTerm(scip, cons, nquadtermsold + j, var2pos, bilincoef * coef * aggrscalars[j]) );
3127  }
3128  }
3129 
3130  consdata->quadvarterms[var2pos].lincoef += bilincoef * (aggrconstant * coef + offset);
3131  }
3132 
3133  /* remove bilinear terms */
3134  SCIP_CALL( removeBilinearTermsPos(scip, cons, consdata->quadvarterms[i].nadjbilin, consdata->quadvarterms[i].adjbilin) );
3135 
3136  /* delete quad. var term i */
3137  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
3138  }
3139  }
3140 
3141  consdata->isremovedfixings = TRUE;
3142 
3143  SCIPdebugMsg(scip, "removed fixations from <%s>\n -> ", SCIPconsGetName(cons));
3144  SCIPdebugPrintCons(scip, cons, NULL);
3145 
3146 #ifndef NDEBUG
3147  for( i = 0; i < consdata->nlinvars; ++i )
3148  assert(SCIPvarIsActive(consdata->linvars[i]));
3149 
3150  for( i = 0; i < consdata->nquadvars; ++i )
3151  assert(SCIPvarIsActive(consdata->quadvarterms[i].var));
3152 #endif
3153 
3154  if( !have_change )
3155  return SCIP_OKAY;
3156 
3157  /* some quadratic variable may have been replaced by an already existing linear variable
3158  * in this case, we want the linear variable to be removed, which happens in mergeAndCleanLinearVars
3159  */
3160  consdata->linvarsmerged = FALSE;
3161 
3162  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
3163  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, cons) );
3164  SCIP_CALL( mergeAndCleanLinearVars(scip, cons) );
3165 
3166 #ifndef NDEBUG
3167  for( i = 0; i < consdata->nbilinterms; ++i )
3168  {
3169  assert(consdata->bilinterms[i].var1 != consdata->bilinterms[i].var2);
3170  assert(consdata->bilinterms[i].coef != 0.0);
3171  assert(SCIPvarCompare(consdata->bilinterms[i].var1, consdata->bilinterms[i].var2) < 0);
3172  }
3173 #endif
3174 
3175  return SCIP_OKAY;
3176 }
3177 
3178 /** create a nonlinear row representation of the constraint and stores them in consdata */
3179 static
3181  SCIP* scip, /**< SCIP data structure */
3182  SCIP_CONS* cons /**< quadratic constraint */
3183  )
3184 {
3185  SCIP_CONSDATA* consdata;
3186  int nquadvars; /* number of variables in quadratic terms */
3187  SCIP_VAR** quadvars; /* variables in quadratic terms */
3188  int nquadelems; /* number of quadratic elements (square and bilinear terms) */
3189  SCIP_QUADELEM* quadelems; /* quadratic elements (square and bilinear terms) */
3190  int nquadlinterms; /* number of linear terms using variables that are in quadratic terms */
3191  SCIP_VAR** quadlinvars; /* variables of linear terms using variables that are in quadratic terms */
3192  SCIP_Real* quadlincoefs; /* coefficients of linear terms using variables that are in quadratic terms */
3193  int i;
3194  int idx1;
3195  int idx2;
3196  int lincnt;
3197  int elcnt;
3198  SCIP_VAR* lastvar;
3199  int lastvaridx;
3200  SCIP_EXPRCURV curvature;
3201 
3202  assert(scip != NULL);
3203  assert(cons != NULL);
3204 
3205  consdata = SCIPconsGetData(cons);
3206  assert(consdata != NULL);
3207 
3208  if( consdata->nlrow != NULL )
3209  {
3210  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3211  }
3212 
3213  nquadvars = consdata->nquadvars;
3214  nquadelems = consdata->nbilinterms;
3215  nquadlinterms = 0;
3216  for( i = 0; i < nquadvars; ++i )
3217  {
3218  if( consdata->quadvarterms[i].sqrcoef != 0.0 )
3219  ++nquadelems;
3220  if( !SCIPisZero(scip, consdata->quadvarterms[i].lincoef) )
3221  ++nquadlinterms;
3222  }
3223 
3224  SCIP_CALL( SCIPallocBufferArray(scip, &quadvars, nquadvars) );
3225  SCIP_CALL( SCIPallocBufferArray(scip, &quadelems, nquadelems) );
3226  SCIP_CALL( SCIPallocBufferArray(scip, &quadlinvars, nquadlinterms) );
3227  SCIP_CALL( SCIPallocBufferArray(scip, &quadlincoefs, nquadlinterms) );
3228 
3229  lincnt = 0;
3230  elcnt = 0;
3231  for( i = 0; i < nquadvars; ++i )
3232  {
3233  quadvars[i] = consdata->quadvarterms[i].var;
3234 
3235  if( consdata->quadvarterms[i].sqrcoef != 0.0 )
3236  {
3237  assert(elcnt < nquadelems);
3238  quadelems[elcnt].idx1 = i;
3239  quadelems[elcnt].idx2 = i;
3240  quadelems[elcnt].coef = consdata->quadvarterms[i].sqrcoef;
3241  ++elcnt;
3242  }
3243 
3244  if( !SCIPisZero(scip, consdata->quadvarterms[i].lincoef) )
3245  {
3246  assert(lincnt < nquadlinterms);
3247  quadlinvars [lincnt] = consdata->quadvarterms[i].var;
3248  quadlincoefs[lincnt] = consdata->quadvarterms[i].lincoef;
3249  ++lincnt;
3250  }
3251  }
3252  assert(lincnt == nquadlinterms);
3253 
3254  /* bilinear terms are sorted first by first variable, then by second variable
3255  * 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 */
3256  lastvar = NULL;
3257  lastvaridx = -1;
3258  for( i = 0; i < consdata->nbilinterms; ++i )
3259  {
3260  if( lastvar == consdata->bilinterms[i].var1 )
3261  {
3262  assert(lastvaridx >= 0);
3263  assert(consdata->quadvarterms[lastvaridx].var == consdata->bilinterms[i].var1);
3264  }
3265  else
3266  {
3267  lastvar = consdata->bilinterms[i].var1;
3268  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, lastvar, &lastvaridx) );
3269  }
3270  idx1 = lastvaridx;
3271 
3272  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->bilinterms[i].var2, &idx2) );
3273 
3274  assert(elcnt < nquadelems);
3275  quadelems[elcnt].idx1 = MIN(idx1, idx2);
3276  quadelems[elcnt].idx2 = MAX(idx1, idx2);
3277  quadelems[elcnt].coef = consdata->bilinterms[i].coef;
3278  ++elcnt;
3279  }
3280  assert(elcnt == nquadelems);
3281 
3282  /* set curvature for the nonlinear row */
3283  if( consdata->isconcave && consdata->isconvex )
3284  {
3285  assert(consdata->nbilinterms == 0 && consdata->nquadvars == 0);
3286  curvature = SCIP_EXPRCURV_LINEAR;
3287  }
3288  else if( consdata->isconcave )
3289  curvature = SCIP_EXPRCURV_CONCAVE;
3290  else if( consdata->isconvex )
3291  curvature = SCIP_EXPRCURV_CONVEX;
3292  else
3293  curvature = SCIP_EXPRCURV_UNKNOWN;
3294 
3295  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
3296  consdata->nlinvars, consdata->linvars, consdata->lincoefs,
3297  nquadvars, quadvars, nquadelems, quadelems,
3298  NULL, consdata->lhs, consdata->rhs,
3299  curvature) );
3300 
3301  SCIP_CALL( SCIPaddLinearCoefsToNlRow(scip, consdata->nlrow, nquadlinterms, quadlinvars, quadlincoefs) );
3302 
3303  SCIPfreeBufferArray(scip, &quadlincoefs);
3304  SCIPfreeBufferArray(scip, &quadlinvars);
3305  SCIPfreeBufferArray(scip, &quadelems);
3306  SCIPfreeBufferArray(scip, &quadvars);
3307 
3308  return SCIP_OKAY;
3309 }
3310 
3311 /** solve constraint as presolving */
3312 static
3314  SCIP* scip, /**< SCIP data structure */
3315  SCIP_CONS* cons, /**< constraint */
3316  SCIP_RESULT* result, /**< to store result of solve: cutoff, success, or do-not-find */
3317  SCIP_Bool* redundant, /**< to store whether constraint is redundant now (should be deleted) */
3318  int* naggrvars /**< counter on number of variable aggregations */
3319  )
3320 {
3321  SCIP_CONSDATA* consdata;
3322 
3323  assert(scip != NULL);
3324  assert(cons != NULL);
3325  assert(result != NULL);
3326  assert(redundant != NULL);
3327 
3328  *result = SCIP_DIDNOTFIND;
3329  *redundant = FALSE;
3330 
3331  consdata = SCIPconsGetData(cons);
3332  assert(consdata != NULL);
3333 
3334  /* if constraint is an equality with two variables, at least one of them binary,
3335  * and linear after fixing the binary, then we can aggregate the variables */
3336  if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) && consdata->nlinvars == 0 && consdata->nquadvars == 2 &&
3337  ((SCIPvarIsBinary(consdata->quadvarterms[0].var) && consdata->quadvarterms[1].sqrcoef == 0.0) ||
3338  (SCIPvarIsBinary(consdata->quadvarterms[1].var) && consdata->quadvarterms[0].sqrcoef == 0.0)) )
3339  {
3340  SCIP_Bool infeasible;
3341  SCIP_Bool aggregated;
3342  SCIP_Real a;
3343  SCIP_Real b;
3344  SCIP_Real c;
3345  SCIP_VAR* x;
3346  SCIP_VAR* y;
3347  int binvaridx;
3348 
3349  /* constraint is a*(x+x^2) + b*y + c*x*y = rhs, with x binary variable
3350  * x = 0 -> b*y == rhs
3351  * x = 1 -> (b+c)*y == rhs - a
3352  *
3353  * 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
3354  */
3355 
3356  binvaridx = (SCIPvarIsBinary(consdata->quadvarterms[0].var) && consdata->quadvarterms[1].sqrcoef == 0.0) ? 0 : 1;
3357 
3358  x = consdata->quadvarterms[binvaridx].var;
3359  a = consdata->quadvarterms[binvaridx].sqrcoef + consdata->quadvarterms[binvaridx].lincoef;
3360 
3361  y = consdata->quadvarterms[1-binvaridx].var;
3362  b = consdata->quadvarterms[1-binvaridx].lincoef;
3363 
3364  assert(consdata->nbilinterms <= 1); /* should actually be 1, since constraint is otherwise linear */
3365  c = (consdata->nbilinterms == 1) ? consdata->bilinterms[0].coef : 0.0;
3366 
3367  if( !SCIPisZero(scip, b) && !SCIPisZero(scip, b+c) )
3368  {
3369  SCIPdebugMsg(scip, "<%s> = 0 -> %g*<%s> = %g and <%s> = 1 -> %g*<%s> = %g\n", SCIPvarGetName(x), b, SCIPvarGetName(y), consdata->rhs,
3370  SCIPvarGetName(x), b+c, SCIPvarGetName(y), consdata->rhs - a);
3371  SCIPdebugMsg(scip, "=> attempt aggregation <%s> = %g*<%s> + %g\n", SCIPvarGetName(y), (consdata->rhs-a)/(b+c) - consdata->rhs/b,
3372  SCIPvarGetName(x), consdata->rhs/b);
3373 
3374  SCIP_CALL( SCIPaggregateVars(scip, x, y, (consdata->rhs-a)/(b+c) - consdata->rhs/b, -1.0, -consdata->rhs/b, &infeasible, redundant, &aggregated) );
3375  if( infeasible )
3376  *result = SCIP_CUTOFF;
3377  else if( *redundant || aggregated )
3378  {
3379  /* aggregated (or were already aggregated), so constraint is now redundant */
3380  *result = SCIP_SUCCESS;
3381  *redundant = TRUE;
3382 
3383  if( aggregated )
3384  ++*naggrvars;
3385  }
3386  }
3387 
3388  /* @todo if b is 0 or b+c is 0, or lhs != rhs, then could replace by varbound constraint */
3389  }
3390 
3391  return SCIP_OKAY;
3392 }
3393 
3394 
3395 /** reformulates products of binary variables as AND constraint
3396  *
3397  * 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.
3398  */
3399 static
3401  SCIP* scip, /**< SCIP data structure */
3402  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3403  SCIP_CONS* cons, /**< constraint */
3404  int* naddconss /**< buffer where to add the number of AND constraints added */
3405  )
3406 {
3407  SCIP_CONSHDLRDATA* conshdlrdata;
3408  SCIP_CONSDATA* consdata;
3409  char name[SCIP_MAXSTRLEN];
3410  SCIP_VAR* vars[2];
3411  SCIP_VAR* auxvar;
3412  SCIP_CONS* andcons;
3413  int i;
3414  int ntodelete;
3415  int* todelete;
3416 
3417  assert(scip != NULL);
3418  assert(conshdlr != NULL);
3419  assert(cons != NULL);
3420  assert(naddconss != NULL);
3421 
3422  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3423  assert(conshdlrdata != NULL);
3424 
3425  /* if user does not like AND very much, then return */
3426  if( conshdlrdata->empathy4and < 2 )
3427  return SCIP_OKAY;
3428 
3429  consdata = SCIPconsGetData(cons);
3430  assert(consdata != NULL);
3431 
3432  if( consdata->nbilinterms == 0 )
3433  return SCIP_OKAY;
3434 
3435  /* get array to store indices of bilinear terms that shall be deleted */
3436  SCIP_CALL( SCIPallocBufferArray(scip, &todelete, consdata->nbilinterms) );
3437  ntodelete = 0;
3438 
3439  for( i = 0; i < consdata->nbilinterms; ++i )
3440  {
3441  vars[0] = consdata->bilinterms[i].var1;
3442  if( !SCIPvarIsBinary(vars[0]) )
3443  continue;
3444 
3445  vars[1] = consdata->bilinterms[i].var2;
3446  if( !SCIPvarIsBinary(vars[1]) )
3447  continue;
3448 
3449  /* create auxiliary variable */
3450  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_%s", SCIPvarGetName(vars[0]), SCIPvarGetName(vars[1]), SCIPconsGetName(cons));
3451  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY,
3452  SCIPvarIsInitial(vars[0]) || SCIPvarIsInitial(vars[1]), SCIPvarIsRemovable(vars[0]) && SCIPvarIsRemovable(vars[1]), NULL, NULL, NULL, NULL, NULL) );
3453  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3454 #ifdef SCIP_DEBUG_SOLUTION
3455  if( SCIPdebugIsMainscip(scip) )
3456  {
3457  SCIP_Real var0val;
3458  SCIP_Real var1val;
3459  SCIP_CALL( SCIPdebugGetSolVal(scip, vars[0], &var0val) );
3460  SCIP_CALL( SCIPdebugGetSolVal(scip, vars[1], &var1val) );
3461  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, var0val * var1val) );
3462  }
3463 #endif
3464 
3465  /* create AND-constraint auxvar = x and y, need to be enforced as not redundant */
3466  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%sAND%s", SCIPvarGetName(vars[0]), SCIPvarGetName(vars[1]));
3467  SCIP_CALL( SCIPcreateConsAnd(scip, &andcons, name, auxvar, 2, vars,
3468  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3469  SCIPconsIsSeparated(cons), TRUE, TRUE,
3472  SCIP_CALL( SCIPaddCons(scip, andcons) );
3473  SCIPdebugMsg(scip, "added AND constraint: ");
3474  SCIPdebugPrintCons(scip, andcons, NULL);
3475  SCIP_CALL( SCIPreleaseCons(scip, &andcons) );
3476  ++*naddconss;
3477 
3478  /* add bilincoef * auxvar to linear terms */
3479  SCIP_CALL( addLinearCoef(scip, cons, auxvar, consdata->bilinterms[i].coef) );
3480  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
3481 
3482  /* remember that we have to delete this bilinear term */
3483  assert(ntodelete < consdata->nbilinterms);
3484  todelete[ntodelete++] = i;
3485  }
3486 
3487  /* remove bilinear terms that have been replaced */
3488  SCIP_CALL( removeBilinearTermsPos(scip, cons, ntodelete, todelete) );
3489  SCIPfreeBufferArray(scip, &todelete);
3490 
3491  return SCIP_OKAY;
3492 }
3493 
3494 /** gets bounds of variable y if x takes a certain value; checks whether x = xval has implications on y */
3495 static
3497  SCIP* scip, /**< SCIP data structure */
3498  SCIP_VAR* x, /**< variable which implications to check */
3499  SCIP_Bool xval, /**< value of x to check for (TRUE for 1, FALSE for 0) */
3500  SCIP_VAR* y, /**< variable to check if bounds can be reduced */
3501  SCIP_INTERVAL* resultant /**< buffer to store bounds on y */
3502  )
3503 {
3504  SCIP_VAR** implvars;
3505  SCIP_BOUNDTYPE* impltypes;
3506  SCIP_Real* implbounds;
3507  int nimpls;
3508  int pos;
3509 
3510  assert(scip != NULL);
3511  assert(x != NULL);
3512  assert(y != NULL);
3513  assert(resultant != NULL);
3514 
3516 
3517  if( !SCIPvarIsBinary(x) || !SCIPvarIsActive(x) )
3518  return SCIP_OKAY;
3519 
3520  /* check in cliques for binary to binary implications */
3521  if( SCIPvarIsBinary(y) )
3522  {
3523  resultant->inf = MAX(resultant->inf, MIN(resultant->sup, 0.0));
3524  resultant->sup = MIN(resultant->sup, MAX(resultant->inf, 1.0));
3525 
3526  if( SCIPhaveVarsCommonClique(scip, x, xval, y, TRUE, FALSE) )
3527  {
3528  resultant->sup = MIN(resultant->sup, MAX(resultant->inf, 0.0));
3529  }
3530  else if( SCIPhaveVarsCommonClique(scip, x, xval, y, FALSE, FALSE) )
3531  {
3532  resultant->inf = MAX(resultant->inf, MIN(resultant->sup, 1.0));
3533  }
3534 
3535  return SCIP_OKAY;
3536  }
3537 
3538  /* analyze implications for x = xval */
3539  nimpls = SCIPvarGetNImpls(x, xval);
3540  if( nimpls == 0 )
3541  return SCIP_OKAY;
3542 
3543  implvars = SCIPvarGetImplVars (x, xval);
3544  impltypes = SCIPvarGetImplTypes (x, xval);
3545  implbounds = SCIPvarGetImplBounds(x, xval);
3546 
3547  assert(implvars != NULL);
3548  assert(impltypes != NULL);
3549  assert(implbounds != NULL);
3550 
3551  /* find implications */
3552  if( !SCIPsortedvecFindPtr((void**)implvars, SCIPvarComp, (void*)y, nimpls, &pos) )
3553  return SCIP_OKAY;
3554 
3555  /* if there are several implications on y, go to the first one */
3556  while( pos > 0 && implvars[pos-1] == y )
3557  --pos;
3558 
3559  /* update implied lower and upper bounds on y
3560  * but make sure that resultant will not be empty, due to tolerances
3561  */
3562  while( pos < nimpls && implvars[pos] == y )
3563  {
3564  if( impltypes[pos] == SCIP_BOUNDTYPE_LOWER )
3565  resultant->inf = MAX(resultant->inf, MIN(resultant->sup, implbounds[pos]));
3566  else
3567  resultant->sup = MIN(resultant->sup, MAX(resultant->inf, implbounds[pos]));
3568  ++pos;
3569  }
3570 
3571  assert(resultant->sup >= resultant->inf);
3572 
3573  return SCIP_OKAY;
3574 }
3575 
3576 /** Reformulates products of binary times bounded continuous variables as system of linear inequalities (plus auxiliary variable).
3577  *
3578  * For a product x*y, with y a binary variable and x a continous variable with finite bounds,
3579  * 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.
3580  *
3581  * 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.
3582  * For each product of linear term of length at most maxnrvar with y, an auxiliary z and linear inequalities are added.
3583  *
3584  * If y is a binary variable, the AND constraint \f$ z = x \wedge y \f$ may be added instead of linear constraints.
3585  */
3586 static
3588  SCIP* scip, /**< SCIP data structure */
3589  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3590  SCIP_CONS* cons, /**< constraint */
3591  int* naddconss /**< buffer where to add the number of auxiliary constraints added */
3592  )
3593 { /*lint --e{666} */
3594  SCIP_CONSHDLRDATA* conshdlrdata;
3595  SCIP_CONSDATA* consdata;
3596  SCIP_VAR** xvars;
3597  SCIP_Real* xcoef;
3598  SCIP_INTERVAL xbndszero;
3599  SCIP_INTERVAL xbndsone;
3600  SCIP_INTERVAL act0;
3601  SCIP_INTERVAL act1;
3602  int nxvars;
3603  SCIP_VAR* y;
3604  SCIP_VAR* bvar;
3605  char name[SCIP_MAXSTRLEN];
3606  int nbilinterms;
3607  SCIP_VAR* auxvar;
3608  SCIP_CONS* auxcons;
3609  int i;
3610  int j;
3611  int k;
3612  int bilinidx;
3613  SCIP_Real bilincoef;
3614  SCIP_Real mincoef;
3615  SCIP_Real maxcoef;
3616  int* todelete;
3617  int ntodelete;
3618  int maxnrvar;
3619  SCIP_Bool integral;
3620  SCIP_Longint gcd;
3621  SCIP_Bool auxvarinitial;
3622  SCIP_Bool auxvarremovable;
3623 
3624  assert(scip != NULL);
3625  assert(conshdlr != NULL);
3626  assert(cons != NULL);
3627  assert(naddconss != NULL);
3628 
3629  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3630  assert(conshdlrdata != NULL);
3631 
3632  maxnrvar = conshdlrdata->replacebinaryprodlength;
3633  if( maxnrvar == 0 )
3634  return SCIP_OKAY;
3635 
3636  consdata = SCIPconsGetData(cons);
3637  assert(consdata != NULL);
3638 
3639  xvars = NULL;
3640  xcoef = NULL;
3641  todelete = NULL;
3642  gcd = 0;
3643 
3644  for( i = 0; i < consdata->nquadvars; ++i )
3645  {
3646  y = consdata->quadvarterms[i].var;
3647  if( !SCIPvarIsBinary(y) )
3648  continue;
3649 
3650  nbilinterms = consdata->quadvarterms[i].nadjbilin;
3651  if( nbilinterms == 0 )
3652  continue;
3653 
3654  SCIP_CALL( SCIPreallocBufferArray(scip, &xvars, MIN(maxnrvar, nbilinterms)+2) ); /* add 2 for later use when creating linear constraints */
3655  SCIP_CALL( SCIPreallocBufferArray(scip, &xcoef, MIN(maxnrvar, nbilinterms)+2) );
3656 
3657  /* alloc array to store indices of bilinear terms that shall be deleted */
3658  SCIP_CALL( SCIPreallocBufferArray(scip, &todelete, nbilinterms) );
3659  ntodelete = 0;
3660 
3661  auxvarinitial = SCIPvarIsInitial(y);
3662  auxvarremovable = SCIPvarIsRemovable(y);
3663 
3664  /* 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)
3665  * and compute range of sum_i a_i*x_i for the cases y = 0 and y = 1
3666  * we may need several rounds of maxnrvar < nbilinterms
3667  */
3668  j = 0;
3669  do
3670  {
3671  nxvars = 0;
3672  SCIPintervalSet(&xbndszero, 0.0);
3673  SCIPintervalSet(&xbndsone, 0.0);
3674 
3675  mincoef = SCIPinfinity(scip);
3676  maxcoef = 0.0;
3677  integral = TRUE;
3678 
3679  /* collect at most maxnrvar variables for x term */
3680  for( ; j < nbilinterms && nxvars < maxnrvar; ++j )
3681  {
3682  bilinidx = consdata->quadvarterms[i].adjbilin[j];
3683  assert(bilinidx >= 0);
3684  assert(bilinidx < consdata->nbilinterms);
3685 
3686  bvar = consdata->bilinterms[bilinidx].var1;
3687  if( bvar == y )
3688  bvar = consdata->bilinterms[bilinidx].var2;
3689  assert(bvar != y);
3690 
3691  /* skip products with unbounded variables */
3692  if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(bvar)) || SCIPisInfinity(scip, SCIPvarGetUbGlobal(bvar)) )
3693  {
3694  SCIPdebugMsg(scip, "skip reform of <%s><%s> due to unbounded second variable [%g,%g]\n",
3696  continue;
3697  }
3698 
3699  bilincoef = consdata->bilinterms[bilinidx].coef;
3700  assert(bilincoef != 0.0);
3701 
3702  /* get activity of bilincoef * x if y = 0 */
3703  SCIP_CALL( getImpliedBounds(scip, y, FALSE, bvar, &act0) );
3704  SCIPintervalMulScalar(SCIPinfinity(scip), &act0, act0, bilincoef);
3705 
3706  /* get activity of bilincoef * x if y = 1 */
3707  SCIP_CALL( getImpliedBounds(scip, y, TRUE, bvar, &act1) );
3708  SCIPintervalMulScalar(SCIPinfinity(scip), &act1, act1, bilincoef);
3709 
3710  /* skip products that give rise to very large coefficients (big big-M's) */
3711  if( SCIPfeastol(scip) * REALABS(act0.inf) >= conshdlrdata->binreformmaxcoef || SCIPfeastol(scip) * REALABS(act0.sup) >= conshdlrdata->binreformmaxcoef )
3712  {
3713  SCIPdebugMsg(scip, "skip reform of %g<%s><%s> due to huge activity [%g,%g] for <%s> = 0.0\n",
3714  bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar), SCIPintervalGetInf(act0), SCIPintervalGetSup(act0), SCIPvarGetName(y));
3715  continue;
3716  }
3717  if( SCIPfeastol(scip) * REALABS(act1.inf) >= conshdlrdata->binreformmaxcoef || SCIPfeastol(scip) * REALABS(act1.sup) >= conshdlrdata->binreformmaxcoef )
3718  {
3719  SCIPdebugMsg(scip, "skip reform of %g<%s><%s> due to huge activity [%g,%g] for <%s> = 1.0\n",
3720  bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar), SCIPintervalGetInf(act1), SCIPintervalGetSup(act1), SCIPvarGetName(y));
3721  continue;
3722  }
3723  if( !SCIPisZero(scip, MIN(REALABS(act0.inf), REALABS(act0.sup))) &&
3724  SCIPfeastol(scip) * MAX(REALABS(act0.inf), REALABS(act0.sup)) / MIN(REALABS(act0.inf), REALABS(act0.sup)) >= conshdlrdata->binreformmaxcoef )
3725  {
3726  SCIPdebugMsg(scip, "skip reform of %g<%s><%s> due to huge activity ratio %g for <%s> = 0.0\n", bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar),
3727  MAX(REALABS(act0.inf), REALABS(act0.sup)) / MIN(REALABS(act0.inf), REALABS(act0.sup)), SCIPvarGetName(y));
3728  continue;
3729  }
3730  if( !SCIPisZero(scip, MIN(REALABS(act1.inf), REALABS(act1.sup))) &&
3731  SCIPfeastol(scip) * MAX(REALABS(act1.inf), REALABS(act1.sup)) / MIN(REALABS(act1.inf), REALABS(act1.sup)) >= conshdlrdata->binreformmaxcoef )
3732  {
3733  SCIPdebugMsg(scip, "skip reform of %g<%s><%s> due to huge activity ratio %g for <%s> = 0.0\n", bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar),
3734  MAX(REALABS(act1.inf), REALABS(act1.sup)) / MIN(REALABS(act1.inf), REALABS(act1.sup)), SCIPvarGetName(y));
3735  continue;
3736  }
3737 
3738  /* add bvar to x term */
3739  xvars[nxvars] = bvar;
3740  xcoef[nxvars] = bilincoef;
3741  ++nxvars;
3742 
3743  /* update bounds on x term */
3744  SCIPintervalAdd(SCIPinfinity(scip), &xbndszero, xbndszero, act0);
3745  SCIPintervalAdd(SCIPinfinity(scip), &xbndsone, xbndsone, act1);
3746 
3747  if( REALABS(bilincoef) < mincoef )
3748  mincoef = ABS(bilincoef);
3749  if( REALABS(bilincoef) > maxcoef )
3750  maxcoef = ABS(bilincoef);
3751 
3752  /* update whether all coefficients will be integral and if so, compute their gcd */
3753  integral &= (SCIPvarGetType(bvar) < SCIP_VARTYPE_CONTINUOUS) && SCIPisIntegral(scip, bilincoef); /*lint !e514 */
3754  if( integral )
3755  {
3756  if( nxvars == 1 )
3757  gcd = (SCIP_Longint)SCIPround(scip, REALABS(bilincoef));
3758  else
3759  gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)SCIPround(scip, REALABS(bilincoef)));
3760  }
3761 
3762  /* if bvar is initial, then also the auxiliary variable should be initial
3763  * if bvar is not removable, then also the auxiliary variable should not be removable
3764  */
3765  auxvarinitial |= SCIPvarIsInitial(bvar);
3766  auxvarremovable &= SCIPvarIsRemovable(bvar);
3767 
3768  /* remember that we have to remove this bilinear term later */
3769  assert(ntodelete < nbilinterms);
3770  todelete[ntodelete++] = bilinidx;
3771  }
3772 
3773  if( nxvars == 0 ) /* all (remaining) x_j seem to be unbounded */
3774  break;
3775 
3776  assert(!SCIPisInfinity(scip, -SCIPintervalGetInf(xbndszero)));
3777  assert(!SCIPisInfinity(scip, SCIPintervalGetSup(xbndszero)));
3778  assert(!SCIPisInfinity(scip, -SCIPintervalGetInf(xbndsone)));
3779  assert(!SCIPisInfinity(scip, SCIPintervalGetSup(xbndsone)));
3780 
3781 #ifdef SCIP_DEBUG
3782  if( SCIPintervalGetInf(xbndszero) != SCIPintervalGetInf(xbndsone) || /*lint !e777*/
3783  +SCIPintervalGetSup(xbndszero) != SCIPintervalGetSup(xbndsone) ) /*lint !e777*/
3784  {
3785  SCIPdebugMsg(scip, "got different bounds for y = 0: [%g, %g] and y = 1: [%g, %g]\n", xbndszero.inf, xbndszero.sup, xbndsone.inf, xbndsone.sup);
3786  }
3787 #endif
3788 
3789  if( nxvars == 1 && conshdlrdata->empathy4and >= 1 && SCIPvarIsBinary(xvars[0]) )
3790  {
3791  /* product of two binary variables, replace by auxvar and AND constraint */
3792  /* add auxiliary variable z */
3793  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3794  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT,
3795  auxvarinitial, auxvarremovable, NULL, NULL, NULL, NULL, NULL) );
3796  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3797 
3798 #ifdef SCIP_DEBUG_SOLUTION
3799  if( SCIPdebugIsMainscip(scip) )
3800  {
3801  SCIP_Real var0val;
3802  SCIP_Real var1val;
3803  SCIP_CALL( SCIPdebugGetSolVal(scip, xvars[0], &var0val) );
3804  SCIP_CALL( SCIPdebugGetSolVal(scip, y, &var1val) );
3805  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, var0val * var1val) );
3806  }
3807 #endif
3808 
3809  /* add constraint z = x and y; need to be enforced, as it is not redundant w.r.t. existing constraints */
3810  xvars[1] = y;
3811  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%sAND%s_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3812  SCIP_CALL( SCIPcreateConsAnd(scip, &auxcons, name, auxvar, 2, xvars,
3813  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3814  SCIPconsIsSeparated(cons), TRUE, TRUE,
3817  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3818  SCIPdebugMsg(scip, "added AND constraint: ");
3819  SCIPdebugPrintCons(scip, auxcons, NULL);
3820  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3821  ++*naddconss;
3822 
3823  /* add linear term coef*auxvar */
3824  SCIP_CALL( addLinearCoef(scip, cons, auxvar, xcoef[0]) );
3825 
3826  /* forget about auxvar */
3827  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
3828  }
3829  else
3830  {
3831  /* product of binary variable with more than one binary or with continuous variables or with binary and user
3832  * did not like AND -> replace by auxvar and linear constraints */
3833  SCIP_Real scale;
3834 
3835  /* scale auxiliary constraint by some nice value,
3836  * if all coefficients are integral, take a value that preserves integrality (-> gcd), so we can make the auxiliary variable impl. integer
3837  */
3838  if( integral )
3839  {
3840  scale = (SCIP_Real)gcd;
3841  assert(scale >= 1.0);
3842  }
3843  else if( nxvars == 1 )
3844  {
3845  /* scaling by the only coefficient gives auxiliary variable = x * y, which thus will be implicit integral provided y is not continuous */
3846  assert(mincoef == maxcoef); /*lint !e777 */
3847  scale = mincoef;
3848  integral = SCIPvarGetType(xvars[0]) < SCIP_VARTYPE_CONTINUOUS;
3849  }
3850  else
3851  {
3852  scale = 1.0;
3853  if( maxcoef < 0.5 )
3854  scale = maxcoef;
3855  if( mincoef > 2.0 )
3856  scale = mincoef;
3857  if( scale != 1.0 )
3858  scale = SCIPselectSimpleValue(scale / 2.0, 1.5 * scale, MAXDNOM);
3859  }
3860  assert(scale > 0.0);
3861  assert(!SCIPisInfinity(scip, scale));
3862 
3863  /* if x-term is always negative for y = 1, negate scale so we get a positive auxiliary variable; maybe this is better sometimes? */
3864  if( !SCIPisPositive(scip, SCIPintervalGetSup(xbndsone)) )
3865  scale = -scale;
3866 
3867  SCIPdebugMsg(scip, "binary reformulation using scale %g, nxvars = %d, integral = %u\n", scale, nxvars, integral);
3868  if( scale != 1.0 )
3869  {
3870  SCIPintervalDivScalar(SCIPinfinity(scip), &xbndszero, xbndszero, scale);
3871  SCIPintervalDivScalar(SCIPinfinity(scip), &xbndsone, xbndsone, scale);
3872  for( k = 0; k < nxvars; ++k )
3873  xcoef[k] /= scale;
3874  }
3875 
3876  /* add auxiliary variable z */
3877  if( nxvars == 1 )
3878  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3879  else
3880  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_more_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3881  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, MIN(0., SCIPintervalGetInf(xbndsone)), MAX(0., SCIPintervalGetSup(xbndsone)),
3883  auxvarinitial, auxvarremovable, NULL, NULL, NULL, NULL, NULL) );
3884  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3885 
3886  /* compute value of auxvar in debug solution */
3887 #ifdef SCIP_DEBUG_SOLUTION
3888  if( SCIPdebugIsMainscip(scip) )
3889  {
3890  SCIP_Real debugval;
3891  SCIP_Real varval;
3892 
3893  SCIP_CALL( SCIPdebugGetSolVal(scip, y, &varval) );
3894  if( SCIPisZero(scip, varval) )
3895  {
3896  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, 0.0) );
3897  }
3898  else
3899  {
3900  assert(SCIPisEQ(scip, varval, 1.0));
3901 
3902  debugval = 0.0;
3903  for( k = 0; k < nxvars; ++k )
3904  {
3905  SCIP_CALL( SCIPdebugGetSolVal(scip, xvars[k], &varval) );
3906  debugval += xcoef[k] * varval;
3907  }
3908  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, debugval) );
3909  }
3910  }
3911 #endif
3912 
3913  /* add auxiliary constraints
3914  * it seems to be advantageous to make the varbound constraints initial and the linear constraints not initial
3915  * maybe because it is more likely that a binary variable takes value 0 instead of 1, and thus the varbound constraints
3916  * are more often active, compared to the linear constraints added below
3917  * also, the varbound constraints are more sparse than the linear cons
3918  */
3919  if( SCIPisNegative(scip, SCIPintervalGetInf(xbndsone)) )
3920  {
3921  /* add 0 <= z - xbndsone.inf * y constraint (as varbound constraint), need to be enforced as not redundant */
3922  if( nxvars == 1 )
3923  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_1", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3924  else
3925  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_1", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3926  SCIP_CALL( SCIPcreateConsVarbound(scip, &auxcons, name, auxvar, y, -SCIPintervalGetInf(xbndsone), 0.0, SCIPinfinity(scip),
3927  SCIPconsIsInitial(cons) /*&& conshdlrdata->binreforminitial*/,
3928  SCIPconsIsSeparated(cons), TRUE, TRUE,
3931  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3932  SCIPdebugMsg(scip, "added varbound constraint: ");
3933  SCIPdebugPrintCons(scip, auxcons, NULL);
3934  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3935  ++*naddconss;
3936  }
3937  if( SCIPisPositive(scip, SCIPintervalGetSup(xbndsone)) )
3938  {
3939  /* add z - xbndsone.sup * y <= 0 constraint (as varbound constraint), need to be enforced as not redundant */
3940  if( nxvars == 1 )
3941  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_2", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3942  else
3943  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_2", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3944  SCIP_CALL( SCIPcreateConsVarbound(scip, &auxcons, name, auxvar, y, -SCIPintervalGetSup(xbndsone), -SCIPinfinity(scip), 0.0,
3945  SCIPconsIsInitial(cons) /*&& conshdlrdata->binreforminitial*/,
3946  SCIPconsIsSeparated(cons), TRUE, TRUE,
3949  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3950  SCIPdebugMsg(scip, "added varbound constraint: ");
3951  SCIPdebugPrintCons(scip, auxcons, NULL);
3952  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3953  ++*naddconss;
3954  }
3955 
3956  /* add xbndszero.inf <= sum_i a_i*x_i + xbndszero.inf * y - z constraint, need to be enforced as not redundant */
3957  xvars[nxvars] = y;
3958  xvars[nxvars+1] = auxvar;
3959  xcoef[nxvars] = SCIPintervalGetInf(xbndszero);
3960  xcoef[nxvars+1] = -1;
3961 
3962  if( nxvars == 1 )
3963  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_3", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3964  else
3965  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_3", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3966  SCIP_CALL( SCIPcreateConsLinear(scip, &auxcons, name, nxvars+2, xvars, xcoef, SCIPintervalGetInf(xbndszero), SCIPinfinity(scip),
3967  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3968  SCIPconsIsSeparated(cons), TRUE, TRUE,
3971  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3972  SCIPdebugMsg(scip, "added linear constraint: ");
3973  SCIPdebugPrintCons(scip, auxcons, NULL);
3974  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3975  ++*naddconss;
3976 
3977  /* add sum_i a_i*x_i + xbndszero.sup * y - z <= xbndszero.sup constraint, need to be enforced as not redundant */
3978  xcoef[nxvars] = SCIPintervalGetSup(xbndszero);
3979 
3980  if( nxvars == 1 )
3981  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_4", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3982  else
3983  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_4", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3984  SCIP_CALL( SCIPcreateConsLinear(scip, &auxcons, name, nxvars+2, xvars, xcoef, -SCIPinfinity(scip), SCIPintervalGetSup(xbndszero),
3985  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3986  SCIPconsIsSeparated(cons), TRUE, TRUE,
3989  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3990  SCIPdebugMsg(scip, "added linear constraint: ");
3991  SCIPdebugPrintCons(scip, auxcons, NULL);
3992  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3993  ++*naddconss;
3994 
3995  /* add linear term scale*auxvar to this constraint */
3996  SCIP_CALL( addLinearCoef(scip, cons, auxvar, scale) );
3997 
3998  /* forget about auxvar */
3999  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
4000  }
4001  }
4002  while( j < nbilinterms );
4003 
4004  /* remove bilinear terms that have been replaced */
4005  SCIP_CALL( removeBilinearTermsPos(scip, cons, ntodelete, todelete) );
4006  }
4007  SCIPdebugMsg(scip, "resulting quadratic constraint: ");
4008  SCIPdebugPrintCons(scip, cons, NULL);
4009 
4010  SCIPfreeBufferArrayNull(scip, &xvars);
4011  SCIPfreeBufferArrayNull(scip, &xcoef);
4012  SCIPfreeBufferArrayNull(scip, &todelete);
4013 
4014  return SCIP_OKAY;
4015 }
4016 
4017 /** tries to automatically convert a quadratic constraint (or a part of it) into a more specific and more specialized constraint */
4018 static
4020  SCIP* scip, /**< SCIP data structure */
4021  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
4022  SCIP_CONS* cons, /**< source constraint to try to convert */
4023  SCIP_Bool* upgraded, /**< buffer to store whether constraint was upgraded */
4024  int* nupgdconss, /**< buffer to increase if constraint was upgraded */
4025  int* naddconss, /**< buffer to increase with number of additional constraints created during upgrade */
4026  SCIP_PRESOLTIMING presoltiming /**< current presolving timing */
4027  )
4028 {
4029  SCIP_CONSHDLRDATA* conshdlrdata;
4030  SCIP_CONSDATA* consdata;
4031  SCIP_VAR* var;
4032  SCIP_Real lincoef;
4033  SCIP_Real quadcoef;
4034  SCIP_Real lb;
4035  SCIP_Real ub;
4036  int nbinlin;
4037  int nbinquad;
4038  int nintlin;
4039  int nintquad;
4040  int nimpllin;
4041  int nimplquad;
4042  int ncontlin;
4043  int ncontquad;
4044  SCIP_Bool integral;
4045  int i;
4046  int j;
4047  SCIP_CONS** upgdconss;
4048  int upgdconsssize;
4049  int nupgdconss_;
4050 
4051  assert(scip != NULL);
4052  assert(conshdlr != NULL);
4053  assert(cons != NULL);
4054  assert(!SCIPconsIsModifiable(cons));
4055  assert(upgraded != NULL);
4056  assert(nupgdconss != NULL);
4057  assert(naddconss != NULL);
4058 
4059  *upgraded = FALSE;
4060 
4061  nupgdconss_ = 0;
4062 
4063  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4064  assert(conshdlrdata != NULL);
4065 
4066  /* if there are no upgrade methods, we can also stop */
4067  if( conshdlrdata->nquadconsupgrades == 0 )
4068  return SCIP_OKAY;
4069 
4070  upgdconsssize = 2;
4071  SCIP_CALL( SCIPallocBufferArray(scip, &upgdconss, upgdconsssize) );
4072 
4073  consdata = SCIPconsGetData(cons);
4074  assert(consdata != NULL);
4075 
4076  /* calculate some statistics on quadratic constraint */
4077  nbinlin = 0;
4078  nbinquad = 0;
4079  nintlin = 0;
4080  nintquad = 0;
4081  nimpllin = 0;
4082  nimplquad = 0;
4083  ncontlin = 0;
4084  ncontquad = 0;
4085  integral = TRUE;
4086  for( i = 0; i < consdata->nlinvars; ++i )
4087  {
4088  var = consdata->linvars[i];
4089  lincoef = consdata->lincoefs[i];
4090  lb = SCIPvarGetLbLocal(var);
4091  ub = SCIPvarGetUbLocal(var);
4092  assert(!SCIPisZero(scip, lincoef));
4093 
4094  switch( SCIPvarGetType(var) )
4095  {
4096  case SCIP_VARTYPE_BINARY:
4097  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4098  integral = integral && SCIPisIntegral(scip, lincoef);
4099  nbinlin++;
4100  break;
4101  case SCIP_VARTYPE_INTEGER:
4102  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4103  integral = integral && SCIPisIntegral(scip, lincoef);
4104  nintlin++;
4105  break;
4106  case SCIP_VARTYPE_IMPLINT:
4107  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4108  integral = integral && SCIPisIntegral(scip, lincoef);
4109  nimpllin++;
4110  break;
4112  integral = integral && SCIPisRelEQ(scip, lb, ub) && SCIPisIntegral(scip, lincoef * lb);
4113  ncontlin++;
4114  break;
4115  default:
4116  SCIPerrorMessage("unknown variable type\n");
4117  return SCIP_INVALIDDATA;
4118  }
4119  }
4120 
4121  for( i = 0; i < consdata->nquadvars; ++i )
4122  {
4123  var = consdata->quadvarterms[i].var;
4124  lincoef = consdata->quadvarterms[i].lincoef;
4125  quadcoef = consdata->quadvarterms[i].sqrcoef;
4126  lb = SCIPvarGetLbLocal(var);
4127  ub = SCIPvarGetUbLocal(var);
4128 
4129  switch( SCIPvarGetType(var) )
4130  {
4131  case SCIP_VARTYPE_BINARY:
4132  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4133  integral = integral && SCIPisIntegral(scip, lincoef) && SCIPisIntegral(scip, quadcoef);
4134  nbinquad++;
4135  break;
4136  case SCIP_VARTYPE_INTEGER:
4137  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4138  integral = integral && SCIPisIntegral(scip, lincoef) && SCIPisIntegral(scip, quadcoef);
4139  nintquad++;
4140  break;
4141  case SCIP_VARTYPE_IMPLINT:
4142  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4143  integral = integral && SCIPisIntegral(scip, lincoef) && SCIPisIntegral(scip, quadcoef);
4144  nimplquad++;
4145  break;
4147  integral = integral && SCIPisRelEQ(scip, lb, ub) && SCIPisIntegral(scip, lincoef * lb + quadcoef * lb * lb);
4148  ncontquad++;
4149  break;
4150  default:
4151  SCIPerrorMessage("unknown variable type\n");
4152  return SCIP_INVALIDDATA;
4153  }
4154  }
4155 
4156  if( integral )
4157  {
4158  for( i = 0; i < consdata->nbilinterms && integral; ++i )
4159  {
4160  if( SCIPvarGetType(consdata->bilinterms[i].var1) < SCIP_VARTYPE_CONTINUOUS && SCIPvarGetType(consdata->bilinterms[i].var2) < SCIP_VARTYPE_CONTINUOUS )
4161  integral = integral && SCIPisIntegral(scip, consdata->bilinterms[i].coef);
4162  else
4163  integral = FALSE;
4164  }
4165  }
4166 
4167  /* call the upgrading methods */
4168 
4169  SCIPdebugMsg(scip, "upgrading quadratic constraint <%s> (%d upgrade methods):\n",
4170  SCIPconsGetName(cons), conshdlrdata->nquadconsupgrades);
4171  SCIPdebugMsg(scip, " binlin=%d binquad=%d intlin=%d intquad=%d impllin=%d implquad=%d contlin=%d contquad=%d integral=%u\n",
4172  nbinlin, nbinquad, nintlin, nintquad, nimpllin, nimplquad, ncontlin, ncontquad, integral);
4173  SCIPdebugPrintCons(scip, cons, NULL);
4174 
4175  /* try all upgrading methods in priority order in case the upgrading step is enable */
4176  for( i = 0; i < conshdlrdata->nquadconsupgrades; ++i )
4177  {
4178  if( !conshdlrdata->quadconsupgrades[i]->active )
4179  continue;
4180 
4181  SCIP_CALL( conshdlrdata->quadconsupgrades[i]->quadconsupgd(scip, cons,
4182  nbinlin, nbinquad, nintlin, nintquad, nimpllin, nimplquad, ncontlin, ncontquad, integral,
4183  &nupgdconss_, upgdconss, upgdconsssize, presoltiming) );
4184 
4185  while( nupgdconss_ < 0 )
4186  {
4187  /* upgrade function requires more memory: resize upgdconss and call again */
4188  assert(-nupgdconss_ > upgdconsssize);
4189  upgdconsssize = -nupgdconss_;
4190  SCIP_CALL( SCIPreallocBufferArray(scip, &upgdconss, -nupgdconss_) );
4191 
4192  SCIP_CALL( conshdlrdata->quadconsupgrades[i]->quadconsupgd(scip, cons,
4193  nbinlin, nbinquad, nintlin, nintquad, nimpllin, nimplquad, ncontlin, ncontquad, integral,
4194  &nupgdconss_, upgdconss, upgdconsssize, presoltiming) );
4195 
4196  assert(nupgdconss_ != 0);
4197  }
4198 
4199  if( nupgdconss_ > 0 )
4200  {
4201  /* got upgrade */
4202  SCIPdebugPrintCons(scip, cons, NULL);
4203  SCIPdebugMsg(scip, " -> upgraded to %d constraints:\n", nupgdconss_);
4204 
4205  /* add the upgraded constraints to the problem and forget them */
4206  for( j = 0; j < nupgdconss_; ++j )
4207  {
4208  SCIPdebugMsgPrint(scip, "\t");
4209  SCIPdebugPrintCons(scip, upgdconss[j], NULL);
4210 
4211  SCIP_CALL( SCIPaddCons(scip, upgdconss[j]) ); /*lint !e613*/
4212  SCIP_CALL( SCIPreleaseCons(scip, &upgdconss[j]) ); /*lint !e613*/
4213  }
4214 
4215  /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
4216  *nupgdconss += 1;
4217  *naddconss += nupgdconss_ - 1;
4218  *upgraded = TRUE;
4219 
4220  /* delete upgraded constraint */
4221  SCIPdebugMsg(scip, "delete constraint <%s> after upgrade\n", SCIPconsGetName(cons));
4222  SCIP_CALL( SCIPdelCons(scip, cons) );
4223 
4224  break;
4225  }
4226  }
4227 
4228  SCIPfreeBufferArray(scip, &upgdconss);
4229 
4230  return SCIP_OKAY;
4231 }
4232 
4233 /** helper function for presolveDisaggregate */
4234 static
4236  SCIP* scip, /**< SCIP data structure */
4237  SCIP_CONSDATA* consdata, /**< constraint data */
4238  int quadvaridx, /**< index of quadratic variable to mark */
4239  SCIP_HASHMAP* var2component, /**< variables to components mapping */
4240  int componentnr /**< the component number to mark to */
4241  )
4242 {
4243  SCIP_QUADVARTERM* quadvarterm;
4244  SCIP_VAR* othervar;
4245  int othervaridx;
4246  int i;
4247 
4248  assert(consdata != NULL);
4249  assert(quadvaridx >= 0);
4250  assert(quadvaridx < consdata->nquadvars);
4251  assert(var2component != NULL);
4252  assert(componentnr >= 0);
4253 
4254  quadvarterm = &consdata->quadvarterms[quadvaridx];
4255 
4256  if( SCIPhashmapExists(var2component, quadvarterm->var) )
4257  {
4258  /* if we saw the variable before, then it should have the same component number */
4259  assert((int)(size_t)SCIPhashmapGetImage(var2component, quadvarterm->var) == componentnr);
4260  return SCIP_OKAY;
4261  }
4262 
4263  /* assign component number to variable */
4264  SCIP_CALL( SCIPhashmapInsert(var2component, quadvarterm->var, (void*)(size_t)componentnr) );
4265 
4266  /* assign same component number to all variables this variable is multiplied with */
4267  for( i = 0; i < quadvarterm->nadjbilin; ++i )
4268  {
4269  othervar = consdata->bilinterms[quadvarterm->adjbilin[i]].var1 == quadvarterm->var ?
4270  consdata->bilinterms[quadvarterm->adjbilin[i]].var2 : consdata->bilinterms[quadvarterm->adjbilin[i]].var1;
4271  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, othervar, &othervaridx) );
4272  assert(othervaridx >= 0);
4273  SCIP_CALL( presolveDisaggregateMarkComponent(scip, consdata, othervaridx, var2component, componentnr) );
4274  }
4275 
4276  return SCIP_OKAY;
4277 }
4278 
4279 /** for quadratic constraints that consists of a sum of quadratic terms, disaggregates the sum into a set of constraints by introducing auxiliary variables */
4280 static
4282  SCIP* scip, /**< SCIP data structure */
4283  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
4284  SCIP_CONS* cons, /**< source constraint to try to convert */
4285  int* naddconss /**< pointer to counter of added constraints */
4286  )
4287 {
4288  SCIP_CONSDATA* consdata;
4289  SCIP_HASHMAP* var2component;
4290  int ncomponents;
4291  int i;
4292  int comp;
4293  SCIP_CONS** auxconss;
4294  SCIP_VAR** auxvars;
4295  SCIP_Real* auxcoefs;
4296  char name[SCIP_MAXSTRLEN];
4297 
4298  assert(scip != NULL);
4299  assert(conshdlr != NULL);
4300  assert(cons != NULL);
4301  assert(naddconss != NULL);
4302 
4303  consdata = SCIPconsGetData(cons);
4304  assert(consdata != NULL);
4305 
4306  /* make sure there are no quadratic variables without coefficients */
4307  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
4308  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, cons) );
4309 
4310  if( consdata->nquadvars <= 1 )
4311  return SCIP_OKAY;
4312 
4313  /* sort quadratic variable terms here, so we can later search in it without reordering the array */
4314  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
4315 
4316  /* check how many quadratic terms with non-overlapping variables we have
4317  * in other words, the number of components in the sparsity graph of the quadratic term matrix */
4318  ncomponents = 0;
4319  SCIP_CALL( SCIPhashmapCreate(&var2component, SCIPblkmem(scip), consdata->nquadvars) );
4320  for( i = 0; i < consdata->nquadvars; ++i )
4321  {
4322  /* if variable was marked already, skip it */
4323  if( SCIPhashmapExists(var2component, (void*)consdata->quadvarterms[i].var) )
4324  continue;
4325 
4326  SCIP_CALL( presolveDisaggregateMarkComponent(scip, consdata, i, var2component, ncomponents) );
4327  ++ncomponents;
4328  }
4329  assert(ncomponents >= 1);
4330 
4331  /* if there is only one component, we cannot disaggregate
4332  * @todo we could still split the constraint into several while keeping the number of variables sharing several constraints as small as possible
4333  */
4334  if( ncomponents == 1 )
4335  {
4336  SCIPhashmapFree(&var2component);
4337  return SCIP_OKAY;
4338  }
4339 
4340  SCIP_CALL( SCIPallocBufferArray(scip, &auxconss, ncomponents) );
4341  SCIP_CALL( SCIPallocBufferArray(scip, &auxvars, ncomponents) );
4342  SCIP_CALL( SCIPallocBufferArray(scip, &auxcoefs, ncomponents) );
4343 
4344  /* create auxiliary variables and empty constraints for each component */
4345  for( comp = 0; comp < ncomponents; ++comp )
4346  {
4347  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_comp%d", SCIPconsGetName(cons), comp);
4348 
4349  SCIP_CALL( SCIPcreateVar(scip, &auxvars[comp], name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
4351 
4352  SCIP_CALL( SCIPcreateConsQuadratic2(scip, &auxconss[comp], name, 0, NULL, NULL, 0, NULL, 0, NULL,
4353  (SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : 0.0),
4354  (SCIPisInfinity(scip, consdata->rhs) ? SCIPinfinity(scip) : 0.0),
4357  SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons)) );
4358 
4359  auxcoefs[comp] = SCIPinfinity(scip);
4360  }
4361 
4362  /* add quadratic variables to each component constraint
4363  * delete adjacency information */
4364  for( i = 0; i < consdata->nquadvars; ++i )
4365  {
4366  comp = (int)(size_t) SCIPhashmapGetImage(var2component, consdata->quadvarterms[i].var);
4367  assert(comp >= 0);
4368  assert(comp < ncomponents);
4369 
4370  /* add variable term to corresponding constraint */
4371  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, auxconss[comp], consdata->quadvarterms[i].var, consdata->quadvarterms[i].lincoef, consdata->quadvarterms[i].sqrcoef) );
4372 
4373  /* reduce coefficient of aux variable */
4374  if( !SCIPisZero(scip, consdata->quadvarterms[i].lincoef) && ABS(consdata->quadvarterms[i].lincoef) < auxcoefs[comp] )
4375  auxcoefs[comp] = REALABS(consdata->quadvarterms[i].lincoef);
4376  if( !SCIPisZero(scip, consdata->quadvarterms[i].sqrcoef) && ABS(consdata->quadvarterms[i].sqrcoef) < auxcoefs[comp] )
4377  auxcoefs[comp] = REALABS(consdata->quadvarterms[i].sqrcoef);
4378 
4379  SCIPfreeBlockMemoryArray(scip, &consdata->quadvarterms[i].adjbilin, consdata->quadvarterms[i].adjbilinsize);
4380  consdata->quadvarterms[i].nadjbilin = 0;
4381  consdata->quadvarterms[i].adjbilinsize = 0;
4382  }
4383 
4384  /* add bilinear terms to each component constraint */
4385  for( i = 0; i < consdata->nbilinterms; ++i )
4386  {
4387  comp = (int)(size_t) SCIPhashmapGetImage(var2component, consdata->bilinterms[i].var1);
4388  assert(comp == (int)(size_t) SCIPhashmapGetImage(var2component, consdata->bilinterms[i].var2));
4389  assert(!SCIPisZero(scip, consdata->bilinterms[i].coef));
4390 
4391  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, auxconss[comp],
4392  consdata->bilinterms[i].var1, consdata->bilinterms[i].var2, consdata->bilinterms[i].coef) );
4393 
4394  if( ABS(consdata->bilinterms[i].coef) < auxcoefs[comp] )
4395  auxcoefs[comp] = ABS(consdata->bilinterms[i].coef);
4396  }
4397 
4398  /* forget about bilinear terms in cons */
4399  SCIPfreeBlockMemoryArray(scip, &consdata->bilinterms, consdata->bilintermssize);
4400  consdata->nbilinterms = 0;
4401  consdata->bilintermssize = 0;
4402 
4403  /* remove quadratic variable terms from cons */
4404  for( i = consdata->nquadvars - 1; i >= 0; --i )
4405  {
4406  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
4407  }
4408  assert(consdata->nquadvars == 0);
4409 
4410  /* add auxiliary variables to auxiliary constraints
4411  * add aux vars and constraints to SCIP
4412  * add aux vars to this constraint
4413  * @todo compute debug solution values and set for auxvars
4414  */
4415  SCIPdebugMsg(scip, "add %d constraints for disaggregation of quadratic constraint <%s>\n", ncomponents, SCIPconsGetName(cons));
4416  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars + ncomponents) );
4417  for( comp = 0; comp < ncomponents; ++comp )
4418  {
4419  SCIP_CALL( SCIPaddLinearVarQuadratic(scip, auxconss[comp], auxvars[comp], -auxcoefs[comp]) );
4420 
4421  SCIP_CALL( SCIPaddVar(scip, auxvars[comp]) );
4422 
4423  SCIP_CALL( SCIPaddCons(scip, auxconss[comp]) );
4424  SCIPdebugPrintCons(scip, auxconss[comp], NULL);
4425 
4426  SCIP_CALL( addLinearCoef(scip, cons, auxvars[comp], auxcoefs[comp]) );
4427 
4428  SCIP_CALL( SCIPreleaseCons(scip, &auxconss[comp]) );
4429  SCIP_CALL( SCIPreleaseVar(scip, &auxvars[comp]) );
4430  }
4431  *naddconss += ncomponents;
4432 
4433  SCIPdebugPrintCons(scip, cons, NULL);
4434 
4435  SCIPfreeBufferArray(scip, &auxconss);
4436  SCIPfreeBufferArray(scip, &auxvars);
4437  SCIPfreeBufferArray(scip, &auxcoefs);
4438  SCIPhashmapFree(&var2component);
4439 
4440  return SCIP_OKAY;
4441 }
4442 
4443 #ifdef CHECKIMPLINBILINEAR
4444 /** checks if there are bilinear terms x*y with a binary variable x and an implication x = {0,1} -> y = 0
4445  *
4446  * In this case, the bilinear term can be removed (x=0 case) or replaced by y (x=1 case).
4447  */
4448 static
4449 SCIP_RETCODE presolveApplyImplications(
4450  SCIP* scip, /**< SCIP data structure */
4451  SCIP_CONS* cons, /**< quadratic constraint */
4452  int* nbilinremoved /**< buffer to store number of removed bilinear terms */
4453  )
4454 {
4455  SCIP_CONSDATA* consdata;
4456  SCIP_VAR* x;
4457  SCIP_VAR* y;
4458  SCIP_INTERVAL implbnds;
4459  int i;
4460  int j;
4461  int k;
4462 
4463  assert(scip != NULL);
4464  assert(cons != NULL);
4465  assert(nbilinremoved != NULL);
4466 
4467  *nbilinremoved = 0;
4468 
4469  consdata = SCIPconsGetData(cons);
4470  assert(consdata != NULL);
4471 
4472  SCIPdebugMsg(scip, "apply implications in <%s>\n", SCIPconsGetName(cons));
4473 
4474  /* sort quadvarterms in case we need to search */
4475  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
4476 
4477  for( i = 0; i < consdata->nquadvars; ++i )
4478  {
4479  x = consdata->quadvarterms[i].var;
4480  assert(x != NULL);
4481 
4482  if( consdata->quadvarterms[i].nadjbilin == 0 )
4483  continue;
4484 
4485  if( !SCIPvarIsBinary(x) )
4486  continue;
4487 
4488  if( !SCIPvarIsActive(x) )
4489  continue;
4490 
4491  if( SCIPvarGetNImpls(x, TRUE) == 0 && SCIPvarGetNImpls(x, FALSE) == 0 )
4492  continue;
4493 
4494  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
4495  {
4496  k = consdata->quadvarterms[i].adjbilin[j];
4497  assert(k >= 0);
4498  assert(k < consdata->nbilinterms);
4499 
4500  if( consdata->bilinterms[k].coef == 0.0 )
4501  continue;
4502 
4503  y = consdata->bilinterms[k].var1 == x ? consdata->bilinterms[k].var2 : consdata->bilinterms[k].var1;
4504  assert(x != y);
4505 
4506  SCIP_CALL( getImpliedBounds(scip, x, TRUE, y, &implbnds) );
4507  if( SCIPisZero(scip, implbnds.inf) && SCIPisZero(scip, implbnds.sup) )
4508  {
4509  /* if x = 1 implies y = 0, then we can remove the bilinear term x*y, since it is always 0
4510  * we only set the coefficient to 0.0 here and mark the bilinterms as not merged */
4511  SCIPdebugMsg(scip, "remove bilinear term %g<%s><%s> from <%s> due to implication\n", consdata->bilinterms[k].coef, SCIPvarGetName(x), SCIPvarGetName(y), SCIPconsGetName(cons));
4512  consdata->bilinterms[k].coef = 0.0;
4513  consdata->bilinmerged = FALSE;
4514  ++*nbilinremoved;
4515  continue;
4516  }
4517 
4518  SCIP_CALL( getImpliedBounds(scip, x, FALSE, y, &implbnds) );
4519  if( SCIPisZero(scip, implbnds.inf) && SCIPisZero(scip, implbnds.sup) )
4520  {
4521  /* if x = 0 implies y = 0, then we can replace the bilinear term x*y by y
4522  * we only move the coefficient to the linear coef of y here and mark the bilinterms as not merged */
4523  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));
4524  assert(consdata->quadvarssorted);
4525  SCIP_CALL( SCIPaddQuadVarLinearCoefQuadratic(scip, cons, y, consdata->bilinterms[k].coef) );
4526  consdata->bilinterms[k].coef = 0.0;
4527  consdata->bilinmerged = FALSE;
4528  ++*nbilinremoved;
4529  }
4530  }
4531  }
4532 
4533  if( *nbilinremoved > 0 )
4534  {
4535  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
4536 
4537  /* invalidate nonlinear row */
4538  if( consdata->nlrow != NULL )
4539  {
4540  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
4541  }
4542 
4543  consdata->ispropagated = FALSE;
4544  consdata->ispresolved = FALSE;
4545  consdata->iscurvchecked = FALSE;
4546  }
4547 
4548  consdata->isimpladded = FALSE;
4549 
4550  return SCIP_OKAY;
4551 }
4552 #endif
4553 
4554 /** checks a quadratic constraint for convexity and/or concavity without checking multivariate functions */
4555 static
4556 void checkCurvatureEasy(
4557  SCIP* scip, /**< SCIP data structure */
4558  SCIP_CONS* cons, /**< quadratic constraint */
4559  SCIP_Bool* determined, /**< pointer to store whether the curvature could be determined */
4560  SCIP_Bool checkmultivariate /**< whether curvature will be checked later on for multivariate functions */
4561  )
4562 {
4563  SCIP_CONSDATA* consdata;
4564  int nquadvars;
4565 
4566  assert(scip != NULL);
4567  assert(cons != NULL);
4568  assert(determined != NULL);
4569 
4570  consdata = SCIPconsGetData(cons);
4571  assert(consdata != NULL);
4572 
4573  nquadvars = consdata->nquadvars;
4574  *determined = TRUE;
4575 
4576  if( consdata->iscurvchecked )
4577  return;
4578 
4579  SCIPdebugMsg(scip, "Checking curvature of constraint <%s> without multivariate functions\n", SCIPconsGetName(cons));
4580 
4581  if( nquadvars == 1 )
4582  {
4583  assert(consdata->nbilinterms == 0);
4584  consdata->isconvex = !SCIPisNegative(scip, consdata->quadvarterms[0].sqrcoef);
4585  consdata->isconcave = !SCIPisPositive(scip, consdata->quadvarterms[0].sqrcoef);
4586  consdata->iscurvchecked = TRUE;
4587  }
4588  else if( nquadvars == 0 )
4589  {
4590  consdata->isconvex = TRUE;
4591  consdata->isconcave = TRUE;
4592  consdata->iscurvchecked = TRUE;
4593  }
4594  else if( consdata->nbilinterms == 0 )
4595  {
4596  int v;
4597 
4598  consdata->isconvex = TRUE;
4599  consdata->isconcave = TRUE;
4600 
4601  for( v = nquadvars - 1; v >= 0; --v )
4602  {
4603  consdata->isconvex = consdata->isconvex && !SCIPisNegative(scip, consdata->quadvarterms[v].sqrcoef);
4604  consdata->isconcave = consdata->isconcave && !SCIPisPositive(scip, consdata->quadvarterms[v].sqrcoef);
4605  }
4606 
4607  consdata->iscurvchecked = TRUE;
4608  }
4609  else if( !checkmultivariate )
4610  {
4611  consdata->isconvex = FALSE;
4612  consdata->isconcave = FALSE;
4613  consdata->iscurvchecked = TRUE;
4614  }
4615  else
4616  *determined = FALSE;
4617 }
4618 
4619 /** checks a quadratic constraint for convexity and/or concavity */
4620 static
4622  SCIP* scip, /**< SCIP data structure */
4623  SCIP_CONS* cons, /**< quadratic constraint */
4624  SCIP_Bool checkmultivariate /**< whether curvature should also be checked for multivariate functions */
4625  )
4626 {
4627  SCIP_CONSDATA* consdata;
4628  double* matrix;
4629  SCIP_HASHMAP* var2index;
4630  int i;
4631  int n;
4632  int nn;
4633  int row;
4634  int col;
4635  double* alleigval;
4636  SCIP_Bool determined;
4637 
4638  assert(scip != NULL);
4639  assert(cons != NULL);
4640 
4641  consdata = SCIPconsGetData(cons);
4642  assert(consdata != NULL);
4643 
4644  n = consdata->nquadvars;
4645 
4646  if( consdata->iscurvchecked )
4647  return SCIP_OKAY;
4648 
4649  /* easy checks for curvature detection */
4650  checkCurvatureEasy(scip, cons, &determined, checkmultivariate);
4651 
4652  /* if curvature was already detected stop */
4653  if( determined )
4654  {
4655  return SCIP_OKAY;
4656  }
4657 
4658  SCIPdebugMsg(scip, "Checking curvature of constraint <%s> with multivariate functions\n", SCIPconsGetName(cons));
4659 
4660  if( n == 2 )
4661  {
4662  /* compute eigenvalues by hand */
4663  assert(consdata->nbilinterms == 1);
4664  consdata->isconvex =
4665  consdata->quadvarterms[0].sqrcoef >= 0 &&
4666  consdata->quadvarterms[1].sqrcoef >= 0 &&
4667  4 * consdata->quadvarterms[0].sqrcoef * consdata->quadvarterms[1].sqrcoef >= consdata->bilinterms[0].coef * consdata->bilinterms[0].coef;
4668  consdata->isconcave =
4669  consdata->quadvarterms[0].sqrcoef <= 0 &&
4670  consdata->quadvarterms[1].sqrcoef <= 0 &&
4671  4 * consdata->quadvarterms[0].sqrcoef * consdata->quadvarterms[1].sqrcoef >= consdata->bilinterms[0].coef * consdata->bilinterms[0].coef;
4672 
4673  consdata->iscurvchecked = TRUE;
4674  return SCIP_OKAY;
4675  }
4676 
4677  /* do not check curvature if n is too large */
4678  nn = n * n;
4679  if( nn < 0 || (unsigned) (int) nn > UINT_MAX / sizeof(SCIP_Real) )
4680  {
4681  SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL, "cons_quadratic - n is too large to check the curvature\n");
4682  consdata->isconvex = FALSE;
4683  consdata->isconcave = FALSE;
4684  consdata->iscurvchecked = TRUE;
4685  return SCIP_OKAY;
4686  }
4687 
4688  /* lower triangular of quadratic term matrix */
4689  SCIP_CALL( SCIPallocBufferArray(scip, &matrix, nn) );
4690  BMSclearMemoryArray(matrix, nn);
4691 
4692  consdata->isconvex = TRUE;
4693  consdata->isconcave = TRUE;
4694 
4695  SCIP_CALL( SCIPhashmapCreate(&var2index, SCIPblkmem(scip), n) );
4696  for( i = 0; i < n; ++i )
4697  {
4698  if( consdata->quadvarterms[i].nadjbilin > 0 )
4699  {
4700  SCIP_CALL( SCIPhashmapInsert(var2index, consdata->quadvarterms[i].var, (void*)(size_t)i) );
4701  matrix[i*n + i] = consdata->quadvarterms[i].sqrcoef;
4702  }
4703  /* nonzero elements on diagonal tell a lot about convexity/concavity */
4704  if( SCIPisNegative(scip, consdata->quadvarterms[i].sqrcoef) )
4705  consdata->isconvex = FALSE;
4706  if( SCIPisPositive(scip, consdata->quadvarterms[i].sqrcoef) )
4707  consdata->isconcave = FALSE;
4708  }
4709 
4710  if( !consdata->isconvex && !consdata->isconcave )
4711  {
4712  SCIPfreeBufferArray(scip, &matrix);
4713  SCIPhashmapFree(&var2index);
4714  consdata->iscurvchecked = TRUE;
4715  return SCIP_OKAY;
4716  }
4717 
4719  {
4720  for( i = 0; i < consdata->nbilinterms; ++i )
4721  {
4722  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var1));
4723  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var2));
4724  row = (int)(size_t)SCIPhashmapGetImage(var2index, consdata->bilinterms[i].var1);
4725  col = (int)(size_t)SCIPhashmapGetImage(var2index, consdata->bilinterms[i].var2);
4726  if( row < col )
4727  matrix[row * n + col] = consdata->bilinterms[i].coef/2;
4728  else
4729  matrix[col * n + row] = consdata->bilinterms[i].coef/2;
4730  }
4731 
4732  SCIP_CALL( SCIPallocBufferArray(scip, &alleigval, n) );
4733  /* @todo Can we compute only min and max eigen value?
4734  * @todo Can we estimate the numerical error?
4735  * @todo Trying a cholesky factorization may be much faster.
4736  */
4737  if( LapackDsyev(FALSE, n, matrix, alleigval) != SCIP_OKAY )
4738  {
4739  SCIPwarningMessage(scip, "Failed to compute eigenvalues of quadratic coefficient matrix of constraint %s. Assuming matrix is indefinite.\n", SCIPconsGetName(cons));
4740  consdata->isconvex = FALSE;
4741  consdata->isconcave = FALSE;
4742  }
4743  else
4744  {
4745  /* deconvexification reformulates a stricly convex quadratic function in binaries such that it becomes not-strictly convex
4746  * by adding the -lambda*(x^2-x) terms for lambda the smallest eigenvalue of the matrix
4747  * 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
4748  */
4749 #ifdef DECONVEXIFY
4750  SCIP_Bool allbinary;
4751  printf("cons <%s>[%g,%g] spectrum = [%g,%g]\n", SCIPconsGetName(cons), consdata->lhs, consdata->rhs, alleigval[0], alleigval[n-1]);
4752 #endif
4753  consdata->isconvex &= !SCIPisNegative(scip, alleigval[0]); /*lint !e514*/
4754  consdata->isconcave &= !SCIPisPositive(scip, alleigval[n-1]); /*lint !e514*/
4755  consdata->iscurvchecked = TRUE;
4756 #ifdef DECONVEXIFY
4757  for( i = 0; i < consdata->nquadvars; ++i )
4758  if( !SCIPvarIsBinary(consdata->quadvarterms[i].var) )
4759  break;
4760  allbinary = i == consdata->nquadvars;
4761 
4762  if( !SCIPisInfinity(scip, consdata->rhs) && alleigval[0] > 0.1 && allbinary )
4763  {
4764  printf("deconvexify cons <%s> by shifting hessian by %g\n", SCIPconsGetName(cons), alleigval[0]);
4765  for( i = 0; i < consdata->nquadvars; ++i )
4766  {
4767  consdata->quadvarterms[i].sqrcoef -= alleigval[0];
4768  consdata->quadvarterms[i].lincoef += alleigval[0];
4769  }
4770  }
4771 
4772  if( !SCIPisInfinity(scip, consdata->lhs) && alleigval[n-1] < -0.1 && allbinary )
4773  {
4774  printf("deconcavify cons <%s> by shifting hessian by %g\n", SCIPconsGetName(cons), alleigval[n-1]);
4775  for( i = 0; i < consdata->nquadvars; ++i )
4776  {
4777  consdata->quadvarterms[i].sqrcoef -= alleigval[n-1];
4778  consdata->quadvarterms[i].lincoef += alleigval[n-1];
4779  }
4780  }
4781 #endif
4782  }
4783 
4784  SCIPfreeBufferArray(scip, &alleigval);
4785  }
4786  else
4787  {
4788  consdata->isconvex = FALSE;
4789  consdata->isconcave = FALSE;
4790  consdata->iscurvchecked = TRUE; /* set to TRUE since it does not help to repeat this procedure again and again (that will not bring Ipopt in) */
4791  }
4792 
4793  SCIPhashmapFree(&var2index);
4794  SCIPfreeBufferArray(scip, &matrix);
4795 
4796  return SCIP_OKAY;
4797 }
4798 
4799 /** check whether indefinite constraint function is factorable and store corresponding coefficients */
4800 static
4802  SCIP* scip, /**< SCIP data structure */
4803  SCIP_CONS* cons /**< constraint */
4804  )
4805 {
4806  SCIP_BILINTERM* bilinterm;
4807  SCIP_CONSDATA* consdata;
4808  SCIP_Real* a;
4809  SCIP_Real* eigvals;
4810  SCIP_Real sigma1;
4811  SCIP_Real sigma2;
4812  SCIP_Bool success;
4813  int n;
4814  int i;
4815  int idx1;
4816  int idx2;
4817  int posidx;
4818  int negidx;
4819 
4820  assert(scip != NULL);
4821  assert(cons != NULL);
4822 
4823  consdata = SCIPconsGetData(cons);
4824  assert(consdata != NULL);
4825  assert(consdata->factorleft == NULL);
4826  assert(consdata->factorright == NULL);
4827 
4828  /* we don't need this if there are no bilinear terms */
4829  if( consdata->nbilinterms == 0 )
4830  return SCIP_OKAY;
4831 
4832  /* write constraint as lhs <= linear + x'^T A x' <= rhs where x' = (x,1) and
4833  * A = ( Q b/2 )
4834  * ( b^T/2 0 )
4835  * compute an eigenvalue factorization of A and check if there are one positive and one negative eigenvalue
4836  * 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
4837  * thus, x'^T A x' = sigma1^2 (v1^T x')^2 - sigma2^2 (v2^T x')^2
4838  * = (sigma1 (v1^T x') - sigma2 (v2^T x')) * (sigma1 (v1^T x') + sigma2 (v2^T x'))
4839  * we then store sigma1 v1^T - sigma2 v2^T as left factor coef, and sigma1 v1^T + sigma2 v2^T as right factor coef
4840  */
4841 
4842  /* if we already know that there are only positive or only negative eigenvalues, then don't try */
4843  if( consdata->iscurvchecked && (consdata->isconvex || consdata->isconcave) )
4844  return SCIP_OKAY;
4845 
4846  n = consdata->nquadvars + 1;
4847 
4848  /* @todo handle case n=3 explicitly */
4849 
4850  /* skip too large matrices */
4851  if( n > 50 )
4852  return SCIP_OKAY;
4853 
4854  /* need routine to compute eigenvalues/eigenvectors */
4855  if( !SCIPisIpoptAvailableIpopt() )
4856  return SCIP_OKAY;
4857 
4858  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
4859 
4860  SCIP_CALL( SCIPallocBufferArray(scip, &a, n*n) );
4861  BMSclearMemoryArray(a, n*n);
4862 
4863  /* set lower triangular entries of A corresponding to bilinear terms */
4864  for( i = 0; i < consdata->nbilinterms; ++i )
4865  {
4866  bilinterm = &consdata->bilinterms[i];
4867 
4868  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var1, &idx1) );
4869  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var2, &idx2) );
4870  assert(idx1 >= 0);
4871  assert(idx2 >= 0);
4872  assert(idx1 != idx2);
4873 
4874  a[MIN(idx1,idx2) * n + MAX(idx1,idx2)] = bilinterm->coef / 2.0;
4875  }
4876 
4877  /* set lower triangular entries of A corresponding to square and linear terms */
4878  for( i = 0; i < consdata->nquadvars; ++i )
4879  {
4880  a[i*n + i] = consdata->quadvarterms[i].sqrcoef;
4881  a[i*n + n-1] = consdata->quadvarterms[i].lincoef / 2.0;
4882  }
4883 
4884  SCIP_CALL( SCIPallocBufferArray(scip, &eigvals, n) );
4885  if( LapackDsyev(TRUE, n, a, eigvals) != SCIP_OKAY )
4886  {
4887  SCIPdebugMsg(scip, "Failed to compute eigenvalues and eigenvectors of augmented quadratic form matrix for constraint <%s>.\n", SCIPconsGetName(cons));
4888  goto CLEANUP;
4889  }
4890 
4891  /* check if there is exactly one positive and one negative eigenvalue */
4892  posidx = -1;
4893  negidx = -1;
4894  for( i = 0; i < n; ++i )
4895  {
4896  if( SCIPisPositive(scip, eigvals[i]) )
4897  {
4898  if( posidx == -1 )
4899  posidx = i;
4900  else
4901  break;
4902  }
4903  else if( SCIPisNegative(scip, eigvals[i]) )
4904  {
4905  if( negidx == -1 )
4906  negidx = i;
4907  else
4908  break;
4909  }
4910  }
4911  if( i < n || posidx == -1 || negidx == -1 )
4912  {
4913  SCIPdebugMsg(scip, "Augmented quadratic form of constraint <%s> is not factorable.\n", SCIPconsGetName(cons));
4914  goto CLEANUP;
4915  }
4916  assert(SCIPisPositive(scip, eigvals[posidx]));
4917  assert(SCIPisNegative(scip, eigvals[negidx]));
4918 
4919  /* compute factorleft and factorright */
4920  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->factorleft, consdata->nquadvars + 1) );
4921  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->factorright, consdata->nquadvars + 1) );
4922 
4923  /* eigenvectors are stored in a, inverse eigenvector matrix is transposed of a
4924  * it seems that v1 and v2 are at &a[posidx*n] and &a[negidx*n]
4925  */
4926  sigma1 = sqrt( eigvals[posidx]);
4927  sigma2 = sqrt(-eigvals[negidx]);
4928  for( i = 0; i < n; ++i )
4929  {
4930  consdata->factorleft[i] = sigma1 * a[posidx * n + i] - sigma2 * a[negidx * n + i];
4931  consdata->factorright[i] = sigma1 * a[posidx * n + i] + sigma2 * a[negidx * n + i];
4932  /* set almost-zero elements to zero */
4933  if( SCIPisZero(scip, consdata->factorleft[i]) )
4934  consdata->factorleft[i] = 0.0;
4935  if( SCIPisZero(scip, consdata->factorright[i]) )
4936  consdata->factorright[i] = 0.0;
4937  }
4938 
4939 #ifdef SCIP_DEBUG
4940  SCIPdebugMsg(scip, "constraint <%s> has factorable quadratic form: (%g", SCIPconsGetName(cons), consdata->factorleft[n-1]);
4941  for( i = 0; i < consdata->nquadvars; ++i )
4942  {
4943  if( consdata->factorleft[i] != 0.0 )
4944  SCIPdebugMsgPrint(scip, " %+g<%s>", consdata->factorleft[i], SCIPvarGetName(consdata->quadvarterms[i].var));
4945  }
4946  SCIPdebugMsgPrint(scip, ") * (%g", consdata->factorright[n-1]);
4947  for( i = 0; i < consdata->nquadvars; ++i )
4948  {
4949  if( consdata->factorright[i] != 0.0 )
4950  SCIPdebugMsgPrint(scip, " %+g<%s>", consdata->factorright[i], SCIPvarGetName(consdata->quadvarterms[i].var));
4951  }
4952  SCIPdebugMsgPrint(scip, ")\n");
4953 #endif
4954 
4955  /* check whether factorleft * factorright^T is matrix of augmented quadratic form
4956  * we check here only the nonzero entries from the quadratic form
4957  */
4958  success = TRUE;
4959 
4960  /* check bilinear terms */
4961  for( i = 0; i < consdata->nbilinterms; ++i )
4962  {
4963  bilinterm = &consdata->bilinterms[i];
4964 
4965  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var1, &idx1) );
4966  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var2, &idx2) );
4967 
4968  if( !SCIPisRelEQ(scip, consdata->factorleft[idx1] * consdata->factorright[idx2] + consdata->factorleft[idx2] * consdata->factorright[idx1], bilinterm->coef) )
4969  {
4970  success = FALSE;
4971  break;
4972  }
4973  }
4974 
4975  /* set lower triangular entries of A corresponding to square and linear terms */
4976  for( i = 0; i < consdata->nquadvars; ++i )
4977  {
4978  if( !SCIPisRelEQ(scip, consdata->factorleft[i] * consdata->factorright[i], consdata->quadvarterms[i].sqrcoef) )
4979  {
4980  success = FALSE;
4981  break;
4982  }
4983 
4984  if( !SCIPisRelEQ(scip, consdata->factorleft[n-1] * consdata->factorright[i] + consdata->factorleft[i] * consdata->factorright[n-1], consdata->quadvarterms[i].lincoef) )
4985  {
4986  success = FALSE;
4987  break;
4988  }
4989  }
4990 
4991  if( !success )
4992  {
4993  SCIPdebugMsg(scip, "Factorization not accurate enough. Dropping it.\n");
4994  SCIPfreeBlockMemoryArray(scip, &consdata->factorleft, consdata->nquadvars + 1);
4995  SCIPfreeBlockMemoryArray(scip, &consdata->factorright, consdata->nquadvars + 1);
4996  }
4997 
4998  CLEANUP:
4999  SCIPfreeBufferArray(scip, &a);
5000  SCIPfreeBufferArray(scip, &eigvals);
5001 
5002  return SCIP_OKAY;
5003 }
5004 
5005 /** gets maximal absolute value in gradient of quadratic function */
5006 static
5008  SCIP* scip, /**< SCIP data structure */
5009  SCIP_CONS* cons, /**< constraint */
5010  SCIP_SOL* sol /**< solution or NULL if LP solution should be used */
5011  )
5012 {
5013  SCIP_CONSDATA* consdata;
5014  SCIP_Real maxelem;
5015  SCIP_Real g;
5016  int i, j, k;
5017  SCIP_VAR* var;
5018 
5019  assert(scip != NULL);
5020  assert(cons != NULL);
5021 
5022  consdata = SCIPconsGetData(cons);
5023  assert(consdata != NULL);
5024 
5025  if( SCIPgetStage(scip) != SCIP_STAGE_SOLVING )
5026  {
5027  maxelem = 0.0;
5028  for( i = 0; i < consdata->nlinvars; ++i )
5029  if( REALABS(consdata->lincoefs[i]) > maxelem )
5030  maxelem = REALABS(consdata->lincoefs[i]);
5031  }
5032  else
5033  maxelem = consdata->lincoefsmax;
5034 
5035  for( i = 0; i < consdata->nquadvars; ++i )
5036  {
5037  var = consdata->quadvarterms[i].var;
5038  assert(!SCIPisInfinity(scip, SCIPgetSolVal(scip, sol, var)));
5039  assert(!SCIPisInfinity(scip, -SCIPgetSolVal(scip, sol, var)));
5040  g = consdata->quadvarterms[i].lincoef;
5041  g += 2.0 * consdata->quadvarterms[i].sqrcoef * SCIPgetSolVal(scip, sol, var);
5042  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
5043  {
5044  k = consdata->quadvarterms[i].adjbilin[j];
5045  if( consdata->bilinterms[k].var1 == var )
5046  g += consdata->bilinterms[k].coef * SCIPgetSolVal(scip, sol, consdata->bilinterms[k].var2);
5047  else
5048  g += consdata->bilinterms[k].coef * SCIPgetSolVal(scip, sol, consdata->bilinterms[k].var1);
5049  }
5050  if( REALABS(g) > maxelem )
5051  maxelem = REALABS(g);
5052  }
5053 
5054  return maxelem;
5055 }
5056 
5057 /** computes activity and violation of a constraint
5058  *
5059  * If solution violates bounds by more than feastol, the violation is still computed, but *solviolbounds is set to TRUE
5060  */
5061 static
5063  SCIP* scip, /**< SCIP data structure */
5064  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5065  SCIP_CONS* cons, /**< constraint */
5066  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
5067  SCIP_Bool* solviolbounds /**< buffer to store whether quadratic variables in solution are outside their bounds by more than feastol */
5068  )
5069 { /*lint --e{666}*/
5070  SCIP_CONSHDLRDATA* conshdlrdata;
5071  SCIP_CONSDATA* consdata;
5072  SCIP_Real varval;
5073  SCIP_Real varval2;
5074  SCIP_VAR* var;
5075  SCIP_VAR* var2;
5076  int i;
5077  int j;
5078 
5079  assert(scip != NULL);
5080  assert(cons != NULL);
5081  assert(solviolbounds != NULL);
5082 
5083  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5084  assert(conshdlrdata != NULL);
5085 
5086  consdata = SCIPconsGetData(cons);
5087  assert(consdata != NULL);
5088 
5089  *solviolbounds = FALSE;
5090  consdata->activity = 0.0;
5091  consdata->lhsviol = 0.0;
5092  consdata->rhsviol = 0.0;
5093 
5094  for( i = 0; i < consdata->nlinvars; ++i )
5095  {
5096  SCIP_Real activity;
5097 
5098  var = consdata->linvars[i];
5099  varval = SCIPgetSolVal(scip, sol, var);
5100  activity = consdata->lincoefs[i] * varval;
5101 
5102  /* the contribution of a variable with |varval| = +inf is +inf when activity > 0.0, -inf when activity < 0.0, and
5103  * 0.0 otherwise
5104  */
5105  if( SCIPisInfinity(scip, REALABS(varval)) )
5106  {
5107  if( activity > 0.0 && !SCIPisInfinity(scip, consdata->rhs) )
5108  {
5109  consdata->activity = SCIPinfinity(scip);
5110  consdata->rhsviol = SCIPinfinity(scip);
5111  return SCIP_OKAY;
5112  }
5113 
5114  if( activity < 0.0 && !SCIPisInfinity(scip, -consdata->lhs) )
5115  {
5116  consdata->activity = -SCIPinfinity(scip);
5117  consdata->lhsviol = SCIPinfinity(scip);
5118  return SCIP_OKAY;
5119  }
5120  }
5121 
5122  consdata->activity += activity;
5123  }
5124 
5125  for( j = 0; j < consdata->nquadvars; ++j )
5126  {
5127  SCIP_Real activity;
5128 
5129  var = consdata->quadvarterms[j].var;
5130  varval = SCIPgetSolVal(scip, sol, var);
5131  activity = (consdata->quadvarterms[j].lincoef + consdata->quadvarterms[j].sqrcoef * varval) * varval;
5132 
5133  /* the contribution of a variable with |varval| = +inf is +inf when activity > 0.0, -inf when activity < 0.0, and
5134  * 0.0 otherwise
5135  */
5136  if( SCIPisInfinity(scip, REALABS(varval)) )
5137  {
5138  if( activity > 0.0 && !SCIPisInfinity(scip, consdata->rhs) )
5139  {
5140  consdata->activity = SCIPinfinity(scip);
5141  consdata->rhsviol = SCIPinfinity(scip);
5142  return SCIP_OKAY;
5143  }
5144 
5145  if( activity < 0.0 && !SCIPisInfinity(scip, -consdata->lhs) )
5146  {
5147  consdata->activity = -SCIPinfinity(scip);
5148  consdata->lhsviol = SCIPinfinity(scip);
5149  return SCIP_OKAY;
5150  }
5151  }
5152 
5153  /* project onto local box, in case the LP solution is slightly outside the bounds (which is not our job to enforce) */
5154  if( sol == NULL )
5155  {
5156  /* 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 */
5157  if( (!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) && !SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var))) ||
5158  (!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) && !SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var))) )
5159  *solviolbounds = TRUE;
5160  else
5161  {
5162  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
5163  activity = (consdata->quadvarterms[j].lincoef + consdata->quadvarterms[j].sqrcoef * varval) * varval;
5164  }
5165  }
5166 
5167  consdata->activity += activity;
5168  }
5169 
5170  for( j = 0; j < consdata->nbilinterms; ++j )
5171  {
5172  SCIP_Real activity;
5173 
5174  var = consdata->bilinterms[j].var1;
5175  var2 = consdata->bilinterms[j].var2;
5176  varval = SCIPgetSolVal(scip, sol, var);
5177  varval2 = SCIPgetSolVal(scip, sol, var2);
5178 
5179  /* project onto local box, in case the LP solution is slightly outside the bounds (which is not our job to enforce) */
5180  if( sol == NULL )
5181  {
5182  /* 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 */
5183  if( (!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) && !SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var))) ||
5184  (!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) && !SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var))) )
5185  *solviolbounds = TRUE;
5186  else
5187  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
5188 
5189  /* 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 */
5190  if( (!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var2)) && !SCIPisFeasGE(scip, varval2, SCIPvarGetLbLocal(var2))) ||
5191  (!SCIPisInfinity(scip, SCIPvarGetUbLocal(var2)) && !SCIPisFeasLE(scip, varval2, SCIPvarGetUbLocal(var2))) )
5192  *solviolbounds = TRUE;
5193  else
5194  varval2 = MAX(SCIPvarGetLbLocal(var2), MIN(SCIPvarGetUbLocal(var2), varval2));
5195  }
5196 
5197  activity = consdata->bilinterms[j].coef * varval * varval2;
5198 
5199  /* consider var*var2 as a new variable and handle it as it would appear linearly */
5200  if( SCIPisInfinity(scip, REALABS(varval*varval2)) )
5201  {
5202  if( activity > 0.0 && !SCIPisInfinity(scip, consdata->rhs) )
5203  {
5204  consdata->activity = SCIPinfinity(scip);
5205  consdata->rhsviol = SCIPinfinity(scip);
5206  return SCIP_OKAY;
5207  }
5208 
5209  if( activity < 0.0 && !SCIPisInfinity(scip, -consdata->lhs) )
5210  {
5211  consdata->activity = -SCIPinfinity(scip);
5212  consdata->lhsviol = SCIPinfinity(scip);
5213  return SCIP_OKAY;
5214  }
5215  }
5216 
5217  consdata->activity += activity;
5218  }
5219 
5220  /* compute absolute violation left hand side */
5221  if( consdata->activity < consdata->lhs && !SCIPisInfinity(scip, -consdata->lhs) )
5222  consdata->lhsviol = consdata->lhs - consdata->activity;
5223  else
5224  consdata->lhsviol = 0.0;
5225 
5226  /* compute absolute violation right hand side */
5227  if( consdata->activity > consdata->rhs && !SCIPisInfinity(scip, consdata->rhs) )
5228  consdata->rhsviol = consdata->activity - consdata->rhs;
5229  else
5230  consdata->rhsviol = 0.0;
5231 
5232  switch( conshdlrdata->scaling )
5233  {
5234  case 'o' :
5235  /* no scaling */
5236  break;
5237 
5238  case 'g' :
5239  /* scale by sup-norm of gradient in current point */
5240  if( consdata->lhsviol > 0.0 || consdata->rhsviol > 0.0 )
5241  {
5242  SCIP_Real norm;
5243  norm = getGradientMaxElement(scip, cons, sol);
5244  if( norm > 1.0 )
5245  {
5246  consdata->lhsviol /= norm;
5247  consdata->rhsviol /= norm;
5248  }
5249  }
5250  break;
5251 
5252  case 's' :
5253  /* scale by left/right hand side of constraint */
5254  if( consdata->lhsviol > 0.0 )
5255  consdata->lhsviol /= MAX(1.0, REALABS(consdata->lhs));
5256 
5257  if( consdata->rhsviol > 0.0 )
5258  consdata->rhsviol /= MAX(1.0, REALABS(consdata->rhs));
5259 
5260  break;
5261 
5262  default :
5263  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
5264  SCIPABORT();
5265  return SCIP_INVALIDDATA; /*lint !e527*/
5266  }
5267 
5268  return SCIP_OKAY;
5269 }
5270 
5271 /** computes violation of a set of constraints */
5272 static
5274  SCIP* scip, /**< SCIP data structure */
5275  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5276  SCIP_CONS** conss, /**< constraints */
5277  int nconss, /**< number of constraints */
5278  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
5279  SCIP_Bool* solviolbounds, /**< buffer to store whether quadratic variables in solution are outside their bounds by more than feastol in some constraint */
5280  SCIP_CONS** maxviolcon /**< buffer to store constraint with largest violation, or NULL if solution is feasible */
5281  )
5282 {
5283  SCIP_CONSDATA* consdata;
5284  SCIP_Real viol;
5285  SCIP_Real maxviol;
5286  SCIP_Bool solviolbounds1;
5287  int c;
5288 
5289  assert(scip != NULL);
5290  assert(conss != NULL || nconss == 0);
5291  assert(solviolbounds != NULL);
5292  assert(maxviolcon != NULL);
5293 
5294  *solviolbounds = FALSE;
5295  *maxviolcon = NULL;
5296 
5297  maxviol = 0.0;
5298 
5299  for( c = 0; c < nconss; ++c )
5300  {
5301  assert(conss != NULL);
5302  assert(conss[c] != NULL);
5303 
5304  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], sol, &solviolbounds1) );
5305  *solviolbounds |= solviolbounds1;
5306 
5307  consdata = SCIPconsGetData(conss[c]);
5308  assert(consdata != NULL);
5309 
5310  viol = MAX(consdata->lhsviol, consdata->rhsviol);
5311  if( viol > maxviol && SCIPisGT(scip, viol, SCIPfeastol(scip)) )
5312  {
5313  maxviol = viol;
5314  *maxviolcon = conss[c];
5315  }
5316  }
5317 
5318  return SCIP_OKAY;
5319 }
5320 
5321 /** tries to compute cut for multleft * <coefleft, x'> * multright <= rhs / (multright * <coefright, x'>) where x'=(x,1) */
5322 static
5324  SCIP* scip, /**< SCIP data structure */
5325  SCIP_CONS* cons, /**< constraint */
5326  SCIP_Real* ref, /**< reference solution where to generate the cut */
5327  SCIP_Real multleft, /**< multiplicator on lhs */
5328  SCIP_Real* coefleft, /**< coefficient for factor on lhs */
5329  SCIP_Real multright, /**< multiplicator on both sides */
5330  SCIP_Real* coefright, /**< coefficient for factor that goes to rhs */
5331  SCIP_Real rightminactivity, /**< minimal activity of <coefright, x> */
5332  SCIP_Real rightmaxactivity, /**< maximal activity of <coefright, x> */
5333  SCIP_Real rhs, /**< denominator on rhs */
5334  SCIP_ROWPREP* rowprep, /**< rowprep to store cut coefs and constant */
5335  SCIP_Bool* success /**< buffer to indicate whether a cut was successfully computed */
5336  )
5337 {
5338  SCIP_CONSDATA* consdata;
5339  SCIP_Real constant;
5340  SCIP_Real coef;
5341  int i;
5342 
5343  assert(rowprep != NULL);
5344  assert(rightminactivity * multright > 0.0);
5345  assert(rightmaxactivity * multright > 0.0);
5346  assert(multright == 1.0 || multright == -1.0);
5347 
5348  consdata = SCIPconsGetData(cons);
5349  assert(consdata != NULL);
5350 
5351  rowprep->sidetype = SCIP_SIDETYPE_RIGHT;
5352 
5353  if( rhs > 0.0 )
5354  {
5355  /* if rhs > 0.0, then rhs / (multright * <coefright, x'>) is convex, thus need secant:
5356  * 1 / multright*<coefright, x'> <= 1/minact + 1/maxact - 1/(minact * maxact) multright*<coefright, x'>
5357  * where [minact, maxact] = multright * [rightminactivity, rightmaxactivity]
5358  *
5359  * assuming multright is either -1 or 1, and substituting gives
5360  * multright/rightminactivity + multright/rightmaxactivity - multright/(rightminactivity * rightmaxactivity) *<coefright, x'>
5361  *
5362  * multiplying by rhs, gives the estimate
5363  * rhs / (multright * <coefright, x'>) <= rhs * multright * (1/rightminactivity + 1/rightmaxactivity - 1/(rightminactivity * rightmaxactivity) * <coefright, x'>)
5364  */
5365 
5366  /* cannot do if unbounded */
5367  if( SCIPisInfinity(scip, rightmaxactivity * multright) )
5368  {
5369  *success = FALSE;
5370  return SCIP_OKAY;
5371  }
5372 
5373  assert(SCIPisFeasLE(scip, rightminactivity, rightmaxactivity));
5374 
5375  constant = multleft * multright * coefleft[consdata->nquadvars];
5376  constant -= rhs * multright * (1.0 / rightminactivity + 1.0 / rightmaxactivity);
5377  constant += rhs * multright * coefright[consdata->nquadvars] / (rightminactivity * rightmaxactivity);
5378 
5379  SCIPaddRowprepConstant(rowprep, constant);
5380 
5381  for( i = 0; i < consdata->nquadvars; ++i )
5382  {
5383  coef = multleft * multright * coefleft[i];
5384  coef += rhs * multright / (rightminactivity * rightmaxactivity) * coefright[i];
5385  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, consdata->quadvarterms[i].var, coef) );
5386  }
5387 
5388  (void) SCIPsnprintf(rowprep->name, SCIP_MAXSTRLEN, "%s_factorablesecant_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
5389  }
5390  else
5391  {
5392  SCIP_Real refvalue;
5393 
5394  /* if rhs < 0.0, then rhs / (multright * <coefright, x'>) is convex, thus need linearization:
5395  * rhs / (multright * <coefright, x'>)
5396  * <= rhs / (multright * <coefright, ref'>) - rhs / (multright * <coefright, ref'>)^2 * (multright * <coefright, x'> - multright * <coefright, ref'>)
5397  * = 2*rhs / (multright * <coefright, ref'>) - rhs / (multright * <coefright, ref'>)^2 * (multright * <coefright, x'>)
5398  *
5399  * where ref' = (ref, 1)
5400  */
5401 
5402  /* compute <coefright, ref'> */
5403  refvalue = coefright[consdata->nquadvars];
5404  for( i = 0; i < consdata->nquadvars; ++i )
5405  refvalue += coefright[i] * ref[i];
5406 
5407  /* should not happen, since we checked activity of <coefright,x> before, and assume ref within bounds */
5408  assert(!SCIPisZero(scip, refvalue));
5409 
5410  constant = multleft * multright * coefleft[consdata->nquadvars];
5411  constant -= 2.0 * rhs / (multright * refvalue);
5412  constant += rhs / (refvalue * refvalue) * multright * coefright[consdata->nquadvars];
5413 
5414  SCIPaddRowprepConstant(rowprep, constant);
5415 
5416  for( i = 0; i < consdata->nquadvars; ++i )
5417  {
5418  coef = multleft * multright * coefleft[i];
5419  coef += rhs / (refvalue * refvalue) * multright * coefright[i];
5420  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, consdata->quadvarterms[i].var, coef) );
5421  }
5422 
5423  (void) SCIPsnprintf(rowprep->name, SCIP_MAXSTRLEN, "%s_factorablelinearization_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
5424  }
5425 
5426  /* @todo does not always need to be local */
5427  rowprep->local = TRUE;
5428  *success = TRUE;
5429 
5430  return SCIP_OKAY;
5431 }
5432 
5433 /** tries to generate a cut if constraint quadratic function is factorable and there are no linear variables
5434  * (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
5435  */
5436 static
5438  SCIP* scip, /**< SCIP data structure */
5439  SCIP_CONS* cons, /**< constraint */
5440  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
5441  SCIP_Real* ref, /**< reference solution where to generate the cut */
5442  SCIP_ROWPREP* rowprep, /**< data structure to store cut coefficients */
5443  SCIP_Bool* success /**< buffer to indicate whether a cut was successfully computed */
5444  )
5445 {
5446  SCIP_CONSDATA* consdata;
5447  SCIP_Real leftminactivity;
5448  SCIP_Real leftmaxactivity;
5449  SCIP_Real rightminactivity;
5450  SCIP_Real rightmaxactivity;
5451  SCIP_Real multleft;
5452  SCIP_Real multright;
5453  SCIP_Real rhs;
5454  int i;
5455 
5456  assert(scip != NULL);
5457  assert(cons != NULL);
5458  assert(ref != NULL);
5459  assert(rowprep != NULL);
5460  assert(success != NULL);
5461 
5462  consdata = SCIPconsGetData(cons);
5463  assert(consdata != NULL);
5464  assert(consdata->nlinvars == 0);
5465  assert(consdata->factorleft != NULL);
5466  assert(consdata->factorright != NULL);
5467 
5468  *success = FALSE;
5469 
5470  leftminactivity = consdata->factorleft[consdata->nquadvars];
5471  leftmaxactivity = consdata->factorleft[consdata->nquadvars];
5472  rightminactivity = consdata->factorright[consdata->nquadvars];
5473  rightmaxactivity = consdata->factorright[consdata->nquadvars];
5474  for( i = 0; i < consdata->nquadvars; ++i )
5475  {
5476  if( !SCIPisInfinity(scip, -leftminactivity) )
5477  {
5478  if( consdata->factorleft[i] > 0.0 )
5479  {
5480  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
5481  leftminactivity = -SCIPinfinity(scip);
5482  else
5483  leftminactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
5484  }
5485  else if( consdata->factorleft[i] < 0.0 )
5486  {
5487  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
5488  leftminactivity = -SCIPinfinity(scip);
5489  else
5490  leftminactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
5491  }
5492  }
5493  if( !SCIPisInfinity(scip, leftmaxactivity) )
5494  {
5495  if( consdata->factorleft[i] > 0.0 )
5496  {
5497  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
5498  leftmaxactivity = SCIPinfinity(scip);
5499  else
5500  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
5501  }
5502  else if( consdata->factorleft[i] < 0.0 )
5503  {
5504  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
5505  leftmaxactivity = SCIPinfinity(scip);
5506  else
5507  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
5508  }
5509  }
5510 
5511  if( !SCIPisInfinity(scip, -rightminactivity) )
5512  {
5513  if( consdata->factorright[i] > 0.0 )
5514  {
5515  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
5516  rightminactivity = -SCIPinfinity(scip);
5517  else
5518  rightminactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
5519  }
5520  else if( consdata->factorright[i] < 0.0 )
5521  {
5522  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
5523  rightminactivity = -SCIPinfinity(scip);
5524  else
5525  rightminactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
5526  }
5527  }
5528  if( !SCIPisInfinity(scip, rightmaxactivity) )
5529  {
5530  if( consdata->factorright[i] > 0.0 )
5531  {
5532  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
5533  rightmaxactivity = SCIPinfinity(scip);
5534  else
5535  rightmaxactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
5536  }
5537  else if( consdata->factorright[i] < 0.0 )
5538  {
5539  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
5540  rightmaxactivity = SCIPinfinity(scip);
5541  else
5542  rightmaxactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
5543  }
5544  }
5545  }
5546 
5547  /* write violated constraints as multleft * factorleft * factorright <= rhs */
5548  if( violside == SCIP_SIDETYPE_RIGHT )
5549  {
5550  rhs = consdata->rhs;
5551  multleft = 1.0;
5552  }
5553  else
5554  {
5555  rhs = -consdata->lhs;
5556  multleft = -1.0;
5557  }
5558 
5559  if( SCIPisZero(scip, rhs) )
5560  {
5561  /* @todo do something for rhs == 0.0? */
5562  return SCIP_OKAY;
5563  }
5564 
5565  if( !SCIPisFeasPositive(scip, leftminactivity) && !SCIPisFeasNegative(scip, leftmaxactivity) )
5566  {
5567  /* left factor has 0 within activity bounds, or is very close, at least */
5568  if( !SCIPisFeasPositive(scip, rightminactivity) && !SCIPisFeasNegative(scip, rightmaxactivity) )
5569  {
5570  /* right factor also has 0 within activity bounds, or is very close, at least
5571  * -> cannot separate
5572  */
5573  return SCIP_OKAY;
5574  }
5575 
5576  /* write violated constraint as multleft * factorleft * multright * (multright * factorright) <= rhs
5577  * such that multright * factorright > 0.0
5578  */
5579  if( rightminactivity < 0.0 )
5580  multright = -1.0;
5581  else
5582  multright = 1.0;
5583 
5584  /* generate cut for multleft * factorleft * multright <= rhs / (factorright * multright) */
5585  SCIP_CALL( generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorleft, multright, consdata->factorright, rightminactivity, rightmaxactivity, rhs, rowprep, success) );
5586  }
5587  else if( !SCIPisFeasPositive(scip, rightminactivity) && !SCIPisFeasNegative(scip, rightmaxactivity) )
5588  {
5589  /* left factor is bounded away from 0
5590  * right factor has 0 within activity bounds, or is very close, at least
5591  * -> so divide by left factor
5592  */
5593 
5594  /* write violated constraint as multleft * factorright * multright * (multright * factorleft) <= rhs
5595  * such that multright * factorleft > 0.0
5596  */
5597  if( leftminactivity < 0.0 )
5598  multright = -1.0;
5599  else
5600  multright = 1.0;
5601 
5602  /* generate cut for multleft * factorright * multright <= rhs / (factorleft * multright) */
5603  SCIP_CALL( generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorright, multright, consdata->factorleft, leftminactivity, leftmaxactivity, rhs, rowprep, success) );
5604  }
5605  else if( SCIPisInfinity(scip, -leftminactivity) || SCIPisInfinity(scip, leftmaxactivity) ||
5606  (!SCIPisInfinity(scip, -rightminactivity) && !SCIPisInfinity(scip, rightmaxactivity) && rightmaxactivity - rightminactivity < leftmaxactivity - leftminactivity) )
5607  {
5608  /* both factors are bounded away from 0, but the right one has a smaller activity range, so divide by that one */
5609 
5610  /* write violated constraint as multleft * factorleft * multright * (multright * factorright) <= rhs
5611  * such that multright * factorright > 0.0
5612  */
5613  if( rightminactivity < 0.0 )
5614  multright = -1.0;
5615  else
5616  multright = 1.0;
5617 
5618  /* generate cut for multleft * factorleft * multright <= rhs / (factorright * multright) */
5619  SCIP_CALL( generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorleft, multright, consdata->factorright, rightminactivity, rightmaxactivity, rhs, rowprep, success) );
5620  }
5621  else
5622  {
5623  /* both factors are bounded away from 0, but the left one has a smaller activity range, so divide by that one */
5624 
5625  /* write violated constraint as multleft * factorright * multright * (multright * factorleft) <= rhs
5626  * such that multright * factorleft > 0.0
5627  */
5628  if( leftminactivity < 0.0 )
5629  multright = -1.0;
5630  else
5631  multright = 1.0;
5632 
5633  /* generate cut for multleft * factorright * multright <= rhs / (factorleft * multright) */
5634  SCIP_CALL( generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorright, multright, consdata->factorleft, leftminactivity, leftmaxactivity, rhs, rowprep, success) );
5635  }
5636 
5637  return SCIP_OKAY;
5638 }
5639 
5640 /* finds intersections of a parametric line (x,y) = (x0,y0) + t [(x1,y1) - (x0,y0)] on curves x*y = wl and x*y = wu;
5641  * returns TRUE if unsuccessful and FALSE otherwise
5642  */
5643 static
5645  SCIP* scip,
5646  SCIP_Real x0,
5647  SCIP_Real y0_,
5648  SCIP_Real x1,
5649  SCIP_Real y1_,
5650  SCIP_Real wl,
5651  SCIP_Real wu,
5652  SCIP_Real* xl,
5653  SCIP_Real* yl,
5654  SCIP_Real* xu,
5655  SCIP_Real* yu
5656  )
5657 {
5658  SCIP_Real a;
5659  SCIP_Real b;
5660  SCIP_Real c;
5661  SCIP_Real tl;
5662  SCIP_Real tu;
5663 
5664  assert(wl == SCIP_INVALID || (xl != NULL && yl != NULL)); /*lint !e777 */
5665  assert(wu == SCIP_INVALID || (xu != NULL && yu != NULL)); /*lint !e777 */
5666 
5667  /* The parametric line is of the form
5668  *
5669  * x = x0 + t (x1-x0)
5670  * y = y0 + t (y1-y0)
5671  *
5672  * and for that to satisfy xy = wl and xy = wu we must have
5673  *
5674  * x0 y0 + t [x0 (y1-y0) + y0 (x1-x0)] + t^2 (x1-x0) (y1-y0) = wl
5675  * = wu
5676  *
5677  * or a t^2 + b t + c - wl = 0 for proper values of a,b,c.
5678  * a t^2 + b t + c - wu = 0
5679  *
5680  * Because of the way this procedure will be used, one of the two
5681  * solutions found we must always use the minimum nonnegative one
5682  */
5683 
5684  a = (x1 - x0) * (y1_ - y0_);
5685  c = x0 * y0_;
5686  b = x0 * y1_ + y0_ * x1 - 2.0 * c;
5687 
5688  tl = 0.0;
5689  tu = 0.0;
5690 
5691  if( !SCIPisZero(scip, (SCIP_Real)a) )
5692  {
5693  if( wl != SCIP_INVALID ) /*lint !e777 */
5694  {
5695  SCIP_Real tl1;
5696  SCIP_Real tl2;
5697  SCIP_Real denom;
5698  SCIP_Real q;
5699 
5700  if( b * b - 4.0 * a * (c - wl) < 0.0 )
5701  {
5702  SCIPdebugMsg(scip, "probable numerical difficulties, give up\n");
5703  return TRUE;
5704  }
5705 
5706  denom = sqrt(b * b - 4.0 * a * (c - wl));
5707  q = -0.5 * (b + COPYSIGN(denom, b));
5708  tl1 = q / a;
5709  tl2 = (c - wl) / q;
5710 
5711  /* choose the smallest non-negative root */
5712  tl = (tl1 >= 0.0 && (tl2 < 0.0 || tl1 < tl2)) ? tl1 : tl2;
5713  }
5714 
5715  if( wu != SCIP_INVALID ) /*lint !e777 */
5716  {
5717  SCIP_Real tu1;
5718  SCIP_Real tu2;
5719  SCIP_Real denom;
5720  SCIP_Real q;
5721 
5722  if( b * b - 4.0 * a * (c - wu) < 0.0 )
5723  {
5724  SCIPdebugMsg(scip, "probable numerical difficulties, give up\n");
5725  return TRUE;
5726  }
5727 
5728  denom = sqrt(b * b - 4.0 * a * (c - wu));
5729  q = -0.5 * (b + COPYSIGN(denom, b));
5730  tu1 = q / a;
5731  tu2 = (c - wu) / q;
5732 
5733  /* choose the smallest non-negative root */
5734  tu = (tu1 >= 0.0 && (tu2 < 0.0 || tu1 < tu2)) ? tu1 : tu2;
5735  }
5736  }
5737  else if( !SCIPisZero(scip, (SCIP_Real)b) )
5738  {
5739  if( wl != SCIP_INVALID ) /*lint !e777 */
5740  tl = (wl - c) / b;
5741  if( wu != SCIP_INVALID ) /*lint !e777 */
5742  tu = (wu - c) / b;
5743  }
5744  else
5745  {
5746  /* no or infinitely many solutions */
5747  return TRUE;
5748  }
5749 
5750  if( wl != SCIP_INVALID ) /*lint !e777 */
5751  {
5752  *xl = (SCIP_Real)(x0 + tl * (x1 - x0 ));
5753  *yl = (SCIP_Real)(y0_ + tl * (y1_ - y0_));
5754 
5755  if( !SCIPisRelEQ(scip, *xl * *yl, wl) )
5756  {
5757  SCIPdebugMsg(scip, "probable numerical difficulties, give up\n");
5758  return TRUE;
5759  }
5760  }
5761 
5762  if( wu != SCIP_INVALID ) /*lint !e777 */
5763  {
5764  *xu = (SCIP_Real)(x0 + tu * (x1 - x0));
5765  *yu = (SCIP_Real)(y0_ + tu * (y1_ - y0_));
5766 
5767  if( !SCIPisRelEQ(scip, *xu * *yu, wu) )
5768  {
5769  SCIPdebugMsg(scip, "probable numerical difficulties, give up\n");
5770  return TRUE;
5771  }
5772  }
5773 
5774  /* do not use the computed points if one of the components is infinite */
5775  if( (xu != NULL && SCIPisInfinity(scip, *xu)) || (xl != NULL && SCIPisInfinity(scip, -*xl)) ||
5776  (yu != NULL && SCIPisInfinity(scip, *yu)) || (yl != NULL && SCIPisInfinity(scip, -*yl)) )
5777  {
5778  SCIPdebugMsg(scip, "probable numerical difficulties, give up\n");
5779  return TRUE;
5780  }
5781 
5782  return FALSE;
5783 }
5784 
5785 /** generate coefficients for a plane through points (x1, y1_, x1*y1) and (x2, y2, x2*y2)
5786  * such that intersecting it with one of them (the first if whichuse is FALSE, the second otherwise)
5787  * gives a tangent to the curve x*y = k
5788  *
5789  * Returns TRUE on error and FALSE on success.
5790  */
5791 static
5793  SCIP* scip,
5794  SCIP_Real x1,
5795  SCIP_Real y1_,
5796  SCIP_Real x2,
5797  SCIP_Real y2,
5798  SCIP_Bool whichuse,
5799  SCIP_Real* cx,
5800  SCIP_Real* cy,
5801  SCIP_Real* cw
5802  )
5803 {
5804  SCIP_Real xd;
5805  SCIP_Real yd;
5806  SCIP_Real xo;
5807  SCIP_Real yo;
5808 
5809  assert(cx != NULL);
5810  assert(cy != NULL);
5811  assert(cw != NULL);
5812 
5813  /* the x-y slope of this constraint must be tangent to a curve x*y = k at (xD,yD) */
5814  if( !whichuse )
5815  {
5816  xd = x1;
5817  xo = x2;
5818  yd = y1_;
5819  yo = y2;
5820  }
5821  else
5822  {
5823  xd = x2;
5824  xo = x1;
5825  yd = y2;
5826  yo = y1_;
5827  }
5828 
5829  *cx = yd;
5830  *cy = xd;
5831 
5832  /* lift it so that it touches the other curve */
5833 
5834  /* if the two points are on the same curve, then no cut */
5835  if( SCIPisZero(scip, xo * yo - xd * yd) )
5836  return TRUE;
5837 
5838  /* should ALWAYS be negative */
5839  *cw = (2.0 * xd * yd - (*cx * xo + *cy * yo)) / (xo * yo - xd * yd);
5840 
5841  return FALSE;
5842 }
5843 
5844 /** computes coefficients of a lifted-tangent inequality for x*y = w
5845  *
5846  * The code is an adaptation of the methods in exprMul-upperHull.cpp in Couenne/stable/0.4 rev773,
5847  * written by P. Belotti and licensed under Eclipse Public License.
5848  */
5849 static
5851  SCIP* scip, /**< SCIP data structure */
5852  SCIP_Real xl, /**< lower bound on x */
5853  SCIP_Real xu, /**< upper bound on x */
5854  SCIP_Real x0, /**< reference point for x */
5855  SCIP_Real yl, /**< lower bound on y */
5856  SCIP_Real yu, /**< upper bound on y */
5857  SCIP_Real y0_, /**< reference point for y */
5858  SCIP_Real wl, /**< lower bound on w */
5859  SCIP_Real wu, /**< upper bound on w */
5860  SCIP_Real w0, /**< reference point for w */
5861  SCIP_Real* cx, /**< buffer where to store cut coefficient for x */
5862  SCIP_Real* cy, /**< buffer where to store cut coefficient for y */
5863  SCIP_Real* cw, /**< buffer where to store cut coefficient for w */
5864  SCIP_Real* c0, /**< buffer where to store cut left-hand-side */
5865  SCIP_Bool* success /**< buffer where to indicate whether cut coefficients were computed */
5866  )
5867 {
5868  SCIP_Bool flipx;
5869  SCIP_Bool flipy;
5870  SCIP_Bool flipw;
5871  SCIP_Real tmp;
5872  SCIP_Real xlow;
5873  SCIP_Real ylow;
5874  SCIP_Real xupp;
5875  SCIP_Real yupp;
5876  SCIP_Real c0x;
5877  SCIP_Real c0y;
5878  SCIP_Real c0w;
5879 
5880  assert(scip != NULL);
5881  assert(cx != NULL);
5882  assert(cy != NULL);
5883  assert(cw != NULL);
5884  assert(c0 != NULL);
5885  assert(success != NULL);
5886 
5887  *success = FALSE;
5888  *cx = 0.0;
5889  *cy = 0.0;
5890  *cw = 0.0;
5891  *c0 = 0.0;
5892 
5893  SCIPdebugMsg(scip, "entering points:\n");
5894  SCIPdebugMsg(scip, "x: %9g\t[%9g\t%9g]\n", x0, xl, xu);
5895  SCIPdebugMsg(scip, "y: %9g\t[%9g\t%9g]\n", y0_, yl, yu);
5896  SCIPdebugMsg(scip, "w: %9g\t[%9g\t%9g]\n", w0, wl, wu);
5897 
5898  /* generateCutLTI should have recognized these */
5899  assert(wl >= 0.0 || wu <= 0.0);
5900  assert(!SCIPisInfinity(scip, -wl));
5901  assert(!SCIPisInfinity(scip, wu));
5902 
5903  assert(SCIPisFeasGE(scip, x0, xl));
5904  assert(SCIPisFeasLE(scip, x0, xu));
5905  assert(SCIPisFeasGE(scip, y0_, yl));
5906  assert(SCIPisFeasLE(scip, y0_, yu));
5907 
5908  /* preliminary bound tightening */
5909  if( wl >= 0.0 )
5910  {
5911  if( xl >= 0.0 || yl >= 0.0 || SCIPisLT(scip, xl * yl, wl) )
5912  {
5913  xl = MAX(xl, 0.0);
5914  yl = MAX(yl, 0.0);
5915  }
5916  else if( xu <= 0.0 || yu <= 0.0 || SCIPisLT(scip, xu * yu, wl) )
5917  {
5918  xu = MIN(xu, 0.0);
5919  yu = MIN(yu, 0.0);
5920  }
5921  else
5922  {
5923  /* both variables have mixed sign (xl < 0 && xu > 0 && yl < 0 && yu > 0) and both xl*yl and xu*yu are feasible
5924  * cannot generate cut for this
5925  */
5926  return;
5927  }
5928  }
5929  else
5930  {
5931  if( xl >= 0.0 || yu <= 0.0 || SCIPisGT(scip, xl * yu, wu) )
5932  {
5933  xl = MAX(xl, 0.0);
5934  yu = MIN(yu, 0.0);
5935  }
5936  else if( xu <= 0.0 || yl >= 0.0 || SCIPisGT(scip, xu * yl, wu))
5937  {
5938  xu = MIN(xu, 0.0);
5939  yl = MAX(yl, 0.0);
5940  }
5941  else
5942  {
5943  /* both variables have mixed sign (xl < 0 && xu > 0 && yl < 0 && yu > 0) and both xl*yu and xu*yl are feasible
5944  * cannot generate cut for this
5945  */
5946  return;
5947  }
5948  }
5949 
5950  /* if x or y is fixed now or even infeasible, then do not think about a cut */
5951  if( SCIPisGE(scip, xl, xu) || SCIPisGE(scip, yl, yu) )
5952  return;
5953 
5954  /* reduce to positive orthant by flipping variables */
5955  if( xl < 0.0 )
5956  {
5957  flipx = TRUE;
5958  tmp = xu;
5959  xu = -xl;
5960  xl = -tmp;
5961  x0 = -x0;
5962  }
5963  else
5964  flipx = FALSE;
5965 
5966  if( yl < 0.0 )
5967  {
5968  flipy = TRUE;
5969  tmp = yu;
5970  yu = -yl;
5971  yl = -tmp;
5972  y0_ = -y0_;
5973  }
5974  else
5975  flipy = FALSE;
5976 
5977  if( flipx ^ flipy )
5978  {
5979  flipw = TRUE;
5980  tmp = wu;
5981  wu = -wl;
5982  wl = -tmp;
5983  w0 = -w0;
5984  }
5985  else
5986  flipw = FALSE;
5987 
5988  /* project refpoint into box not only for numerical reasons, but also due to preliminary bound tightening above */
5989  x0 = MIN(xu, MAX(x0, xl));
5990  y0_ = MIN(yu, MAX(y0_, yl));
5991  w0 = MIN(wu, MAX(w0, wl));
5992 
5993  SCIPdebugMsg(scip, "reduced points:\n");
5994  SCIPdebugMsg(scip, "x: %9g\t[%9g\t%9g]\n", x0, xl, xu);
5995  SCIPdebugMsg(scip, "y: %9g\t[%9g\t%9g]\n", y0_, yl, yu);
5996  SCIPdebugMsg(scip, "w: %9g\t[%9g\t%9g]\n", w0, wl, wu);
5997 
5998  if( SCIPisGE(scip, xl * yl, wl) && SCIPisLE(scip, xu * yu, wu) )
5999  {
6000  SCIPdebugMsg(scip, "box for x and y inside feasible region -> nothing to separate\n");
6001  return;
6002  }
6003  if( SCIPisGE(scip, x0 * y0_, w0) )
6004  {
6005  SCIPdebugMsg(scip, "point to separate not below curve -> cannot separate\n");
6006  return;
6007  }
6008 
6009  /* find intersections of halfline from origin
6010  * return if no proper point could be found
6011  */
6012  if( generateCutLTIfindIntersection(scip, 0.0, 0.0, x0, y0_, wl, wu, &xlow, &ylow, &xupp, &yupp) )
6013  return;
6014 
6015  SCIPdebugMsg(scip, "intersections:\n");
6016  SCIPdebugMsg(scip, "lower: %9g\t%9g\tprod %9g\n", xlow, ylow, xlow*ylow);
6017  SCIPdebugMsg(scip, "upper: %9g\t%9g\tprod %9g\n", xupp, yupp, xupp*yupp);
6018 
6019  /* Case 1: If both are outside of bounding box, either NW or SE, then McCormick is sufficient, so return */
6020  if( (xlow <= xl && yupp >= yu) || (ylow <= yl && xupp >= xu) )
6021  return;
6022 
6023  /* There will be at least one cut. Define coefficients and rhs ---will have to change them back if (flipX || flipY) */
6024  if( xlow >= xl && xupp <= xu && ylow >= yl && yupp <= yu )
6025  {
6026  /* Case 2: both are inside. Easy lifting... */
6027  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, FALSE, cx, cy, cw) )
6028  return;
6029 
6030  c0x = *cx * xlow;
6031  c0y = *cy * ylow;
6032  c0w = *cw * wl;
6033  }
6034  else if( xlow >= xl && ylow >= yl && (xupp > xu || yupp > yu) )
6035  {
6036  /* Case 3a and 3b: through lower curve, but not upper. */
6037  if( yupp > yu )
6038  {
6039  /* upper intersect is North; place it within box */
6040  assert(!SCIPisInfinity(scip, yu));
6041  yupp = yu;
6042  xupp = wu / yu;
6043  }
6044  else
6045  {
6046  /* upper intersect is East; place it within box */
6047  assert(!SCIPisInfinity(scip, xu));
6048  xupp = xu;
6049  yupp = wu / xu;
6050  }
6051 
6052  /* find intersection on low curve on half line through new point and (x0,y0_) */
6053  if( generateCutLTIfindIntersection(scip, xupp, yupp, x0, y0_, wl, SCIP_INVALID, &xlow, &ylow, NULL, NULL) )
6054  return;
6055 
6056  /* check whether McCormick is sufficient */
6057  if( xlow < xl || ylow < yl )
6058  return;
6059 
6060  /* lift inequality on lower point */
6061  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, FALSE, cx, cy, cw) )
6062  return;
6063 
6064  c0x = *cx * xlow;
6065  c0y = *cy * ylow;
6066  c0w = *cw * wl;
6067  }
6068  else if( xupp <= xu && yupp <= yu && (xlow < xl || ylow < yl) )
6069  {
6070  /* Case 4a and 4b: viceversa (lift for validity) */
6071  if( ylow < yl )
6072  {
6073  /* upper intersect is South; place it within box */
6074  assert(!SCIPisZero(scip, yl));
6075  ylow = yl;
6076  xlow = wl / yl;
6077  }
6078  else
6079  {
6080  /* upper intersect is West; place it within box */
6081  assert(!SCIPisZero(scip, xl));
6082  xlow = xl;
6083  ylow = wl / xl;
6084  }
6085 
6086  /* find intersection on low curve on half line through new point and (x0,y0) */
6087  if( generateCutLTIfindIntersection(scip, xlow, ylow, x0, y0_, SCIP_INVALID, wu, NULL, NULL, &xupp, &yupp) )
6088  return;
6089 
6090  /* check whether McCormick is sufficient */
6091  if( xupp > xu || yupp > yu )
6092  return;
6093 
6094  /* lift inequality on UPPER point */
6095  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, TRUE, cx, cy, cw) )
6096  return;
6097 
6098  c0x = *cx * xupp;
6099  c0y = *cy * yupp;
6100  c0w = *cw * wu;
6101  }
6102  else if( (xlow < xl && xupp > xu) || (ylow < yl && yupp > yu) )
6103  {
6104  /* Case 5: both outside of bounding box, N and S or W and E. */
6105 #if 0
6106  SCIP_Real xlow2;
6107  SCIP_Real ylow2;
6108  SCIP_Real xupp2;
6109  SCIP_Real yupp2;
6110 #endif
6111 
6112  if( ylow < yl )
6113  {
6114  /* upper intersect is South; place it within box */
6115  assert(!SCIPisZero(scip, yl));
6116  assert(!SCIPisZero(scip, yu));
6117  ylow = yl;
6118  yupp = yu;
6119  xlow = wl / yl;
6120  xupp = wu / yu;
6121  }
6122  else
6123  {
6124  /* upper intersect is West; place it within box */
6125  assert(!SCIPisZero(scip, xl));
6126  assert(!SCIPisZero(scip, xu));
6127  xlow = xl;
6128  xupp = xu;
6129  ylow = wl / xl;
6130  yupp = wu / xu;
6131  }
6132 
6133  SCIPdebugMsg(scip, "New intersections:\n");
6134  SCIPdebugMsg(scip, "lower: %9g\t%9g\tprod %9g\n", xlow, ylow, xlow*ylow);
6135  SCIPdebugMsg(scip, "upper: %9g\t%9g\tprod %9g\n", xupp, yupp, xupp*yupp);
6136 
6137 #if 1
6138  /* Nothing to find. Just separate two inequalities at the same point, just using different support */
6139  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, FALSE, cx, cy, cw) )
6140  {
6141  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, TRUE, cx, cy, cw) )
6142  return;
6143 
6144  c0x = *cx * xupp;
6145  c0y = *cy * yupp;
6146  c0w = *cw * wu;
6147  }
6148  else
6149  {
6150  c0x = *cx * xlow;
6151  c0y = *cy * ylow;
6152  c0w = *cw * wl;
6153  }
6154 
6155 #else
6156  /* find the intersection on the lower (upper) curve on the line through xLP and the upper (lower) point
6157  * this does not seem to work (cuts off solution at nous2), so it is disabled for now
6158  */
6159  if( generateCutLTIfindIntersection(scip, xlow, ylow, x0, y0_, SCIP_INVALID, wu, NULL, NULL, &xupp2, &yupp2) ||
6160  generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp2, yupp2, FALSE, cx, cx, cw) )
6161  {
6162  if( generateCutLTIfindIntersection(scip, xupp, yupp, x0, y0_, wl, SCIP_INVALID, &xlow2, &ylow2, NULL, NULL) ||
6163  generateCutLTIgenMulCoeff(scip, xlow2, ylow2, xupp, yupp, TRUE, cx, cy, cw) )
6164  return;
6165 
6166  c0x = *cx * xupp;
6167  c0y = *cy * yupp;
6168  c0w = *cw * wu;
6169  }
6170  else
6171  {
6172  c0x = *cx * xlow;
6173  c0y = *cy * ylow;
6174  c0w = *cw * wl;
6175  }
6176 #endif
6177  }
6178  else
6179  {
6180  SCIPdebugMsg(scip, "points are in a weird position:\n");
6181  SCIPdebugMsg(scip, "lower: %9g\t%9g\tprod %9g\n", xlow, ylow, xlow*ylow);
6182  SCIPdebugMsg(scip, "upper: %9g\t%9g\tprod %9g\n", xupp, yupp, xupp*yupp);
6183 
6184  return;
6185  }
6186 
6187  SCIPdebugMsg(scip, "cut w.r.t. reduced points: %gx-%g %+gy-%g %+gw-%g >= 0\n",
6188  *cx, c0x, *cy, c0y, *cw, c0w);
6189 
6190  /* re-transform back into original variables */
6191  if( flipx )
6192  *cx = -*cx;
6193  if( flipy )
6194  *cy = -*cy;
6195  if( flipw )
6196  *cw = -*cw;
6197 
6198  *c0 = c0x + c0y + c0w;
6199 
6200  *success = TRUE;
6201 }
6202 
6203 /** tries to generate a cut if constraint quadratic function is factorable and there are linear variables
6204  *
6205  * Computes what is called a lifted tangent inequality described in@n
6206  * Belotti, Miller, Namazifar, Lifted inequalities for bounded products of variables, SIAG/OPT Views-and-News 22:1, 2011
6207  */
6208 static
6210  SCIP* scip, /**< SCIP data structure */
6211  SCIP_CONS* cons, /**< constraint */
6212  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
6213  SCIP_Real* ref, /**< reference solution where to generate the cut */
6214  SCIP_SOL* sol, /**< solution that shall be cutoff, NULL for LP solution */
6215  SCIP_ROWPREP* rowprep, /**< rowprep to store cut data */
6216  SCIP_Bool* success /**< buffer to indicate whether a cut was successfully computed */
6217  )
6218 {
6219  SCIP_CONSDATA* consdata;
6220  SCIP_Real leftminactivity;
6221  SCIP_Real leftmaxactivity;
6222  SCIP_Real leftrefactivity;
6223  SCIP_Real rightminactivity;
6224  SCIP_Real rightmaxactivity;
6225  SCIP_Real rightrefactivity;
6226  SCIP_Real rhsminactivity;
6227  SCIP_Real rhsmaxactivity;
6228  SCIP_Real rhsrefactivity;
6229  SCIP_Real coefleft;
6230  SCIP_Real coefright;
6231  SCIP_Real coefrhs;
6232  SCIP_Real cutlhs;
6233  int i;
6234 
6235  assert(scip != NULL);
6236  assert(cons != NULL);
6237  assert(ref != NULL);
6238  assert(rowprep != NULL);
6239  assert(success != NULL);
6240  /* currently only separate LP solution or solutions given as SCIP_SOL, i.e., no cutgeneration during initlp */
6241  assert(sol != NULL || SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL);
6242 
6243  consdata = SCIPconsGetData(cons);
6244  assert(consdata != NULL);
6245  assert(consdata->nlinvars > 0);
6246  assert(consdata->factorleft != NULL);
6247  assert(consdata->factorright != NULL);
6248 
6249  *success = FALSE;
6250  rowprep->sidetype = SCIP_SIDETYPE_LEFT;
6251 
6252  /* write violated constraints as factorleft * factorright '==' rhs
6253  * where rhs are constraint sides - activity bound of linear part
6254  */
6255  rhsminactivity = consdata->lhs;
6256  rhsmaxactivity = consdata->rhs;
6257  rhsrefactivity = (violside == SCIP_SIDETYPE_LEFT ? consdata->lhs : consdata->rhs);
6258 
6259  for( i = 0; i < consdata->nlinvars; ++i )
6260  {
6261  if( !SCIPisInfinity(scip, -rhsminactivity) )
6262  {
6263  if( consdata->lincoefs[i] < 0.0 )
6264  {
6265  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i])) )
6266  rhsminactivity = -SCIPinfinity(scip);
6267  else
6268  rhsminactivity -= consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
6269  }
6270  else
6271  {
6272  assert(consdata->lincoefs[i] > 0.0);
6273  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i])) )
6274  rhsminactivity = -SCIPinfinity(scip);
6275  else
6276  rhsminactivity -= consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
6277  }
6278  }
6279  if( !SCIPisInfinity(scip, rhsmaxactivity) )
6280  {
6281  if( consdata->lincoefs[i] < 0.0 )
6282  {
6283  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i])) )
6284  rhsmaxactivity = SCIPinfinity(scip);
6285  else
6286  rhsmaxactivity -= consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
6287  }
6288  else
6289  {
6290  assert(consdata->lincoefs[i] > 0.0);
6291  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i])) )
6292  rhsmaxactivity = SCIPinfinity(scip);
6293  else
6294  rhsmaxactivity -= consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
6295  }
6296  }
6297  rhsrefactivity -= consdata->lincoefs[i] * SCIPgetSolVal(scip, sol, consdata->linvars[i]);
6298  }
6299 
6300  if( SCIPisInfinity(scip, -rhsminactivity) || SCIPisInfinity(scip, rhsmaxactivity) )
6301  {
6302  /* if right hand side is unbounded, then cannot do LTI */
6303  return SCIP_OKAY;
6304  }
6305 
6306  if( !SCIPisFeasPositive(scip, rhsminactivity) && !SCIPisFeasNegative(scip, rhsmaxactivity) )
6307  {
6308  /* if right hand side has 0 inside activity, then cannot do anything
6309  * if it has 0.0 as min or max activity, then a usual McCormick should be sufficient, too
6310  */
6311  return SCIP_OKAY;
6312  }
6313 
6314  leftminactivity = consdata->factorleft[consdata->nquadvars];
6315  leftmaxactivity = consdata->factorleft[consdata->nquadvars];
6316  leftrefactivity = consdata->factorleft[consdata->nquadvars];
6317  rightminactivity = consdata->factorright[consdata->nquadvars];
6318  rightmaxactivity = consdata->factorright[consdata->nquadvars];
6319  rightrefactivity = consdata->factorright[consdata->nquadvars];
6320  for( i = 0; i < consdata->nquadvars; ++i )
6321  {
6322  if( !SCIPisInfinity(scip, -leftminactivity) )
6323  {
6324  if( consdata->factorleft[i] > 0.0 )
6325  {
6326  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6327  leftminactivity = -SCIPinfinity(scip);
6328  else
6329  leftminactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6330  }
6331  else if( consdata->factorleft[i] < 0.0 )
6332  {
6333  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6334  leftminactivity = -SCIPinfinity(scip);
6335  else
6336  leftminactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6337  }
6338  }
6339  if( !SCIPisInfinity(scip, leftmaxactivity) )
6340  {
6341  if( consdata->factorleft[i] > 0.0 )
6342  {
6343  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6344  leftmaxactivity = SCIPinfinity(scip);
6345  else
6346  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6347  }
6348  else if( consdata->factorleft[i] < 0.0 )
6349  {
6350  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6351  leftmaxactivity = SCIPinfinity(scip);
6352  else
6353  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6354  }
6355  }
6356  leftrefactivity += consdata->factorleft[i] * ref[i];
6357 
6358  if( !SCIPisInfinity(scip, -rightminactivity) )
6359  {
6360  if( consdata->factorright[i] > 0.0 )
6361  {
6362  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6363  rightminactivity = -SCIPinfinity(scip);
6364  else
6365  rightminactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6366  }
6367  else if( consdata->factorright[i] < 0.0 )
6368  {
6369  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6370  rightminactivity = -SCIPinfinity(scip);
6371  else
6372  rightminactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6373  }
6374  }
6375  if( !SCIPisInfinity(scip, rightmaxactivity) )
6376  {
6377  if( consdata->factorright[i] > 0.0 )
6378  {
6379  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6380  rightmaxactivity = SCIPinfinity(scip);
6381  else
6382  rightmaxactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6383  }
6384  else if( consdata->factorright[i] < 0.0 )
6385  {
6386  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6387  rightmaxactivity = SCIPinfinity(scip);
6388  else
6389  rightmaxactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6390  }
6391  }
6392  rightrefactivity += consdata->factorright[i] * ref[i];
6393  }
6394 
6395  /* if activities exceed "opposite" infinity, huge bounds seem to be involved, for which the below method is not prepared */
6396  if( SCIPisInfinity(scip, leftminactivity) || SCIPisInfinity(scip, -leftmaxactivity) ||
6397  SCIPisInfinity(scip, rightminactivity) || SCIPisInfinity(scip, -rightmaxactivity) )
6398  return SCIP_OKAY;
6399 
6400  /* if any of the factors is essentially fixed, give up and do usual method (numerically less sensitive, I hope) */
6401  if( SCIPisRelEQ(scip, leftminactivity, leftmaxactivity) || SCIPisRelEQ(scip, rightminactivity, rightmaxactivity) )
6402  return SCIP_OKAY;
6403 
6404  /* success can only be expected for separation of violated x*y <= w, assuming x>=0, y>=0
6405  * @todo we should check this early? */
6406 
6407  /* call Couenne magic */
6409  leftminactivity, leftmaxactivity, leftrefactivity,
6410  rightminactivity, rightmaxactivity, rightrefactivity,
6411  rhsminactivity, rhsmaxactivity, rhsrefactivity,
6412  &coefleft, &coefright, &coefrhs, &cutlhs,
6413  success);
6414 
6415  if( !*success )
6416  return SCIP_OKAY;
6417 
6418  SCIPdebugMsg(scip, "LTI for x[%g,%g] * y[%g,%g] = w[%g,%g]: %gx %+gy %+gw >= %g; feas: %g\n",
6419  leftminactivity, leftmaxactivity, rightminactivity, rightmaxactivity, rhsminactivity, rhsmaxactivity,
6420  coefleft, coefright, coefrhs, cutlhs,
6421  coefleft * leftrefactivity + coefright * rightrefactivity + coefrhs * rhsrefactivity - cutlhs
6422  );
6423 
6424  if( coefleft * leftrefactivity + coefright * rightrefactivity + coefrhs * rhsrefactivity >= cutlhs )
6425  {
6426  SCIPdebugMsg(scip, "does not cutoff point? :-(\n");
6427  *success = FALSE;
6428  return SCIP_OKAY;
6429  }
6430 
6431  /* setup cut coefs for
6432  * coefleft * leftfactor + coefright * rightfactor + coefrhs * w >= cutlhs, where conslhs - lincoefs <= w <= consrhs - lincoefs
6433  */
6434  for( i = 0; i < consdata->nquadvars; ++i )
6435  {
6436  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, consdata->quadvarterms[i].var, coefleft * consdata->factorleft[i] + coefright * consdata->factorright[i]) );
6437  }
6438  SCIPaddRowprepConstant(rowprep, coefleft * consdata->factorleft[i] + coefright * consdata->factorright[i]);
6439 
6440  for( i = 0; i < consdata->nlinvars; ++i )
6441  {
6442  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, consdata->linvars[i], -coefrhs * consdata->lincoefs[i]) );
6443  }
6444  if( coefrhs > 0.0 )
6445  {
6446  /* use coefrhs * w <= coefrhs * (consrhs - lincoefs) */
6447  assert(!SCIPisInfinity(scip, consdata->rhs));
6448  SCIPaddRowprepConstant(rowprep, coefrhs * consdata->rhs);
6449  }
6450  else
6451  {
6452  /* use coefrhs * w <= coeflhs * (conslhs - lincoefs) */
6453  assert(!SCIPisInfinity(scip, -consdata->lhs));
6454  SCIPaddRowprepConstant(rowprep, coefrhs * consdata->lhs);
6455  }
6456  SCIPaddRowprepSide(rowprep, cutlhs);
6457 
6458  rowprep->local = TRUE;
6459 
6460  (void) SCIPsnprintf(rowprep->name, SCIP_MAXSTRLEN, "%s_lti_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
6461 
6462  *success = TRUE;
6463 
6464  return SCIP_OKAY;
6465 }
6466 
6467 /** computes cut coefficients by linearizing a quadratic function */
6468 static
6470  SCIP* scip, /**< SCIP data structure */
6471  SCIP_CONS* cons, /**< constraint */
6472  SCIP_SIDETYPE violside, /**< side for which to generate cut */
6473  SCIP_Real* ref, /**< reference solution where to generate the cut */
6474  SCIP_ROWPREP* rowprep, /**< rowprep to store cut data */
6475  SCIP_Bool* success /**< buffer to indicate whether a cut was successfully computed */
6476  )
6477 {
6478  SCIP_CONSDATA* consdata;
6479  SCIP_BILINTERM* bilinterm;
6480  SCIP_Real constant;
6481  SCIP_Real coef;
6482  SCIP_Real coef2;
6483  SCIP_VAR* var;
6484  int var2pos;
6485  int j;
6486  int k;
6487 
6488  assert(scip != NULL);
6489  assert(cons != NULL);
6490  assert(ref != NULL);
6491  assert(success != NULL);
6492 
6493  consdata = SCIPconsGetData(cons);
6494  assert(consdata != NULL);
6495 
6496  *success = TRUE;
6497 
6498  /* do first-order Taylor for each term */
6499  for( j = 0; j < consdata->nquadvars && *success; ++j )
6500  {
6501  var = consdata->quadvarterms[j].var;
6502 
6503  /* initialize coefficients to linear coefficients of quadratic variables */
6504  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, consdata->quadvarterms[j].lincoef) );
6505 
6506  /* add linearization of square term */
6507  coef = 0.0;
6508  constant = 0.0;
6509  SCIPaddSquareLinearization(scip, consdata->quadvarterms[j].sqrcoef, ref[j],
6510  consdata->quadvarterms[j].nadjbilin == 0 && SCIPvarGetType(var) < SCIP_VARTYPE_CONTINUOUS, &coef, &constant, success);
6511  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, coef) );
6512  SCIPaddRowprepConstant(rowprep, constant);
6513 
6514  /* add linearization of bilinear terms that have var as first variable */
6515  for( k = 0; k < consdata->quadvarterms[j].nadjbilin && *success; ++k )
6516  {
6517  bilinterm = &consdata->bilinterms[consdata->quadvarterms[j].adjbilin[k]];
6518  if( bilinterm->var1 != var )
6519  continue;
6520  assert(bilinterm->var2 != var);
6521  assert(consdata->sepabilinvar2pos != NULL);
6522 
6523  var2pos = consdata->sepabilinvar2pos[consdata->quadvarterms[j].adjbilin[k]];
6524  assert(var2pos >= 0);
6525  assert(var2pos < consdata->nquadvars);
6526  assert(consdata->quadvarterms[var2pos].var == bilinterm->var2);
6527 
6528  coef = 0.0;
6529  coef2 = 0.0;
6530  constant = 0.0;
6531  SCIPaddBilinLinearization(scip, bilinterm->coef, ref[j], ref[var2pos], &coef, &coef2, &constant, success);
6532  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, coef) );
6533  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, bilinterm->var2, coef2) );
6534  SCIPaddRowprepConstant(rowprep, constant);
6535  }
6536  }
6537 
6538  if( !*success )
6539  {
6540  SCIPdebugMsg(scip, "no success in linearization of <%s> in reference point\n", SCIPconsGetName(cons));
6541  return SCIP_OKAY;
6542  }
6543 
6544  rowprep->sidetype = violside;
6545  SCIPaddRowprepSide(rowprep, violside == SCIP_SIDETYPE_LEFT ? consdata->lhs : consdata->rhs);
6546 
6547  (void) SCIPsnprintf(rowprep->name, SCIP_MAXSTRLEN, "%s_side%d_linearization_%d", SCIPconsGetName(cons), violside, SCIPgetNLPs(scip));
6548 
6549  return SCIP_OKAY;
6550 }
6551 
6552 /** computes cut coefficients for a nonconvex quadratic function */
6553 static
6555  SCIP* scip, /**< SCIP data structure */
6556  SCIP_CONS* cons, /**< constraint */
6557  SCIP_SIDETYPE violside, /**< side for which to generate cut */
6558  SCIP_Real* ref, /**< reference solution where to generate the cut */
6559  SCIP_ROWPREP* rowprep, /**< rowprep to store cut data */
6560  SCIP_Bool* success /**< buffer to indicate whether a cut was successfully computed */
6561  )
6562 {
6563  SCIP_CONSDATA* consdata;
6564  SCIP_BILINTERM* bilinterm;
6565  SCIP_Real sqrcoef;
6566  SCIP_Real coef;
6567  SCIP_Real coef2;
6568  SCIP_Real constant;
6569  SCIP_VAR* var;
6570  int var2pos;
6571  int j;
6572  int k;
6573 
6574  assert(scip != NULL);
6575  assert(cons != NULL);
6576  assert(ref != NULL);
6577  assert(success != NULL);
6578 
6579  consdata = SCIPconsGetData(cons);
6580  assert(consdata != NULL);
6581 
6582  rowprep->local = TRUE;
6583  *success = TRUE;
6584 
6585  /* underestimate (secant, McCormick) or linearize each term separately */
6586  for( j = 0; j < consdata->nquadvars && *success; ++j )
6587  {
6588  var = consdata->quadvarterms[j].var;
6589 
6590  /* initialize coefficients to linear coefficients of quadratic variables */
6591  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, consdata->quadvarterms[j].lincoef) );
6592 
6593  sqrcoef = consdata->quadvarterms[j].sqrcoef;
6594  if( sqrcoef != 0.0 )
6595  {
6596  coef = 0.0;
6597  constant = 0.0;
6598  if( (violside == SCIP_SIDETYPE_LEFT && sqrcoef <= 0.0) || (violside == SCIP_SIDETYPE_RIGHT && sqrcoef > 0.0) )
6599  {
6600  /* convex -> linearize */
6601  SCIPaddSquareLinearization(scip, sqrcoef, ref[j], SCIPvarGetType(var) < SCIP_VARTYPE_CONTINUOUS, &coef,
6602  &constant, success);
6603  }
6604  else
6605  {
6606  /* not convex -> secant approximation */
6607  SCIPaddSquareSecant(scip, sqrcoef, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), ref[j], &coef,
6608  &constant, success);
6609  }
6610  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, coef) );
6611  SCIPaddRowprepConstant(rowprep, constant);
6612  }
6613 
6614  for( k = 0; k < consdata->quadvarterms[j].nadjbilin && *success; ++k )
6615  {
6616  bilinterm = &consdata->bilinterms[consdata->quadvarterms[j].adjbilin[k]];
6617  if( bilinterm->var1 != var )
6618  continue;
6619  assert(bilinterm->var2 != var);
6620  assert(consdata->sepabilinvar2pos != NULL);
6621 
6622  var2pos = consdata->sepabilinvar2pos[consdata->quadvarterms[j].adjbilin[k]];
6623  assert(var2pos >= 0);
6624  assert(var2pos < consdata->nquadvars);
6625  assert(consdata->quadvarterms[var2pos].var == bilinterm->var2);
6626 
6627  coef = 0.0;
6628  coef2 = 0.0;
6629  constant = 0.0;
6630  SCIPaddBilinMcCormick(scip, bilinterm->coef,
6631  SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), ref[j],
6632  SCIPvarGetLbLocal(bilinterm->var2), SCIPvarGetUbLocal(bilinterm->var2), ref[var2pos],
6633  violside == SCIP_SIDETYPE_LEFT, &coef, &coef2, &constant, success);
6634 
6635  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, coef) );
6636  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, bilinterm->var2, coef2) );
6637  SCIPaddRowprepConstant(rowprep, constant);
6638  }
6639  }
6640 
6641  if( !*success )
6642  {
6643  SCIPdebugMsg(scip, "no success to find estimator for nonconvex <%s>\n", SCIPconsGetName(cons));
6644  return SCIP_OKAY;
6645  }
6646 
6647  rowprep->sidetype = violside;
6648  SCIPaddRowprepSide(rowprep, violside == SCIP_SIDETYPE_LEFT ? consdata->lhs : consdata->rhs);
6649 
6650  (void) SCIPsnprintf(rowprep->name, SCIP_MAXSTRLEN, "%s_side%d_estimation_%d", SCIPconsGetName(cons), violside, SCIPgetNLPs(scip));
6651 
6652  return SCIP_OKAY;
6653 }
6654 
6655 /** generates a cut based on linearization (if convex) or McCormick (if nonconvex) in a given reference point */
6656 static
6658  SCIP* scip, /**< SCIP data structure */
6659  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6660  SCIP_CONS* cons, /**< constraint */
6661  SCIP_Real* ref, /**< reference solution where to generate the cut */
6662  SCIP_SOL* sol, /**< point that we aim to separate, or NULL for LP solution */
6663  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
6664  SCIP_ROW** row, /**< storage for cut */
6665  SCIP_Real* efficacy, /**< buffer to store efficacy of row in reference solution, or NULL if not of interest */
6666  SCIP_Bool checkcurvmultivar, /**< are we allowed to check the curvature of a multivariate quadratic function, if not done yet */
6667  SCIP_Real minefficacy /**< minimal required efficacy (violation possibly scaled) */
6668  )
6669 {
6670  SCIP_CONSHDLRDATA* conshdlrdata;
6671  SCIP_CONSDATA* consdata;
6672  SCIP_ROWPREP* rowprep;
6673  SCIP_Bool success;
6674  SCIP_Real viol = 0.0;
6675 
6676  assert(scip != NULL);
6677  assert(conshdlr != NULL);
6678  assert(cons != NULL);
6679  assert(ref != NULL);
6680  assert(row != NULL);
6681 
6682  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6683  assert(conshdlrdata != NULL);
6684 
6685  consdata = SCIPconsGetData(cons);
6686  assert(consdata != NULL);
6687  assert(violside != SCIP_SIDETYPE_LEFT || !SCIPisInfinity(scip, -consdata->lhs));
6688  assert(violside != SCIP_SIDETYPE_RIGHT || !SCIPisInfinity(scip, consdata->rhs));
6689 
6690  *row = NULL;
6691 
6693  success = FALSE;
6694 
6695  /* if constraint function is factorable, then try to use factorable form to generate cut */
6696  if( consdata->factorleft != NULL )
6697  {
6698  if( consdata->nlinvars == 0 )
6699  {
6700  SCIP_CALL( generateCutFactorable(scip, cons, violside, ref, rowprep, &success) );
6701  }
6702  else if( sol != NULL || SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
6703  {
6704  /* generateCutLTI needs reference values also for the linear variables, which we only have if sol is given or LP has been solved */
6705  SCIP_CALL( generateCutLTI(scip, cons, violside, ref, sol, rowprep, &success) );
6706  }
6707  }
6708 
6709  /* if constraint is not factorable or failed to generate cut, try default method */
6710  if( !success )
6711  {
6712  SCIP_CALL( checkCurvature(scip, cons, checkcurvmultivar) );
6713 
6714  if( (violside == SCIP_SIDETYPE_LEFT && consdata->isconcave) || (violside == SCIP_SIDETYPE_RIGHT && consdata->isconvex) )
6715  {
6716  SCIP_CALL( generateCutConvex(scip, cons, violside, ref, rowprep, &success) );
6717  }
6718  else
6719  {
6720  SCIP_CALL( generateCutNonConvex(scip, cons, violside, ref, rowprep, &success) );
6721  }
6722 
6723  SCIP_CALL( SCIPaddRowprepTerms(scip, rowprep, consdata->nlinvars, consdata->linvars, consdata->lincoefs) );
6724  }
6725 
6726  /* check if reference point violates cut at least a little bit */
6727  if( success && !SCIPisInfinity(scip, -minefficacy) )
6728  {
6729  viol = SCIPgetRowprepViolation(scip, rowprep, sol, conshdlrdata->scaling);
6730 
6731  if( viol <= 0.0 ) /*lint !e644*/
6732  {
6733  SCIPdebugMsg(scip, "skip cut for constraint <%s> because efficacy %g too low (< %g)\n", SCIPconsGetName(cons), viol, minefficacy);
6734  success = FALSE;
6735  }
6736  }
6737 
6738  /* cleanup and improve cut */
6739  if( success )
6740  {
6741  SCIP_Real coefrange;
6742 
6743  /* merge terms */
6744  SCIPmergeRowprepTerms(scip, rowprep);
6745 
6746  /* improve coefficients; disregarding conshdlrdata->scaling here for simplicity */
6747  SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, conshdlrdata->cutmaxrange, minefficacy, &coefrange, &viol) );
6748  success = coefrange <= conshdlrdata->cutmaxrange;
6749  }
6750 
6751  /* check that side is finite */ /*lint --e{514} */
6752  success &= !SCIPisInfinity(scip, REALABS(rowprep->side));
6753 
6754  /* check whether maximal coef is finite, if any */ /*lint --e{514} */
6755  success &= (rowprep->nvars == 0) || !SCIPisInfinity(scip, REALABS(rowprep->coefs[0]));
6756 
6757  /* compute scaled violation, if necessary (minefficacy is given (>-inf) or efficacy is requested (!=NULL)) */
6758  if( success && conshdlrdata->scaling != 'o' && (!SCIPisInfinity(scip, -minefficacy) || efficacy != NULL) )
6759  {
6760  /* if scaling is off, then violation was computed in SCIPcleanupRowprep above */
6761  viol = SCIPgetRowprepViolation(scip, rowprep, sol, conshdlrdata->scaling);
6762  }
6763 
6764  /* check if reference point violates cut sufficiently */
6765  if( success && !SCIPisInfinity(scip, -minefficacy) && viol < minefficacy ) /*lint !e644*/
6766  {
6767  SCIPdebugMsg(scip, "skip cut for constraint <%s> because efficacy %g too low (< %g)\n", SCIPconsGetName(cons), viol, minefficacy);
6768  success = FALSE;
6769  }
6770 
6771  /* generate row */
6772  if( success )
6773  {
6774  SCIP_CALL( SCIPgetRowprepRowCons(scip, row, rowprep, SCIPconsGetHdlr(cons)) );
6775 
6776  SCIPdebugMsg(scip, "found cut <%s>, lhs=%g, rhs=%g, mincoef=%g, maxcoef=%g, range=%g, nnz=%d, efficacy=%g\n",
6777  SCIProwGetName(*row), SCIProwGetLhs(*row), SCIProwGetRhs(*row),
6778  rowprep->coefs[rowprep->nvars-1], rowprep->coefs[0], rowprep->coefs[0]/rowprep->coefs[rowprep->nvars-1],
6779  SCIProwGetNNonz(*row), viol); /*lint !e414 */
6780 
6781  if( efficacy != NULL )
6782  *efficacy = viol;
6783  }
6784 
6785  SCIPfreeRowprep(scip, &rowprep);
6786 
6787  return SCIP_OKAY;
6788 }
6789 
6790 /** computes eigen decomposition of A, where \f$ f(x) = x^T A x + b^T x \f$.
6791  *
6792  * The eigen decomposition is given by A = P D P^T, where D is diagonal formed by the eigenvalues and P is orthonormal
6793  * whose columns are the eigenvectors; we also compute b^T * P, in case one needs the change of variables P^T x = y <=>
6794  * 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
6795  * of P^T is stored in eigenvector[0..n-1], the second row is stored in eigenvectors[n..2n-1], etc; equivalently, the
6796  * first eigenvector is eigenvector[0..n-1], the second one is eigenvectors[n..2n-1], etc.
6797  *
6798  * @todo: - at the moment of writing, checkCurvature computes the eigenvalues (and vectors) for determining curvature
6799  * when it can't to it via other considerations. so one could try to merge both methods together.
6800  * - it seems that if A is of the form [I 0; 0 A'], one only needs to compute the decomposition for A' so one
6801  * could do better in terms of memory and speed. For instance, when the matrix is diagonal, the eigenvectors
6802  * are the identity matrix and the eigenvalues are readily available from the constraint, so one could adapt
6803  * the functions that uses the eigenvectors in this particular case. One could also think about storing the
6804  * eigenvectors in a sparse fashion, though eigenvectors are seldom sparse.
6805  */
6806 static
6808  SCIP* scip, /**< SCIP data structure */
6809  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6810  SCIP_CONS* cons /**< constraint */
6811  )
6812 {
6813  SCIP_CONSDATA* consdata;
6814  int n;
6815  int nn;
6816  int row;
6817  int col;
6818  int i;
6819  int j;
6820  double* matrix;
6821  SCIP_HASHMAP* var2index;
6822 
6823  SCIPdebugMsg(scip, "computing ED for cons %s\n", SCIPconsGetName(cons));
6824 
6825  assert(scip != NULL);
6826  assert(conshdlr != NULL);
6827  assert(cons != NULL);
6828 
6829  consdata = SCIPconsGetData(cons);
6830  assert(consdata != NULL);
6831 
6832  /* function has to be convex with finite rhs or concave with finite lhs */
6833  assert((consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
6834  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)));
6835 
6836  /* can't compute eigenvectors without IPOPT */
6837  if( !SCIPisIpoptAvailableIpopt() )
6838  {
6839  consdata->isedavailable = FALSE;
6840  return SCIP_OKAY;
6841  }
6842 
6843  /* @todo: - it seems that if A is of the form [I 0; 0 A'], one only needs to compute the decomposition for A'
6844  * so one could do better in terms of memory and speed
6845  * - if n too big don't compute SVD
6846  */
6847  n = consdata->nquadvars;
6848 
6849  /* do not compute eigendecomposition if n is too large */
6850  nn = n * n;
6851  if( nn < 0 || (unsigned) (int) nn > UINT_MAX / sizeof(SCIP_Real) )
6852  {
6853  SCIPdebugMsg(scip, "n is too large to compute eigendecomposition\n");
6854  consdata->isedavailable = FALSE;
6855  return SCIP_OKAY;
6856  }
6857 
6858  /* we just need to pass the upper triangle of A since it is symmetric; build it here */
6859  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->eigenvectors, nn) );
6860  matrix = consdata->eigenvectors;
6861  BMSclearMemoryArray(matrix, nn);
6862 
6863  /* @todo if we are called in solving stage (or late from initsol), we can avoid the hashmap by using sepabilinvar2pos */
6864  SCIP_CALL( SCIPhashmapCreate(&var2index, SCIPblkmem(scip), n) );
6865 
6866  for( i = 0; i < n; ++i )
6867  {
6868  SCIP_CALL( SCIPhashmapInsert(var2index, consdata->quadvarterms[i].var, (void*)(size_t)i) );
6869  matrix[i*n + i] = consdata->quadvarterms[i].sqrcoef;
6870 #ifdef DEBUG_PROJ
6871  printf("inserting in position %d, value %g\n", i*n + i, consdata->quadvarterms[i].sqrcoef);
6872 #endif
6873  }
6874 
6875  for( i = 0; i < consdata->nbilinterms; ++i )
6876  {
6877  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var1));
6878  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var2));
6879  row = (int)(size_t)SCIPhashmapGetImage(var2index, consdata->bilinterms[i].var1);
6880  col = (int)(size_t)SCIPhashmapGetImage(var2index, consdata->bilinterms[i].var2);
6881  if( row < col )
6882  {
6883  matrix[row * n + col] = consdata->bilinterms[i].coef/2;
6884 #ifdef DEBUG_PROJ
6885  printf("inserting in position %d, value %g\n", row*n + col, consdata->bilinterms[i].coef/2);
6886 #endif
6887  }
6888  else
6889  {
6890  matrix[col * n + row] = consdata->bilinterms[i].coef/2;
6891 #ifdef DEBUG_PROJ
6892  printf("inserting in position %d, value %g\n", col*n + row, consdata->bilinterms[i].coef/2);
6893 #endif
6894  }
6895  }
6896 
6897 #ifdef DEBUG_PROJ
6898  printf("matrix built:\n");
6899  for( i = 0; i < n; i++ )
6900  {
6901  for( j = 0; j < n; j++ )
6902  printf("%g ", matrix[i*n + j]);
6903  printf("\n");
6904  }
6905 #endif
6906 
6907  /* compute eigenvalues and eigenvectors */
6908  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->eigenvalues, n) );
6909 
6910  if( LapackDsyev(TRUE, n, matrix, consdata->eigenvalues) != SCIP_OKAY )
6911  {
6912  SCIPdebugMsg(scip, "couldn't compute ED for cons %s\n", SCIPconsGetName(cons));
6913  consdata->isedavailable = FALSE;
6914  }
6915  else
6916  {
6917  consdata->isedavailable = TRUE;
6918 
6919  /* compute b^T*P */
6920  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &consdata->bp, n) );
6921  for( i = 0; i < n; i++ )
6922  for( j = 0; j < n; j++ )
6923  consdata->bp[i] += consdata->quadvarterms[j].lincoef * matrix[i*n + j];
6924 
6925 #ifdef DEBUG_PROJ
6926  printf("eigenvalues:\n");
6927  for( j = 0; j < n; j++ )
6928  printf("%g ", consdata->eigenvalues[j]);
6929 
6930  printf("\neigenvectors (P^T):\n");
6931  for( i = 0; i < n; i++ )
6932  {
6933  for( j = 0; j < n; j++ )
6934  printf("%g ", matrix[i*n + j]);
6935  printf("\n");
6936  }
6937 
6938  printf("b*P^T:\n");
6939  for( j = 0; j < n; j++ )
6940  printf("%g ", consdata->bp[j]);
6941  printf("svd computed successfully\n");
6942 #endif
6943  }
6944 
6945 
6946  SCIPhashmapFree(&var2index);
6947 
6948  return SCIP_OKAY;
6949 }
6950 
6951 /** computes an interior point for the quadratic part of the convex constraint
6952  *
6953  * There are different methods for computing the interior point
6954  * - 'a'ny: solves min 0, f(x) <= rhs, x in bounds
6955  * - 'm'ost interior: solves min f(x), x in bounds
6956  *
6957  * @todo: other methods for computing an interior point?
6958  */
6959 static
6961  SCIP* scip, /**< SCIP data structure */
6962  SCIP_CONS* cons, /**< constraint */
6963  char method, /**< method for computing interior point ('a' any point, 'm'ost interior) */
6964  SCIP_Bool* success /**< buffer to store if an interior point was found */
6965  )
6966 {
6967  SCIP_CONSDATA* consdata;
6968  SCIP_QUADELEM* nlrowquadelems;
6969  SCIP_NLPIPROBLEM* prob;
6970  SCIP_NLPI* nlpi;
6971  SCIP_Real* interiorpoint;
6972  SCIP_Real* lbs;
6973  SCIP_Real* ubs;
6974  SCIP_Real* lincoefs;
6975  SCIP_Real nlpiside;
6976  char probname[SCIP_MAXSTRLEN];
6977  int* lininds;
6978  int nlrownquadelems;
6979  int nquadvars;
6980  int i;
6981 
6982  assert(scip != NULL);
6983  assert(cons != NULL);
6984 
6985  assert(success != NULL);
6986  *success = FALSE;
6987 
6988  consdata = SCIPconsGetData(cons);
6989  assert(consdata != NULL);
6990 
6991  assert((consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
6992  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)));
6993 
6994  /* need an NLP solver */
6995  if( SCIPgetNNlpis(scip) == 0 )
6996  return SCIP_OKAY;
6997 
6998  nlpi = NULL;
6999  prob = NULL;
7000  lbs = NULL;
7001  ubs = NULL;
7002  lincoefs = NULL;
7003  lininds = NULL;
7004 
7005 #ifdef SCIP_DEBUG_INT
7006  SCIPinfoMessage(scip, NULL, "Computing interior point for\n");
7007  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
7008  SCIPinfoMessage(scip, NULL, ";\n");
7009 #endif
7010 
7011  /* in the convex case, we try to find an interior point of x^T A x + b^T x <= rhs - maximum activity linear part
7012  * in the concave case: lhs - minimum activity linear part <= x^T A x + b^T x; we compute activities ourselves,
7013  * since consdata->max(min)linactivity are only computed when lhs (rhs) is finite and this not always holds
7014  */
7015  if( consdata->isconvex )
7016  {
7017  /* compute maximum activity */
7018  nlpiside = 0;
7019  for( i = 0; i < consdata->nlinvars; ++i )
7020  {
7021  if( consdata->lincoefs[i] >= 0.0 )
7022  {
7023  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i]) ) )
7024  nlpiside = SCIPinfinity(scip);
7025  else
7026  nlpiside += consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
7027  }
7028  else
7029  {
7030  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i]) ) )
7031  nlpiside = SCIPinfinity(scip);
7032  else
7033  nlpiside += consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
7034  }
7035 
7036  if( SCIPisInfinity(scip, nlpiside) )
7037  {
7038  SCIPdebugMsg(scip, "maximum activity is infinity: there is no interior point for fun <= rhs - maxlinactivity!\n");
7039  return SCIP_OKAY;
7040  }
7041  }
7042 
7043  if( consdata->nlinvars == 0 )
7044  nlpiside = INTERIOR_EPS;
7045 
7046  nlpiside = consdata->rhs - nlpiside;
7047  }
7048  else
7049  {
7050  /* compute minimum activity */
7051  nlpiside = 0;
7052  for( i = 0; i < consdata->nlinvars; ++i )
7053  {
7054  if( consdata->lincoefs[i] >= 0.0 )
7055  {
7056  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i])) )
7057  nlpiside = -SCIPinfinity(scip);
7058  else
7059  nlpiside += consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
7060  }
7061  else
7062  {
7063  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i])) )
7064  nlpiside = -SCIPinfinity(scip);
7065  else
7066  nlpiside += consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
7067  }
7068 
7069  if( SCIPisInfinity(scip, -nlpiside) )
7070  {
7071  SCIPdebugMsg(scip, "minimum activity is -infinity: there is no interior point for fun >= lhs - minlinactivity!\n");
7072  return SCIP_OKAY;
7073  }
7074  }
7075 
7076  if( consdata->nlinvars == 0 )
7077  nlpiside = INTERIOR_EPS;
7078 
7079  nlpiside = consdata->lhs - nlpiside;
7080  }
7081 
7082  nquadvars = consdata->nquadvars;
7083 
7084  /* if we are looking for any interior point and the 0 is one, then use it */
7085  if( method == 'a' && ((consdata->isconvex && SCIPisGE(scip, nlpiside, 0.0))
7086  || (consdata->isconcave && SCIPisLE(scip, nlpiside, 0.0))) )
7087  {
7088  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &(consdata->interiorpoint), nquadvars) );
7089 
7090  *success = TRUE;
7091  goto TERMINATE;
7092  }
7093 
7094  /* build nlrow */
7095  if( consdata->nlrow == NULL )
7096  {
7097  SCIP_CALL( createNlRow(scip, cons) );
7098  assert(consdata->nlrow != NULL);
7099  }
7100 
7101  nlpi = SCIPgetNlpis(scip)[0];
7102  assert(nlpi != NULL);
7103 
7104  /* initializing the subproblem */
7105  (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "%s_subquad", SCIPgetProbName(scip));
7106  SCIP_CALL( SCIPnlpiCreateProblem(nlpi, &prob, probname) );
7107  assert(prob != NULL);
7108 
7109 #ifdef SCIP_DEBUG_INT
7111 #endif
7112  /* TODO: maybe one should set some generous iteration limit and/or a timelimit (remaining scip solve time)? */
7113 
7114  /* ask for memory to store data needed to create vars and linear coefficients */
7115  SCIP_CALL( SCIPallocBufferArray(scip, &lbs, nquadvars) );
7116  SCIP_CALL( SCIPallocBufferArray(scip, &ubs, nquadvars) );
7117  SCIP_CALL( SCIPallocBufferArray(scip, &lininds, nquadvars) );
7118  SCIP_CALL( SCIPallocBufferArray(scip, &lincoefs, nquadvars) );
7119 
7120  /* get bounds and linear coefficients */
7121  for( i = 0; i < nquadvars; i++ )
7122  {
7123  lbs[i] = SCIPvarGetLbGlobal(consdata->quadvarterms[i].var);
7124  ubs[i] = SCIPvarGetUbGlobal(consdata->quadvarterms[i].var);
7125 
7126  lincoefs[i] = consdata->quadvarterms[i].lincoef;
7127  lininds[i] = i;
7128  }
7129 
7130  /* add vars */
7131  SCIP_CALL( SCIPnlpiAddVars(nlpi, prob, nquadvars, lbs, ubs, NULL) );
7132 
7133  /* get nlrow info */
7134  nlrownquadelems = SCIPnlrowGetNQuadElems(consdata->nlrow);
7135  nlrowquadelems = SCIPnlrowGetQuadElems(consdata->nlrow);
7136 
7137 #ifndef NDEBUG
7138  {
7139  SCIP_VAR** nlrowquadvars;
7140 
7141  nlrowquadvars = SCIPnlrowGetQuadVars(consdata->nlrow);
7142  for( i = 0; i < nlrownquadelems; i++ )
7143  {
7144  assert(nlrowquadvars[nlrowquadelems[i].idx1] == consdata->quadvarterms[nlrowquadelems[i].idx1].var);
7145  assert(nlrowquadvars[nlrowquadelems[i].idx2] == consdata->quadvarterms[nlrowquadelems[i].idx2].var);
7146  }
7147  }
7148 #endif
7149 
7150  (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "%s", SCIPconsGetName(cons));
7151 
7152  switch( method )
7153  {
7154  case 'a':
7155  /* add constraint */
7156  if( consdata->isconvex )
7157  {
7158  SCIP_CALL( SCIPnlpiAddConstraints(nlpi, prob, 1, NULL, &nlpiside, &nquadvars, &lininds, &lincoefs,
7159  &nlrownquadelems, &nlrowquadelems, NULL, NULL, NULL) );
7160  }
7161  else
7162  {
7163  SCIP_CALL( SCIPnlpiAddConstraints(nlpi, prob, 1, &nlpiside, NULL, &nquadvars, &lininds, &lincoefs,
7164  &nlrownquadelems, &nlrowquadelems, NULL, NULL, NULL) );
7165  }
7166  break;
7167 
7168  case 'm':
7169  /* add objective */
7170  if( consdata->isconvex )
7171  {
7172  SCIP_CALL( SCIPnlpiSetObjective(nlpi, prob, nquadvars, lininds, lincoefs,
7173  nlrownquadelems, nlrowquadelems, NULL, NULL, 0.0) );
7174  }
7175  else
7176  {
7177  /* NLPI assumes minimization: change signs */
7178  for( i = 0; i < nquadvars; i++ )
7179  lincoefs[i] *= -1;
7180 
7181  /* WARNING: this pointer is not ours, information should be restored! */
7182  for( i = 0; i < nlrownquadelems; i++ )
7183  nlrowquadelems->coef *= -1;
7184 
7185  SCIP_CALL( SCIPnlpiSetObjective(nlpi, prob, nquadvars, lininds, lincoefs,
7186  nlrownquadelems, nlrowquadelems, NULL, NULL, 0.0) );
7187 
7188  /* WARNING: restore information! */
7189  for( i = 0; i < nlrownquadelems; i++ )
7190  nlrowquadelems->coef *= -1;
7191  }
7192  break;
7193 
7194  default:
7195  SCIPerrorMessage("undefined method for computing interior point: %c\n", method);
7196  return SCIP_INVALIDDATA;
7197  }
7198 
7199  /* solve NLP problem */
7200  SCIP_CALL( SCIPnlpiSolve(nlpi, prob) );
7201 
7202  /* check termination status */
7203  if( SCIPnlpiGetTermstat(nlpi, prob) != SCIP_NLPTERMSTAT_OKAY )
7204  {
7205  SCIPdebugMsg(scip, "cons <%s>: NLP Solver termination status not okay: %d\n",
7206  SCIPconsGetName(cons), SCIPnlpiGetTermstat(nlpi, prob));
7207  *success = FALSE;
7208  goto TERMINATE;
7209  }
7210 
7211  /* check solution status */
7212  switch( SCIPnlpiGetSolstat(nlpi, prob) )
7213  {
7217  /* fallthrough */
7218  SCIPdebugMsg(scip, "cons <%s>: found an interior point. solution status: %d, termination status: %d\n",
7219  SCIPconsGetName(cons), SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
7220  break;
7221 
7224  /* fallthrough */
7225  /* TODO: we could still use the point, and let evaluateGauge decide whether the point is interior or not */
7226  SCIPdebugMsg(scip, "cons <%s>: failed to find an interior point. solution status: %d, termination status: %d\n",
7227  SCIPconsGetName(cons), SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
7228  goto TERMINATE;
7229 
7232  default:
7233  /* fallthrough */
7234  SCIPerrorMessage("cons <%s>: undefined behaviour of NLP Solver. solution status: %d, termination status: %d\n",
7235  SCIPconsGetName(cons), SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
7236  SCIPABORT();
7237  goto TERMINATE; /*lint !e527*/
7238  }
7239 
7240  /* fetch solution
7241  * note: nlpiGetSolution (at least for IPOPT) makes interiorpoint point to the internal solution stored in the
7242  * nlpi problem data structure; we need to copy it here because it will be destroyed once the problem is free'd
7243  */
7244  SCIP_CALL( SCIPnlpiGetSolution(nlpi, prob, &interiorpoint, NULL, NULL, NULL) );
7245 
7246  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(consdata->interiorpoint), nquadvars) );
7247 
7248  for( i = 0; i < nquadvars; i++ )
7249  {
7250  if( SCIPisFeasZero(scip, interiorpoint[i]) )
7251  consdata->interiorpoint[i] = 0.0;
7252  else
7253  consdata->interiorpoint[i] = interiorpoint[i];
7254  }
7255 
7256  *success = TRUE;
7257 
7258 TERMINATE:
7259 
7260 #ifdef SCIP_DEBUG_INT
7261  printf("Computation of interior point for cons <%s>:\n", SCIPconsGetName(cons));
7262  printf(" - has %d linear variables\n", consdata->nlinvars);
7263  if( consdata->isconvex )
7264  {
7265  printf(" - is convex. rhs: %g maximum activity of linear variables: %g\n", consdata->rhs, consdata->rhs - nlpiside);
7266  printf(" - searched for point whose quadratic part is <= %g\n", nlpiside);
7267  }
7268  else
7269  {
7270  printf(" - is concave. lhs: %g minimum activity of linear variables: %g\n", consdata->lhs, consdata->lhs - nlpiside);
7271  printf(" - searched for point whose quadratic part is >= %g\n", nlpiside);
7272  }
7273 
7274  if( *success )
7275  {
7276  if( prob == NULL )
7277  {
7278  printf("Computation successful, 0 is interior point.\n");
7279  for( i = 0; i < nquadvars; i++ )
7280  {
7281  assert(consdata->interiorpoint[i] == 0.0);
7282  }
7283  }
7284  else
7285  {
7286  printf("Computation successful, NLP soltat: %d, termstat: %d\nPoint found:\n",
7287  SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
7288  for( i = 0; i < nquadvars; i++ )
7289  {
7290  printf("%s = %g\n", SCIPvarGetName(consdata->quadvarterms[i].var), consdata->interiorpoint[i]);
7291  }
7292  }
7293  }
7294  else
7295  {
7296  printf("Computation failed. NLP soltat: %d, termstat: %d\n",
7297  SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
7298  printf("run with SCIP_DEBUG for more info\n");
7299  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
7300  SCIPinfoMessage(scip, NULL, ";\n");
7301  /* FIXME: instance camshape100 says that there is no interior point (interior empty)
7302  * is there something intelligent that can be said?
7303  */
7304  }
7305 #endif
7306 
7307  /* free memory */
7308  SCIPfreeBufferArrayNull(scip, &lbs);
7309  SCIPfreeBufferArrayNull(scip, &ubs);
7310  SCIPfreeBufferArrayNull(scip, &lininds);
7311  SCIPfreeBufferArrayNull(scip, &lincoefs);
7312 
7313  if( prob != NULL )
7314  {
7315  SCIP_CALL( SCIPnlpiFreeProblem(nlpi, &prob) );
7316  }
7317 
7318  return SCIP_OKAY;
7319 }
7320 
7321 /** 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$.
7322  *
7323  * Here, \f$ f(x) \f$ is a purely quadratic (i.e, all \f$x\f$ variables appear in a bilinear or quadratic term).
7324  * Explicitly, \f$ f(x) = \pm x^T A x \pm b^T x \f$ depending whether \f$A\f$
7325  * is positive semidefinite (+) or negative semidefinite (-).
7326  * The constant \f$c\f$ is rhs - maximum activity of the purely linear part of the constraint
7327  * if \f$A \succeq 0\f$ and minimum activity - lhs if \f$A \preceq 0\f$.
7328  * This is computed only at INITSOL.
7329  *
7330  * The method does:
7331  * 1. compute interior point
7332  * 2. compute gauge function
7333  */
7334 static
7336  SCIP* scip, /**< SCIP data structure */
7337  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7338  SCIP_CONS* cons /**< constraint */
7339  )
7340 {
7341  SCIP_CONSHDLRDATA* conshdlrdata;
7342  SCIP_CONSDATA* consdata;
7343  SCIP_QUADVARTERM* quadvarterm;
7344  SCIP_BILINTERM* bilinterm;
7345  SCIP_Bool success;
7346  SCIP_Bool convex;
7347  int i;
7348  int j;
7349 
7350  assert(scip != NULL);
7351  assert(conshdlr != NULL);
7352  assert(cons != NULL);
7353 
7354  consdata = SCIPconsGetData(cons);
7355  assert(consdata != NULL);
7356 
7357  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7358  assert(conshdlrdata != NULL);
7359  assert(conshdlrdata->gaugecuts);
7360 
7361  /* function has to be convex with finite rhs or concave with finite lhs */
7362  convex = consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs);
7363  assert(convex || (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)));
7364 
7365  SCIPdebugMsg(scip, "cons %s: is %s\n", SCIPconsGetName(cons), convex ? "convex" : "concave");
7366 
7367  /* 1. */
7368  SCIP_CALL( computeInteriorPoint(scip, cons, conshdlrdata->interiorcomputation, &success) );
7369 
7370  /* if success, compute gaugecoefs (b_gauge) and gaugeconst (c_gauge) */
7371  if( !success )
7372  {
7373  SCIPdebugMsg(scip, "failed to compute gauge function\n");
7374  consdata->isgaugeavailable = FALSE;
7375  return SCIP_OKAY;
7376  }
7377 
7378  /* 2.
7379  * we are going to evaluate the function at interiorpoint; so, we need to compute interiorpoint^T A interiorpoint;
7380  * therefore, we need a mechanism that for a given variable, it returns its interior point value
7381  * fortunately, sepabilinvar2pos in consdata gives us all the information that we need
7382  */
7383 
7384  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &(consdata->gaugecoefs), consdata->nquadvars) );
7385 
7386  /* compute value of quadratic part at interior point, build map and compute gaugeconst (c_gauge) */
7387  consdata->interiorpointval = 0;
7388  consdata->gaugeconst = 0;
7389  for( i = 0; i < consdata->nquadvars; i++ )
7390  {
7391  SCIP_Real val;
7392  SCIP_Real val2;
7393 
7394  val = consdata->interiorpoint[i];
7395  quadvarterm = &consdata->quadvarterms[i];
7396 
7397  consdata->interiorpointval += (quadvarterm->lincoef + quadvarterm->sqrcoef * val) * val;
7398  consdata->gaugeconst += quadvarterm->sqrcoef * val * val;
7399 
7400  for( j = 0; j < quadvarterm->nadjbilin; ++j )
7401  {
7402  int bilintermidx;
7403 
7404  bilintermidx = quadvarterm->adjbilin[j];
7405  bilinterm = &consdata->bilinterms[bilintermidx];
7406 
7407  if( bilinterm->var1 != quadvarterm->var )
7408  continue;
7409 
7410  /* the index of the variable associated with var2 in bilinterm should be given by sepabilinvar2pos */
7411  assert(consdata->sepabilinvar2pos != NULL); /* this should have been computed in INITSOL */
7412  assert(consdata->quadvarterms[consdata->sepabilinvar2pos[bilintermidx]].var == bilinterm->var2);
7413 
7414  val2 = consdata->interiorpoint[consdata->sepabilinvar2pos[bilintermidx]];
7415 
7416  consdata->interiorpointval += bilinterm->coef * val * val2;
7417  consdata->gaugeconst += bilinterm->coef * val * val2;
7418  }
7419  }
7420 
7421  /* compute gaugecoefs (b_gauge = b + 2 * A * interiorpoint) */
7422  for( i = 0; i < consdata->nquadvars; i++ )
7423  {
7424  quadvarterm = &consdata->quadvarterms[i];
7425  consdata->gaugecoefs[i] += quadvarterm->lincoef + 2.0 * quadvarterm->sqrcoef * consdata->interiorpoint[i];
7426 
7427  for( j = 0; j < quadvarterm->nadjbilin; j++ )
7428  {
7429  int varpos;
7430  int bilintermidx;
7431 
7432  bilintermidx = quadvarterm->adjbilin[j];
7433  bilinterm = &consdata->bilinterms[bilintermidx];
7434 
7435  if( bilinterm->var1 == quadvarterm->var )
7436  {
7437  varpos = consdata->sepabilinvar2pos[bilintermidx];
7438 
7439  /* the index of the variable associated with var2 in bilinterm should be given by sepabilinvar2pos */
7440  assert(consdata->quadvarterms[varpos].var == bilinterm->var2);
7441 
7442  consdata->gaugecoefs[i] += bilinterm->coef * consdata->interiorpoint[varpos];
7443  consdata->gaugecoefs[varpos] += bilinterm->coef * consdata->interiorpoint[i];
7444  }
7445  }
7446  }
7447 
7448 #ifdef SCIP_DEBUG_INT
7449  printf("quadratic part at interior point: %g\n", consdata->interiorpointval);
7450 
7451  for( j = 0; j < consdata->nquadvars; j++ )
7452  {
7453  printf("b_gauge[%s] = %g\n", SCIPvarGetName(consdata->quadvarterms[j].var), consdata->gaugecoefs[j]);
7454  }
7455  printf("c_gauge = %g\n", consdata->gaugeconst);
7456 #endif
7457 
7458  SCIPdebugMsg(scip, "gauge function computed successfully\n");
7459  consdata->isgaugeavailable = TRUE;
7460 
7461  return SCIP_OKAY;
7462 }
7463 
7464 /** 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$.
7465  *
7466  * \f$ S = \{ x : f(x) \le c \}\f$ at \f$sol - s_0\f$;
7467  * see computeGauge() for more details
7468  *
7469  * @todo Think about if user should tell that function is convex or ...
7470  */
7471 static
7473  SCIP* scip, /**< SCIP data structure */
7474  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7475  SCIP_CONS* cons, /**< constraint */
7476  SCIP_SOL* refsol, /**< reference point where to generate cut, or NULL if sol should be used */
7477  SCIP_Real* gaugeval, /**< buffer to store the value of the gauge function */
7478  SCIP_Bool* success /**< buffer to store if evaluation was successful */
7479  )
7480 {
7481  SCIP_CONSDATA* consdata;
7482  SCIP_Real side;
7483  SCIP_Real aterm;
7484  SCIP_Real bterm;
7485  SCIP_Real cterm;
7486  SCIP_Bool convex;
7487  int i;
7488 
7489  assert(scip != NULL);
7490  assert(conshdlr != NULL);
7491  assert(cons != NULL);
7492 
7493  consdata = SCIPconsGetData(cons);
7494  assert(consdata != NULL);
7495  assert(consdata->isgaugeavailable);
7496 
7497  *success = FALSE;
7498 
7499  convex = consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs);
7500 
7501  SCIPdebugMsg(scip, "cons %s: is %s\n", SCIPconsGetName(cons), convex ? "convex" : "concave");
7502 
7503  /* evaluate gauge function at x0 = (refsol - interior point)
7504  *
7505  * compute aterm = side - function(interior point)
7506  */
7507  if( convex )
7508  {
7509  side = consdata->rhs;
7510  for( i = 0; i < consdata->nlinvars; i++ )
7511  side -= SCIPgetSolVal(scip, refsol, consdata->linvars[i]) * consdata->lincoefs[i];
7512 
7513  aterm = side - consdata->interiorpointval;
7514 
7515  /* it can happen that the interior point is not really interior, since we are not so strict at the moment of
7516  * computing the interior point, which makes sense in the case that the constraint is quadratic <= linear expr,
7517  * since we compute a point in quadratic <= min linear expr and it might be that this set consists of a single
7518  * point which will not be interior. furthermore, if this set is empty, we could just take any point and it could
7519  * happen that for some value of linear expr, the point is actually interior, but for many it could not be.
7520  * also, if min linear expr = -infinity, we might have computed an interior point using some finite value.
7521  * the point will not be an interior point, if and only if aterm is negative.
7522  */
7523 #ifdef SCIP_DEBUG_GAUGE
7524  if( SCIPisLE(scip, aterm, 0.0) )
7525  {
7526  printf("For current level, there is no interior point. ");
7527  printf("rhs: %g level: %15.20g interiorpointval: %15.20g\n", consdata->rhs, side, consdata->interiorpointval);
7528  if( consdata->nlinvars == 1 )
7529  {
7530  SCIP_VAR* var;
7531 
7532  var = consdata->linvars[0];
7533  printf("var <%s> = %g in [%15.20g, %15.20g] is linpart\n", SCIPvarGetName(var),
7534  SCIPgetSolVal(scip, refsol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
7535  }
7536  }
7537  else
7538  {
7539  printf("For current level, there is interior point. ");
7540  printf("rhs: %g level: %15.20g interiorpointval: %15.20g\n", consdata->rhs, side, consdata->interiorpointval);
7541  }
7542 #endif
7543  if( !SCIPisPositive(scip, aterm) )
7544  {
7545  *gaugeval = -1.0;
7546  return SCIP_OKAY;
7547  }
7548  }
7549  else
7550  {
7551  side = consdata->lhs;
7552  for( i = 0; i < consdata->nlinvars; i++ )
7553  side -= SCIPgetSolVal(scip, refsol, consdata->linvars[i]) * consdata->lincoefs[i];
7554 
7555  aterm = side - consdata->interiorpointval;
7556 
7557 #ifdef SCIP_DEBUG_GAUGE
7558  if( SCIPisGE(scip, aterm, 0.0) )
7559  {
7560  printf("For current level, there is no interior point. ");
7561  printf("lhs: %g level: %15.20g interiorpointval: %15.20g\n", consdata->lhs, side, consdata->interiorpointval);
7562  if( consdata->nlinvars == 1 )
7563  {
7564  SCIP_VAR* var;
7565 
7566  var = consdata->linvars[0];
7567  printf("var <%s> = %g in [%15.20g, %15.20g] is linpart\n", SCIPvarGetName(var),
7568  SCIPgetSolVal(scip, refsol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
7569  }
7570  }
7571  else
7572  {
7573  printf("For current level, there is interior point. ");
7574  printf("lhs: %g level: %15.20g interiorpointval: %15.20g\n", consdata->lhs, side, consdata->interiorpointval);
7575  }
7576 #endif
7577  if( !SCIPisNegative(scip, aterm) )
7578  {
7579  *gaugeval = -1.0;
7580  return SCIP_OKAY;
7581  }
7582  }
7583 
7584  /* compute bterm = b_gauge^T * refsol - f(interiorpoint) - c_gauge
7585  * compute cterm = f(refsol) - b_gauge^T * refsol + c_gauge */
7586  bterm = -consdata->interiorpointval - consdata->gaugeconst;
7587  cterm = consdata->gaugeconst;
7588  for( i = 0; i < consdata->nquadvars; i++ )
7589  {
7590  SCIP_Real val;
7591 
7592  val = SCIPgetSolVal(scip, refsol, consdata->quadvarterms[i].var);
7593  bterm += consdata->gaugecoefs[i] * val;
7594  cterm -= consdata->gaugecoefs[i] * val;
7595  cterm += (consdata->quadvarterms[i].lincoef + consdata->quadvarterms[i].sqrcoef * val) * val;
7596  }
7597 
7598  for( i = 0; i < consdata->nbilinterms; i++ )
7599  {
7600  SCIP_VAR* var1;
7601  SCIP_VAR* var2;
7602 
7603  var1 = consdata->bilinterms[i].var1;
7604  var2 = consdata->bilinterms[i].var2;
7605  cterm += consdata->bilinterms[i].coef * SCIPgetSolVal(scip, refsol, var1) * SCIPgetSolVal(scip, refsol, var2);
7606  }
7607 
7608  /* now compute gauge */
7609  if( convex && cterm < 0.0 )
7610  {
7611  assert(SCIPisZero(scip, cterm));
7612  cterm = 0.0;
7613  }
7614  else if( !convex && cterm > 0.0 )
7615  {
7616  assert(SCIPisZero(scip, cterm));
7617  cterm = 0.0;
7618  }
7619  assert(bterm*bterm + 4*aterm*cterm >= 0);
7620 
7621  if( convex )
7622  {
7623  *gaugeval = bterm + sqrt(bterm*bterm + 4 * aterm * cterm);
7624  *gaugeval = *gaugeval / (2 * aterm);
7625  }
7626  else
7627  {
7628  *gaugeval = bterm - sqrt(bterm*bterm + 4 * aterm * cterm);
7629  *gaugeval = *gaugeval / (2 * aterm);
7630  }
7631  assert(!SCIPisNegative(scip, *gaugeval));
7632  *success = TRUE;
7633 
7634 #ifdef SCIP_DEBUG_GAUGE
7635  printf("Gauge's aterm = %g, bterm = %g, cterm = %g\n", aterm, bterm, cterm);
7636 #endif
7637  return SCIP_OKAY;
7638 }
7639 
7640 /** compute projection of refsol onto feasible region of cons; stores the projection in ref
7641  *
7642  * This method solves
7643  * \f[
7644  * \min \{ ||x - \bar x||^2 : x^T A x + 2 b^T x \le c \}
7645  * \f]
7646  * where \f$ \bar x \f$ is refsol.
7647  * Note that \f$ \bar x \f$ is not feasible, so the optimal solution actually satisfies
7648  * \f[
7649  * \min \{ ||x - \bar x||^2 : x^T A x + 2 b^T x = c \}
7650  * \f]
7651  * Using the eigendecomposition \f$ A = P D P^T \f$, the change of variables \f$ y = P^T x
7652  * \f$ and the optimality conditions, this reduces to finding \f$ \rho \f$ such that
7653  * \f[
7654  * y(\rho) = (I + \rho D)^{-1} (\bar y - \rho \bar b)
7655  * \f]
7656  * 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$
7657  * D \neq 0 \f$, the function
7658  * \f[
7659  * \varphi(\rho) := y(\rho)^T D y(\rho) + 2 \bar b^T y(\rho) - c
7660  * \f]
7661  * is strictly convex. So this method actually computes the unique 0 of this function using Newton's method.
7662  */
7663 static
7665  SCIP* scip, /**< SCIP data structure */
7666  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7667  SCIP_CONS* cons, /**< constraint */
7668  SCIP_SOL* refsol, /**< the given point to project, or NULL if LP solution should be used */
7669  SCIP_Real* ref /**< array to store reference point */
7670  )
7671 {
7672  SCIP_CONSDATA* consdata;
7673  SCIP_Real* pt; /* stores P^T */
7674  SCIP_Real* bp;
7675  SCIP_Real* D;
7676  SCIP_Real* y0_;
7677  SCIP_Real* yrho;
7678  SCIP_Real* yrhoprime;
7679  SCIP_Real c;
7680  SCIP_Real c1;
7681  SCIP_Real c2;
7682  SCIP_Real rho;
7683  SCIP_Real phirho;
7684  SCIP_Real phirhoprime;
7685  SCIP_Bool isconcave;
7686  int iter;
7687  int i;
7688  int j;
7689  int n;
7690 
7691  assert(scip != NULL);
7692  assert(conshdlr != NULL);
7693  assert(cons != NULL);
7694 
7695  consdata = SCIPconsGetData(cons);
7696  assert(consdata != NULL);
7697  assert(consdata->isedavailable);
7698 
7699  SCIPdebugMessage("computing projection\n");
7700 
7701  /* get the data we need */
7702  pt = consdata->eigenvectors;
7703  D = consdata->eigenvalues;
7704  n = consdata->nquadvars;
7705  bp = consdata->bp;
7706  c = consdata->rhs;
7707  c1 = 0;
7708  c2 = 0;
7709  for( i = 0; i < consdata->nlinvars; i++ )
7710  {
7711  c1 += consdata->lincoefs[i] * SCIPgetSolVal(scip, refsol, consdata->linvars[i]);
7712  c2 -= consdata->lincoefs[i] * consdata->lincoefs[i];
7713  }
7714  c2 /= 2.0;
7715 
7716  /* determine if convex or concave */
7717  isconcave = consdata->isconcave;
7718  assert((isconcave && !SCIPisInfinity(scip, -consdata->lhs)) || !SCIPisInfinity(scip, consdata->rhs));
7719 
7720  SCIP_CALL( SCIPallocClearBufferArray(scip, &y0_, n) );
7721  SCIP_CALL( SCIPallocBufferArray(scip, &yrho, n) );
7722  SCIP_CALL( SCIPallocBufferArray(scip, &yrhoprime, n) );
7723 
7724  /* change data if function is concave */
7725  if( isconcave )
7726  {
7727  c = -consdata->lhs;
7728  c1 = - c1;
7729  for( i = 0; i < n; i++ )
7730  {
7731  D[i] = -D[i];
7732  bp[i] = -bp[i];
7733  }
7734  }
7735 
7736  /* change coordinates: compute y(0) = x_0' * P */
7737  for( i = 0; i < n; i++ )
7738  for( j = 0; j < n; j++ )
7739  y0_[i] += SCIPgetSolVal(scip, refsol, consdata->quadvarterms[j].var) * pt[i*n + j];
7740 
7741 #ifdef DEBUG_PROJ
7742  /* debug output */
7743  printf("\nP^T:\n");
7744  for( i = 0; i < n; i++ )
7745  {
7746  for( j = 0; j < n; j++ )
7747  printf("%g ", pt[i*n + j]);
7748  printf("\n");
7749  }
7750  printf("x_0: ");
7751  for( i = 0; i < n; i++ )
7752  printf("%g ", SCIPgetSolVal(scip, refsol, consdata->quadvarterms[i].var));
7753  printf("\n");
7754  printf("P^T x_0: ");
7755  for( i = 0; i < n; i++ )
7756  printf("%g ", y0_[i]);
7757  printf("\n");
7758  printf("P^T b: ");
7759  for( i = 0; i < n; i++ )
7760  printf("%g ", bp[i]);
7761  printf("\n");
7762  printf("<d,linvars> = %g\n", c1);
7763  printf("-norm(d)^2/2 = %g\n", c2);
7764 #endif
7765 
7766  /* perform newton's method: rho^+ = rho - phi(rho)/phi'(rho) */
7767  rho = 0.0;
7768  phirho = c;
7769  phirhoprime = 1.0;
7770  for( iter = 0; iter < 9; iter++ )
7771  {
7772  assert(phirhoprime != 0.0);
7773  rho = rho - (phirho - c)/ phirhoprime;
7774 
7775  /* compute phi(rho) and phi'(rho):
7776  * note that formulas were deduced for constraints of the form x' A x + 2 b x, so we use b/2 in the formulas:
7777  * c1 = <lin_coefs, sol_lin_vars>
7778  * c2 = - norm(lin_coefs)^2/2
7779  * y(rho) = (I + rho * D)^-1 * (y(0) - rho * bp/2)
7780  * y'(rho) = -(I + rho * D)^-2 * (D y(0) + bp/2)
7781  * phi(rho) = <y(rho), D * y(rho) + pb> + c1 + c2*rho
7782  * phi'(rho) = <y'(rho), 2 * D * y(rho) + pb> + c2
7783  */
7784  phirho = 0.0;
7785  phirhoprime = 0.0;
7786  for( i = 0; i < n; i++ )
7787  {
7788  assert(1.0 + rho * D[i] != 0.0);
7789  yrho[i] = (y0_[i] - rho * bp[i]/2.0) / (1.0 + rho * D[i]);
7790  yrhoprime[i] = -(D[i] * y0_[i] + bp[i]/2.0) / ( (1.0 + rho * D[i])*(1.0 + rho * D[i]) );
7791  phirho += yrho[i] * (yrho[i] * D[i] + bp[i]);
7792  phirhoprime += yrhoprime[i] * (2 * D[i] * yrho[i] + bp[i]);
7793  }
7794  phirho += c2 * rho + c1;
7795  phirhoprime += c2;
7796 #ifdef DEBUG_PROJ
7797  printf("iteration %d: rho = %g, phirho = %g, phirho' = %g\n", iter, rho, phirho, phirhoprime);
7798 #endif
7799  }
7800 
7801  /* come back to the original coordinates: new ref point is P*yrho */
7802  for( i = 0; i < n; i++ )
7803  {
7804  ref[i] = 0.0;
7805 
7806  for( j = 0; j < n; j++ )
7807  ref[i] += pt[j*n + i] * yrho[j];
7808  }
7809 
7810  /* change data back if function is concave */
7811  if( isconcave )
7812  {
7813  for( i = 0; i < n; i++ )
7814  {
7815  D[i] = -D[i];
7816  bp[i] = -bp[i];
7817  }
7818  }
7819 
7820 #ifdef SCIP_DISABLED_CODE
7821  /* project onto bounds; this is important for some cut generation methods such as generateCutLTI */
7822  for( j = 0; j < consdata->nquadvars; ++j )
7823  {
7824  SCIP_Real lb;
7825  SCIP_Real ub;
7826  SCIP_VAR* var;
7827 
7828  var = consdata->quadvarterms[j].var;
7829  lb = SCIPvarGetLbLocal(var);
7830  ub = SCIPvarGetUbLocal(var);
7831  /* do not like variables at infinity */
7832  assert(!SCIPisInfinity(scip, lb));
7833  assert(!SCIPisInfinity(scip, -ub));
7834 
7835  ref[j] = MIN(ub, MAX(lb, ref[j])); /* project value into bounds */
7836  }
7837 #endif
7838 
7839 #ifdef DEBUG_PROJ
7840  printf("modified reference point by a projection:\n");
7841  for( j = 0; j < consdata->nquadvars; ++j )
7842  {
7843  printf("%s = %g\n", SCIPvarGetName(consdata->quadvarterms[j].var), ref[j]);
7844  }
7845 #endif
7846 
7847  SCIPfreeBufferArray(scip, &y0_);
7848  SCIPfreeBufferArray(scip, &yrho);
7849  SCIPfreeBufferArray(scip, &yrhoprime);
7850 
7851  return SCIP_OKAY;
7852 }
7853 
7854 /** compute reference point suggested by gauge function */
7855 static
7857  SCIP* scip, /**< SCIP data structure */
7858  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7859  SCIP_CONS* cons, /**< constraint */
7860  SCIP_SOL* refsol, /**< reference point where to compute gauge, or NULL if LP solution should be used */
7861  SCIP_Real* ref, /**< array to store reference point */
7862  SCIP_Bool* success /**< buffer to store whether we succeeded computing reference point */
7863  )
7864 {
7865  SCIP_CONSDATA* consdata;
7866  SCIP_Real gaugeval;
7867  SCIP_Real intpoint;
7868  SCIP_Real lb;
7869  SCIP_Real ub;
7870  SCIP_VAR* var;
7871  int j;
7872 
7873  assert(scip != NULL);
7874  assert(conshdlr != NULL);
7875  assert(cons != NULL);
7876 
7877  consdata = SCIPconsGetData(cons);
7878  assert(consdata != NULL);
7879  assert(consdata->isgaugeavailable);
7880 
7881  SCIPdebugMsg(scip, "evaluating gauge\n");
7882  SCIP_CALL( evaluateGauge(scip, conshdlr, cons, refsol, &gaugeval, success) );
7883 
7884  if( !(*success) )
7885  {
7886 #ifdef SCIP_DEBUG_GAUGE
7887  printf("Couldn't evaluate gauge!\n");
7888 #endif
7889  return SCIP_OKAY;
7890  }
7891 
7892 #ifdef SCIP_DEBUG_GAUGE
7893  {
7894  SCIP_Real level;
7895 
7896  level = consdata->rhs;
7897  for( j = 0; j < consdata->nlinvars; j++ )
7898  level -= SCIPgetSolVal(scip, refsol, consdata->linvars[j]) * consdata->lincoefs[j];
7899 
7900  printf("Summary:\n");
7901  printf("For cons <%s>: gauge at level %g evaluated at (refsol - intpoint) is %.10f\n",
7902  SCIPconsGetName(cons), level, gaugeval);
7903  printf("refsol - intpoint:\n");
7904 
7905  for( j = 0; j < consdata->nquadvars; ++j )
7906  {
7907  SCIP_VAR* vvar;
7908  vvar = consdata->quadvarterms[j].var;
7909  printf("%s: % 20.15g - %g = %g\n", SCIPvarGetName(vvar), SCIPgetSolVal(scip, refsol, vvar),
7910  consdata->interiorpoint[j], SCIPgetSolVal(scip, refsol, vvar) - consdata->interiorpoint[j]);
7911  }
7912  if( SCIPisFeasLE(scip, gaugeval, 1.0) )
7913  printf("refsol is in the closure of the region (gaugeval <= 1), don't modify reference point\n");
7914  }
7915 #endif
7916 
7917  /* scale gauge value so that final point is close to the boundary, but not on the boundary (weakens the cut) */
7918  gaugeval *= GAUGESCALE;
7919 
7920  /* if the point is not sufficiently violated, we don't modify it */
7921  if( SCIPisFeasLE(scip, gaugeval, 1.0) )
7922  {
7923  *success = FALSE;
7924  return SCIP_OKAY;
7925  }
7926 
7927  /* set reference to (refsol - interior point)/gaugeval + interior point and project onto bounds this is important for
7928  * some cut generation methods such as generateCutLTI
7929  * @todo remove the projection onto the bounds; generateCutLTI shouldn't be called for convex constraints
7930  */
7931  for( j = 0; j < consdata->nquadvars; ++j )
7932  {
7933  var = consdata->quadvarterms[j].var;
7934  lb = SCIPvarGetLbLocal(var);
7935  ub = SCIPvarGetUbLocal(var);
7936  /* do not like variables at infinity */
7937  assert(!SCIPisInfinity(scip, lb));
7938  assert(!SCIPisInfinity(scip, -ub));
7939 
7940  intpoint = consdata->interiorpoint[j];
7941  ref[j] = (SCIPgetSolVal(scip, refsol, var) - intpoint) / gaugeval + intpoint;
7942  ref[j] = MIN(ub, MAX(lb, ref[j])); /* project value into bounds */
7943  }
7944 
7945 #ifdef SCIP_DEBUG_GAUGE
7946  printf("successful application of guage: %g\n", gaugeval);
7947  printf("modified reference point:\n");
7948  for( j = 0; j < consdata->nquadvars; ++j )
7949  {
7950  printf("%s = % 20.15g\n", SCIPvarGetName(consdata->quadvarterms[j].var), ref[j]);
7951  }
7952 #endif
7953 
7954  return SCIP_OKAY;
7955 }
7956 
7957 /** generates a cut based on linearization (if convex) or McCormick (if nonconvex) in a solution
7958  * @note mode indicates whether we should modify the point we want to cutoff (sol) via gauge or projection,
7959  * or if just normal linearization should be use, or the default way (whatever is specified via settings)
7960  */
7961 static
7963  SCIP* scip, /**< SCIP data structure */
7964  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7965  SCIP_CONS* cons, /**< constraint */
7966  SCIP_SOL* sol, /**< solution where to generate cut, or NULL if LP solution should be used */
7967  SCIP_SOL* refsol, /**< reference point where to generate cut, or NULL if sol should be used */
7968  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
7969  SCIP_ROW** row, /**< storage for cut */
7970  SCIP_Real* efficacy, /**< buffer to store efficacy of row in reference solution, or NULL if not of interest */
7971  SCIP_Bool checkcurvmultivar, /**< are we allowed to check the curvature of a multivariate quadratic function, if not done yet */
7972  SCIP_Real minefficacy, /**< minimal required efficacy (violation scaled by maximal absolute coefficient) */
7973  char mode /**< mode of execution 'g'auge, 'p'rojection, 'l'inearization gradient, 'd'efault */
7974  )
7975 {
7976  SCIP_CONSHDLRDATA* conshdlrdata;
7977  SCIP_CONSDATA* consdata;
7978  SCIP_VAR* var;
7979  SCIP_Real lb;
7980  SCIP_Real ub;
7981  SCIP_Real* ref;
7982  SCIP_Bool success;
7983  int j;
7984 
7985  assert(scip != NULL);
7986  assert(conshdlr != NULL);
7987  assert(cons != NULL);
7988 
7989  consdata = SCIPconsGetData(cons);
7990  assert(consdata != NULL);
7991 
7992  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7993  assert(conshdlrdata != NULL);
7994 
7995  if( refsol == NULL )
7996  refsol = sol;
7997 
7998  /* get reference point */
7999  SCIP_CALL( SCIPallocBufferArray(scip, &ref, consdata->nquadvars) );
8000  success = FALSE;
8001 
8002  if( mode == 'd')
8003  {
8004  if( (consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) ||
8005  (consdata->isconcave && violside == SCIP_SIDETYPE_LEFT) )
8006  {
8007  if( conshdlrdata->gaugecuts && consdata->isgaugeavailable )
8008  {
8009  SCIP_CALL( computeReferencePointGauge(scip, conshdlr, cons, refsol, ref, &success) );
8010  }
8011  else if( conshdlrdata->projectedcuts && consdata->isedavailable )
8012  {
8013  SCIPdebugMessage("use the projection of refsol onto the region defined by the constraint as reference point\n");
8014  SCIP_CALL( computeReferencePointProjection(scip, conshdlr, cons, refsol, ref) );
8015  success = TRUE;
8016  }
8017  }
8018 
8019  if( success )
8020  {
8021  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
8022 
8023  /* if cut fails, try again without modifying reference point */
8024  if( *row == NULL || (efficacy != NULL && !SCIPisGT(scip, *efficacy, minefficacy)) || !SCIPisCutApplicable(scip, *row) ) /*lint !e644 */
8025  {
8026  SCIPdebugMsg(scip, "%s cut fail, try without modifying\n", conshdlrdata->gaugecuts ? "gauge" : "projected");
8027  success = FALSE;
8028  }
8029  }
8030 
8031  /* note that this is not the same as calling this method with mode 'l', 'l' assume convex/concave function */
8032  if( !success )
8033  {
8034  for( j = 0; j < consdata->nquadvars; ++j )
8035  {
8036  var = consdata->quadvarterms[j].var;
8037  lb = SCIPvarGetLbLocal(var);
8038  ub = SCIPvarGetUbLocal(var);
8039  /* do not like variables at infinity */
8040  assert(!SCIPisInfinity(scip, lb));
8041  assert(!SCIPisInfinity(scip, -ub));
8042 
8043  ref[j] = SCIPgetSolVal(scip, refsol, var);
8044  ref[j] = MIN(ub, MAX(lb, ref[j])); /* project value into bounds */
8045  }
8046 
8047  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
8048  }
8049  }
8050  /* gauge cut */
8051  if( mode == 'g' )
8052  {
8053  assert((consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) || (consdata->isconcave && violside == SCIP_SIDETYPE_LEFT));
8054  if( conshdlrdata->gaugecuts && consdata->isgaugeavailable )
8055  {
8056  SCIP_CALL( computeReferencePointGauge(scip, conshdlr, cons, refsol, ref, &success) );
8057  }
8058  if( success )
8059  {
8060  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
8061  }
8062  }
8063  /* projection cut */
8064  if( mode == 'p' )
8065  {
8066  assert((consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) || (consdata->isconcave && violside == SCIP_SIDETYPE_LEFT));
8067  if( conshdlrdata->projectedcuts && consdata->isedavailable )
8068  {
8069  SCIP_CALL( computeReferencePointProjection(scip, conshdlr, cons, refsol, ref) );
8070  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
8071  }
8072  }
8073  /* gradient linearization cut at refsol */
8074  if( mode == 'l' )
8075  {
8076  assert((consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) || (consdata->isconcave && violside == SCIP_SIDETYPE_LEFT));
8077  for( j = 0; j < consdata->nquadvars; ++j )
8078  {
8079  var = consdata->quadvarterms[j].var;
8080  lb = SCIPvarGetLbLocal(var);
8081  ub = SCIPvarGetUbLocal(var);
8082  /* do not like variables at infinity */
8083  assert(!SCIPisInfinity(scip, lb));
8084  assert(!SCIPisInfinity(scip, -ub));
8085 
8086  ref[j] = SCIPgetSolVal(scip, refsol, var);
8087  ref[j] = MIN(ub, MAX(lb, ref[j])); /* project value into bounds */
8088  }
8089  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
8090  }
8091 
8092  SCIPfreeBufferArray(scip, &ref);
8093 
8094  return SCIP_OKAY;
8095 }
8096 
8097 /** tries to find a cut that intersects with an unbounded ray of the LP
8098  *
8099  * For convex functions, we do this by linearizing in the feasible solution of the LPI.
8100  * For nonconvex functions, we just call generateCutSol with the unbounded solution as reference point.
8101  */
8102 static
8104  SCIP* scip, /**< SCIP data structure */
8105  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8106  SCIP_CONS* cons, /**< constraint */
8107  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
8108  SCIP_ROW** row, /**< storage for cut */
8109  SCIP_Real* rowrayprod, /**< buffer to store product of ray with row coefficients, or NULL if not of interest */
8110  SCIP_Bool checkcurvmultivar /**< are we allowed to check the curvature of a multivariate quadratic function, if not done yet */
8111  )
8112 {
8113  SCIP_CONSDATA* consdata;
8114  SCIP_BILINTERM* bilinterm;
8115  SCIP_VAR* var;
8116  SCIP_Real* ref;
8117  SCIP_Real matrixrayprod;
8118  SCIP_Real linrayprod;
8119  SCIP_Real quadrayprod;
8120  SCIP_Real rayval;
8121  int i;
8122  int j;
8123 
8124  assert(scip != NULL);
8125  assert(conshdlr != NULL);
8126  assert(cons != NULL);
8127  assert(row != NULL);
8129 
8130  consdata = SCIPconsGetData(cons);
8131  assert(consdata != NULL);
8132 
8133  *row = NULL;
8134 
8135  if( !SCIPhasPrimalRay(scip) )
8136  {
8137  SCIPdebugMsg(scip, "do not have primal ray, thus cannot resolve unboundedness\n");
8138  return SCIP_OKAY;
8139  }
8140 
8141  SCIP_CALL( checkCurvature(scip, cons, checkcurvmultivar) );
8142  if( (!consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) ||
8143  (!consdata->isconcave && violside == SCIP_SIDETYPE_LEFT) )
8144  {
8145  /* if not convex, just call generateCut and hope it's getting something useful */
8146  SCIP_CALL( generateCutSol(scip, conshdlr, cons, NULL, NULL, violside, row, NULL, FALSE, -SCIPinfinity(scip), 'd') );
8147 
8148  /* compute product of cut coefficients with ray, if required */
8149  if( *row != NULL && rowrayprod != NULL )
8150  {
8151  *rowrayprod = 0.0;
8152  for( i = 0; i < SCIProwGetNNonz(*row); ++i )
8153  {
8154  assert(SCIProwGetCols(*row)[i] != NULL);
8155  var = SCIPcolGetVar(SCIProwGetCols(*row)[i]);
8156  assert(var != NULL);
8157 
8158  *rowrayprod += SCIProwGetVals(*row)[i] * SCIPgetPrimalRayVal(scip, var);
8159  }
8160  }
8161 
8162  return SCIP_OKAY;
8163  }
8164 
8165  /* we seek for a linearization of the quadratic function such that it intersects with the unbounded ray
8166  * that is, we need a reference point ref such that for the gradient g of xAx+bx in ref, we have
8167  * <g, ray> > 0.0 if rhs is finite and <g, ray> < 0.0 if lhs is finite
8168  * Since g = 2*A*ref + b, we have <g, ray> = <2*A*ref + b, ray> = <ref, 2*A*ray> + <b,ray>
8169  * 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)
8170  * <ref, 2*A*ray> + <b,ray> is sufficiently larger 0.0, we call generateCut for this point, otherwise, we scale up ref
8171  */
8172 
8173  quadrayprod = 0.0; /* <ref, 2*A*ray> */
8174  linrayprod = 0.0; /* <b, ray> */
8175  SCIP_CALL( SCIPallocBufferArray(scip, &ref, consdata->nquadvars) );
8176  for( i = 0; i < consdata->nquadvars; ++i )
8177  {
8178  var = consdata->quadvarterms[i].var;
8179  rayval = SCIPgetPrimalRayVal(scip, var);
8180 
8181  /* compute i-th entry of (2*A*ray) */
8182  matrixrayprod = 2.0 * consdata->quadvarterms[i].sqrcoef * rayval;
8183  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
8184  {
8185  bilinterm = &consdata->bilinterms[consdata->quadvarterms[i].adjbilin[j]];
8186  matrixrayprod += bilinterm->coef * SCIPgetPrimalRayVal(scip, bilinterm->var1 == var ? bilinterm->var2 : bilinterm->var1);
8187  }
8188 
8189  if( SCIPisPositive(scip, matrixrayprod) )
8190  ref[i] = (violside == SCIP_SIDETYPE_RIGHT ? 1.0 : -1.0);
8191  else if( SCIPisNegative(scip, matrixrayprod) )
8192  ref[i] = (violside == SCIP_SIDETYPE_RIGHT ? -1.0 : 1.0);
8193  else
8194  ref[i] = 0.0;
8195 
8196  quadrayprod += matrixrayprod * ref[i];
8197  linrayprod += consdata->quadvarterms[i].lincoef * rayval;
8198  }
8199  assert((violside == SCIP_SIDETYPE_RIGHT && quadrayprod >= 0.0) || (violside == SCIP_SIDETYPE_LEFT && quadrayprod <= 0.0));
8200 
8201  if( SCIPisZero(scip, quadrayprod) )
8202  {
8203  SCIPdebugMsg(scip, "ray is zero along cons <%s>\n", SCIPconsGetName(cons));
8204  SCIPfreeBufferArray(scip, &ref);
8205  return SCIP_OKAY;
8206  }
8207 
8208  /* add linear part to linrayprod */
8209  for( i = 0; i < consdata->nlinvars; ++i )
8210  linrayprod += consdata->lincoefs[i] * SCIPgetPrimalRayVal(scip, consdata->linvars[i]);
8211 
8212  SCIPdebugMsg(scip, "initially have <b,ray> = %g and <ref, 2*A*ref> = %g\n", linrayprod, quadrayprod);
8213 
8214  /* 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
8215  * if <b,ray> is zero, then we scale refpoint up if |<ref, 2*A*ray>| < 1.0
8216  */
8217  if( (!SCIPisZero(scip, linrayprod) && violside == SCIP_SIDETYPE_RIGHT && quadrayprod < -2*linrayprod) ||
8218  ( !SCIPisZero(scip, linrayprod) && violside == SCIP_SIDETYPE_LEFT && quadrayprod > -2*linrayprod) ||
8219  (SCIPisZero(scip, linrayprod) && REALABS(quadrayprod) < 1.0) )
8220  {
8221  SCIP_Real scale;
8222 
8223  if( !SCIPisZero(scip, linrayprod) )
8224  scale = 2*REALABS(linrayprod/quadrayprod); /*lint !e795 */
8225  else
8226  scale = 1.0/REALABS(quadrayprod);
8227 
8228  SCIPdebugMsg(scip, "scale refpoint by %g\n", scale);
8229  for( i = 0; i < consdata->nquadvars; ++i )
8230  ref[i] *= scale;
8231  quadrayprod *= scale;
8232  }
8233 
8234  if( rowrayprod != NULL )
8235  *rowrayprod = quadrayprod + linrayprod;
8236 
8237  SCIPdebugMsg(scip, "calling generateCut, expecting ray product %g\n", quadrayprod + linrayprod);
8238  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, NULL, violside, row, NULL, FALSE, -SCIPinfinity(scip)) );
8239 
8240  SCIPfreeBufferArray(scip, &ref);
8241 
8242  return SCIP_OKAY;
8243 }
8244 
8245 /** processes a cut for constraint cons, i.e., checks numerics and possibly adds cut to sepastore */
8246 static
8248  SCIP* scip, /**< SCIP data structure */
8249  SCIP_ROW** row, /**< cut to process */
8250  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
8251  SCIP_CONS* cons, /**< constraint */
8252  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
8253  SCIP_Real efficacy, /**< efficacy of row in reference solution */
8254  SCIP_Real actminefficacy, /**< actual minimal efficacy (whatever that is) */
8255  SCIP_Bool inenforcement, /**< whether we are in constraint enforcement */
8256  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 */
8257  SCIP_RESULT* result /**< result of separation */
8258  )
8259 {
8260  SCIP_CONSDATA* consdata;
8261  SCIP_CONSHDLRDATA* conshdlrdata;
8262 
8263  assert(scip != NULL);
8264  assert(row != NULL);
8265  assert(conshdlr != NULL);
8266  assert(result != NULL);
8267  assert(cons != NULL);
8268 
8269  /* no cut to process */
8270  if( *row == NULL )
8271  return SCIP_OKAY;
8272 
8273  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8274  assert(conshdlrdata != NULL);
8275 
8276  consdata = SCIPconsGetData(cons);
8277  assert(consdata != NULL);
8278 
8279  if( SCIPisGT(scip, efficacy, actminefficacy) && SCIPisCutApplicable(scip, *row) ) /*lint !e644 */
8280  {
8281  SCIP_Bool infeasible;
8282 
8283  /* cut cuts off solution */
8284  SCIP_CALL( SCIPaddCut(scip, sol, *row, FALSE /* forcecut */, &infeasible) );
8285  if( infeasible )
8286  {
8287  SCIPdebugMessage("cut for constraint <%s> is infeasible -> cutoff.\n", SCIPconsGetName(cons));
8288  *result = SCIP_CUTOFF;
8289  }
8290  else
8291  {
8292  SCIPdebugMessage("add cut with efficacy %g for constraint <%s> violated by %g\n", efficacy,
8293  SCIPconsGetName(cons), consdata->lhsviol+consdata->rhsviol);
8294  *result = SCIP_SEPARATED;
8295  }
8296  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8297 
8298  /* mark row as not removable from LP for current node, if in enforcement */
8299  if( inenforcement && !conshdlrdata->enfocutsremovable )
8300  SCIPmarkRowNotRemovableLocal(scip, *row);
8301  }
8302  if( bestefficacy != NULL && efficacy > *bestefficacy )
8303  *bestefficacy = efficacy;
8304 
8305  SCIP_CALL( SCIPreleaseRow (scip, row) );
8306  return SCIP_OKAY;
8307 }
8308 /** tries to separate solution or LP solution by a linear cut
8309  *
8310  * assumes that constraint violations have been computed
8311  */
8312 static
8314  SCIP* scip, /**< SCIP data structure */
8315  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
8316  SCIP_CONS** conss, /**< constraints */
8317  int nconss, /**< number of constraints */
8318  int nusefulconss, /**< number of constraints that seem to be useful */
8319  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
8320  SCIP_Real minefficacy, /**< minimal efficacy of a cut if it should be added to the LP */
8321  SCIP_Bool inenforcement, /**< whether we are in constraint enforcement */
8322  SCIP_RESULT* result, /**< result of separation */
8323  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 */
8324  )
8325 {
8326  SCIP_CONSHDLRDATA* conshdlrdata;
8327  SCIP_CONSDATA* consdata;
8328  SCIP_Real efficacy;
8329  SCIP_Real actminefficacy;
8330  SCIP_SIDETYPE violside;
8331  int c;
8332  SCIP_ROW* row;
8333 
8334  assert(scip != NULL);
8335  assert(conshdlr != NULL);
8336  assert(conss != NULL || nconss == 0);
8337  assert(nusefulconss <= nconss);
8338  assert(result != NULL);
8339 
8340  *result = SCIP_FEASIBLE;
8341 
8342  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8343  assert(conshdlrdata != NULL);
8344 
8345  if( bestefficacy != NULL )
8346  *bestefficacy = 0.0;
8347 
8348  row = NULL;
8349  /* loop over both sides of each constraint */
8350  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) )
8351  {
8352  assert(conss != NULL);
8353  consdata = SCIPconsGetData(conss[c]);
8354  assert(consdata != NULL);
8355 
8356  /* if side not violated, then go on */
8357  if( !SCIPisGT(scip, violside == SCIP_SIDETYPE_LEFT ? consdata->lhsviol : consdata->rhsviol, SCIPfeastol(scip)) )
8358  continue;
8359 
8360  /* we are not feasible anymore */
8361  if( *result == SCIP_FEASIBLE )
8362  *result = SCIP_DIDNOTFIND;
8363 
8364  /* actual minimal efficacy */
8365  actminefficacy = inenforcement && ((violside == SCIP_SIDETYPE_RIGHT && consdata->isconvex ) || (violside == SCIP_SIDETYPE_LEFT && consdata->isconcave))
8366  ? (SCIPgetRelaxFeastolFactor(scip) > 0.0 ? SCIPepsilon(scip) : SCIPfeastol(scip))
8367  : minefficacy;
8368 
8369  /* generate cut */
8370  if( sol == NULL && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY )
8371  {
8372  /* if the LP is unbounded, then we need a cut that cuts into the direction of a hopefully existing primal ray
8373  * 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
8374  * given a cut lhs <= <c,x> <= rhs, we check whether it imposes an upper bound on t and thus bounds the ray
8375  * 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>
8376  * similar, lhs > -infinity and <c,r> < 0 is good
8377  */
8378  SCIP_Real rayprod;
8379  SCIP_Real norm;
8380 
8381  rayprod = 0.0; /* for compiler */
8382  SCIP_CALL( generateCutUnboundedLP(scip, conshdlr, conss[c], violside, &row, &rayprod, conshdlrdata->checkcurvature) );
8383 
8384  if( row != NULL )
8385  {
8386  if( !SCIPisInfinity(scip, SCIProwGetRhs(row)) && SCIPisPositive(scip, rayprod) )
8387  efficacy = rayprod;
8388  else if( !SCIPisInfinity(scip, -SCIProwGetLhs(row)) && SCIPisNegative(scip, rayprod) )
8389  efficacy = -rayprod;
8390  else
8391  efficacy = 0.0;
8392 
8393  switch( conshdlrdata->scaling )
8394  {
8395  case 'o' :
8396  break;
8397 
8398  case 'g' :
8399  /* in difference to SCIPgetCutEfficacy, we scale by norm only if the norm is > 1.0 this avoid finding
8400  * cuts efficient which are only very slightly violated CPLEX does not seem to scale row
8401  * coefficients up too also we use infinity norm, since that seem to be the usual scaling strategy
8402  * in LP solvers (equilibrium scaling) */
8403  norm = SCIPgetRowMaxCoef(scip, row);
8404  efficacy /= MAX(1.0, norm);
8405  break;
8406 
8407  case 's' :
8408  {
8409  SCIP_Real abslhs = REALABS(SCIProwGetLhs(row));
8410  SCIP_Real absrhs = REALABS(SCIProwGetRhs(row));
8411  SCIP_Real minval = MIN(abslhs, absrhs);
8412 
8413  efficacy /= MAX(1.0, minval);
8414  break;
8415  }
8416 
8417  default:
8418  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
8419  SCIPABORT();
8420  return SCIP_INVALIDDATA; /*lint !e527*/
8421  }
8422 
8423  SCIP_CALL( processCut(scip, &row, conshdlr, conss[c], sol, efficacy, actminefficacy, inenforcement, bestefficacy, result) );
8424  }
8425  continue;
8426  }
8427  else
8428  {
8429  SCIP_CALL( generateCutSol(scip, conshdlr, conss[c], sol, NULL, violside, &row, &efficacy,
8430  conshdlrdata->checkcurvature, actminefficacy, 'd') );
8431  /* @todo If generation failed not because of low efficacy, then probably because of numerical issues */
8432  SCIP_CALL( processCut(scip, &row, conshdlr, conss[c], sol, efficacy, actminefficacy, inenforcement, bestefficacy, result) );
8433  }
8434 
8435  if( *result == SCIP_CUTOFF )
8436  break;
8437 
8438  /* enforce only useful constraints
8439  * others are only checked and enforced if we are still feasible or have not found a separating cut yet
8440  */
8441  if( c >= nusefulconss && *result == SCIP_SEPARATED )
8442  break;
8443  }
8444 
8445  return SCIP_OKAY;
8446 }
8447 
8448 /** adds linearizations cuts for convex constraints w.r.t. a given reference point to cutpool and sepastore
8449  *
8450  * - 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.
8451  * - If separatedlpsol is not NULL, but cut does not separate the LP solution, then it is added to the cutpool only.
8452  * - If separatedlpsol is NULL, then cut is added to cutpool only.
8453  */
8454 static
8456  SCIP* scip, /**< SCIP data structure */
8457  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
8458  SCIP_CONS** conss, /**< constraints */
8459  int nconss, /**< number of constraints */
8460  SCIP_SOL* ref, /**< reference point where to linearize, or NULL for LP solution */
8461  SCIP_Bool* separatedlpsol, /**< buffer to store whether a cut that separates the current LP solution was found and added to LP,
8462  * or NULL if adding to cutpool only */
8463  SCIP_Real minefficacy /**< minimal efficacy of a cut when checking for separation of LP solution */
8464  )
8465 {
8466  SCIP_CONSHDLRDATA* conshdlrdata;
8467  SCIP_CONSDATA* consdata;
8468  SCIP_Bool addedtolp;
8469  SCIP_ROW* row;
8470  int c;
8471 
8472  assert(scip != NULL);
8473  assert(conshdlr != NULL);
8474  assert(conss != NULL || nconss == 0);
8475 
8476  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8477  assert(conshdlrdata != NULL);
8478 
8479  if( separatedlpsol != NULL )
8480  *separatedlpsol = FALSE;
8481 
8482  for( c = 0; c < nconss; ++c )
8483  {
8484  assert(conss[c] != NULL); /*lint !e613 */
8485 
8486  if( SCIPconsIsLocal(conss[c]) || !SCIPconsIsEnabled(conss[c]) ) /*lint !e613 */
8487  continue;
8488 
8489  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
8490 
8491  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
8492  assert(consdata != NULL);
8493 
8494  if( consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs) )
8495  {
8496  SCIP_CALL( generateCutSol(scip, conshdlr, conss[c], NULL, ref, SCIP_SIDETYPE_RIGHT, &row, NULL,
8497  conshdlrdata->checkcurvature, -SCIPinfinity(scip), 'l') ); /*lint !e613 */
8498  }
8499  else if( consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs) )
8500  {
8501  SCIP_CALL( generateCutSol(scip, conshdlr, conss[c], NULL, ref, SCIP_SIDETYPE_LEFT, &row, NULL,
8502  conshdlrdata->checkcurvature, -SCIPinfinity(scip), 'l') ); /*lint !e613 */
8503  }
8504  else
8505  continue;
8506 
8507  if( row == NULL )
8508  continue;
8509 
8510  addedtolp = FALSE;
8511 
8512  /* if caller wants, then check if cut separates LP solution and add to sepastore if so */
8513  if( separatedlpsol != NULL )
8514  {
8515  SCIP_Real efficacy;
8516  SCIP_Real norm;
8517 
8518  efficacy = -SCIPgetRowLPFeasibility(scip, row);
8519  switch( conshdlrdata->scaling )
8520  {
8521  case 'o' :
8522  break;
8523 
8524  case 'g' :
8525  /* in difference to SCIPgetCutEfficacy, we scale by norm only if the norm is > 1.0 this avoid finding cuts
8526  * efficient which are only very slightly violated CPLEX does not seem to scale row coefficients up too
8527  * also we use infinity norm, since that seem to be the usual scaling strategy in LP solvers (equilibrium
8528  * scaling) */
8529  norm = SCIPgetRowMaxCoef(scip, row);
8530  efficacy /= MAX(1.0, norm);
8531  break;
8532 
8533  case 's' :
8534  {
8535  SCIP_Real abslhs = REALABS(SCIProwGetLhs(row));
8536  SCIP_Real absrhs = REALABS(SCIProwGetRhs(row));
8537  SCIP_Real minval = MIN(abslhs, absrhs);
8538 
8539  efficacy /= MAX(1.0, minval);
8540  break;
8541  }
8542 
8543  default:
8544  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
8545  SCIPABORT();
8546  return SCIP_INVALIDDATA; /*lint !e527*/
8547  }
8548 
8549  if( efficacy >= minefficacy )
8550  {
8551  SCIP_Bool infeasible;
8552 
8553  *separatedlpsol = TRUE;
8554  addedtolp = TRUE;
8555  SCIP_CALL( SCIPaddCut(scip, NULL, row, TRUE, &infeasible) );
8556  assert( ! infeasible );
8557  SCIPdebugMsg(scip, "added linearization cut <%s> to LP, efficacy = %g\n", SCIProwGetName(row), efficacy);
8558  }
8559  }
8560 
8561  if( !SCIProwIsLocal(row) && !addedtolp )
8562  {
8563  SCIP_CALL( SCIPaddPoolCut(scip, row) );
8564  SCIPdebugMsg(scip, "added linearization cut <%s> to cutpool\n", SCIProwGetName(row));
8565  }
8566 
8567  SCIP_CALL( SCIPreleaseRow(scip, &row) );
8568  }
8569 
8570  return SCIP_OKAY;
8571 }
8572 
8573 /** processes the event that a new primal solution has been found */
8574 static
8575 SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
8577  SCIP_CONSHDLRDATA* conshdlrdata;
8578  SCIP_CONSHDLR* conshdlr;
8579  SCIP_CONS** conss;
8580  int nconss;
8581  SCIP_SOL* sol;
8582 
8583  assert(scip != NULL);
8584  assert(event != NULL);
8585  assert(eventdata != NULL);
8586  assert(eventhdlr != NULL);
8587 
8588  assert((SCIPeventGetType(event) & SCIP_EVENTTYPE_SOLFOUND) != 0);
8589 
8590  conshdlr = (SCIP_CONSHDLR*)eventdata;
8591 
8592  nconss = SCIPconshdlrGetNConss(conshdlr);
8593 
8594  if( nconss == 0 )
8595  return SCIP_OKAY;
8596 
8597  sol = SCIPeventGetSol(event);
8598  assert(sol != NULL);
8599 
8600  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8601  assert(conshdlrdata != NULL);
8602 
8603  /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
8604  * the reason for ignoring trysol solutions is that they may come from an NLP solve in sepalp, where we already added linearizations,
8605  * or are from the tree, but postprocessed via proposeFeasibleSolution
8606  */
8607  if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
8608  return SCIP_OKAY;
8609 
8610  conss = SCIPconshdlrGetConss(conshdlr);
8611  assert(conss != NULL);
8612 
8613  SCIPdebugMsg(scip, "caught new sol event %" SCIP_EVENTTYPE_FORMAT " from heur <%s>; have %d conss\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)), nconss);
8614 
8615  SCIP_CALL( addLinearizationCuts(scip, conshdlr, conss, nconss, sol, NULL, 0.0) );
8616 
8617  return SCIP_OKAY;
8618 }
8619 
8620 /** registers branching candidates according to convexification gap rule
8621  *
8622  * That is, computes for every nonconvex term the gap between the terms value in the LP solution and the value of the underestimator
8623  * as it would be (and maybe has been) constructed by the separation routines of this constraint handler. Then it registers all
8624  * variables occurring in each term with the computed gap. If variables appear in more than one term, they are registered several times.
8625  */
8626 static
8628  SCIP* scip, /**< SCIP data structure */
8629  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8630  SCIP_CONS** conss, /**< constraints to check */
8631  int nconss, /**< number of constraints to check */
8632  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8633  int* nnotify /**< counter for number of notifications performed */
8634  )
8635 {
8636  SCIP_CONSDATA* consdata;
8637  int c;
8638  int j;
8639  SCIP_Bool xbinary;
8640  SCIP_Bool ybinary;
8641  SCIP_Bool xunbounded;
8642  SCIP_Bool yunbounded;
8643  SCIP_VAR* x;
8644  SCIP_VAR* y;
8645  SCIP_Real xlb;
8646  SCIP_Real xub;
8647  SCIP_Real xval;
8648  SCIP_Real ylb;
8649  SCIP_Real yub;
8650  SCIP_Real yval;
8651  SCIP_Real gap;
8652  SCIP_Real coef_;
8653 
8654  assert(scip != NULL);
8655  assert(conshdlr != NULL);
8656  assert(conss != NULL || nconss == 0);
8657 
8658  *nnotify = 0;
8659  yval = SCIP_INVALID;
8660  xval = SCIP_INVALID;
8661 
8662  for( c = 0; c < nconss; ++c )
8663  {
8664  assert(conss != NULL);
8665  consdata = SCIPconsGetData(conss[c]);
8666  assert(consdata != NULL);
8667 
8668  if( !consdata->nquadvars )
8669  continue;
8670 
8671  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || consdata->isconcave) &&
8672  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || consdata->isconvex ) )
8673  continue;
8674  SCIPdebugMsg(scip, "cons %s violation: %g %g convex: %u %u\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->isconvex, consdata->isconcave);
8675 
8676  /* square terms */
8677  for( j = 0; j < consdata->nquadvars; ++j )
8678  {
8679  x = consdata->quadvarterms[j].var;
8680  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && consdata->quadvarterms[j].sqrcoef < 0) ||
8681  ( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && consdata->quadvarterms[j].sqrcoef > 0) )
8682  {
8683  xlb = SCIPvarGetLbLocal(x);
8684  xub = SCIPvarGetUbLocal(x);
8685  if( SCIPisRelEQ(scip, xlb, xub) )
8686  {
8687  SCIPdebugMsg(scip, "ignore fixed variable <%s>[%g, %g], diff %g\n", SCIPvarGetName(x), xlb, xub, xub-xlb);
8688  continue;
8689  }
8690 
8691  xval = SCIPgetSolVal(scip, sol, x);
8692 
8693  /* if variable is at bounds, then no need to branch, since secant is exact there */
8694  if( SCIPisLE(scip, xval, xlb) || SCIPisGE(scip, xval, xub) )
8695  continue;
8696 
8697  if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) )
8698  gap = SCIPinfinity(scip);
8699  else
8700  gap = (xval-xlb)*(xub-xval)/(1+2*ABS(xval));
8701  assert(!SCIPisFeasNegative(scip, gap));
8702  SCIP_CALL( SCIPaddExternBranchCand(scip, x, MAX(gap, 0.0), SCIP_INVALID) );
8703  ++*nnotify;
8704  }
8705  }
8706 
8707  /* bilinear terms */
8708  for( j = 0; j < consdata->nbilinterms; ++j )
8709  {
8710  /* if any of the variables if fixed, then it actually behaves like a linear term, so we don't need to branch on it */
8711  x = consdata->bilinterms[j].var1;
8712  xlb = SCIPvarGetLbLocal(x);
8713  xub = SCIPvarGetUbLocal(x);
8714  if( SCIPisRelEQ(scip, xlb, xub) )
8715  continue;
8716 
8717  y = consdata->bilinterms[j].var2;
8718  ylb = SCIPvarGetLbLocal(y);
8719  yub = SCIPvarGetUbLocal(y);
8720  if( SCIPisRelEQ(scip, ylb, yub) )
8721  continue;
8722 
8723  xunbounded = SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub);
8724  yunbounded = SCIPisInfinity(scip, -ylb) || SCIPisInfinity(scip, yub);
8725 
8726  /* compute gap, if both variable are bounded */
8727  gap = SCIPinfinity(scip);
8728  if( !xunbounded && !yunbounded )
8729  {
8730  xval = SCIPgetSolVal(scip, sol, x);
8731  yval = SCIPgetSolVal(scip, sol, y);
8732 
8733  /* if both variables are at one of its bounds, then no need to branch, since McCormick is exact there */
8734  if( (SCIPisLE(scip, xval, xlb) || SCIPisGE(scip, xval, xub)) &&
8735  ( SCIPisLE(scip, yval, ylb) || SCIPisGE(scip, yval, yub)) )
8736  continue;
8737 
8738  xval = MAX(xlb, MIN(xval, xub));
8739  yval = MAX(ylb, MIN(yval, yub));
8740 
8741  coef_ = SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) ? -consdata->bilinterms[j].coef : consdata->bilinterms[j].coef;
8742  if( coef_ > 0.0 )
8743  {
8744  if( (xub-xlb)*yval + (yub-ylb)*xval <= xub*yub - xlb*ylb )
8745  gap = (xval*yval - xlb*yval - ylb*xval + xlb*ylb) / (1+sqrt(xval*xval + yval*yval));
8746  else
8747  gap = (xval*yval - xval*yub - yval*xub + xub*yub) / (1+sqrt(xval*xval + yval*yval));
8748  }
8749  else
8750  { /* coef_ < 0 */
8751  if( (xub-xlb)*yval - (yub-ylb)*xval <= xub*ylb - xlb*yub )
8752  gap = -(xval*yval - xval*ylb - yval*xub + xub*ylb) / (1+sqrt(xval*xval + yval*yval));
8753  else
8754  gap = -(xval*yval - xval*yub - yval*xlb + xlb*yub) / (1+sqrt(xval*xval + yval*yval));
8755  }
8756 
8757  assert(!SCIPisNegative(scip, gap / MAX3(MAX(REALABS(xlb), REALABS(xub)), MAX(REALABS(ylb), REALABS(yub)), 1.0))); /*lint !e666*/
8758  if( gap < 0.0 )
8759  gap = 0.0;
8760  }
8761 
8762  /* if one of the variables is binary or integral with domain width 1, then branching on this makes the term linear, so prefer this */
8763  xbinary = SCIPvarIsBinary(x) || (SCIPvarIsIntegral(x) && xub - xlb < 1.5);
8764  ybinary = SCIPvarIsBinary(y) || (SCIPvarIsIntegral(y) && yub - ylb < 1.5);
8765  if( xbinary )
8766  {
8768  ++*nnotify;
8769  }
8770  if( ybinary )
8771  {
8773  ++*nnotify;
8774  }
8775  if( xbinary || ybinary )
8776  continue;
8777 
8778  /* if one of the variables is unbounded, then branch on it first */
8779  if( xunbounded )
8780  {
8782  ++*nnotify;
8783  }
8784  if( yunbounded )
8785  {
8787  ++*nnotify;
8788  }
8789  if( xunbounded || yunbounded )
8790  continue;
8791 
8792  /* if both variables are integral, prefer the one with the smaller domain, so variable gets fixed soon
8793  * does not seem to work well on tln instances, so disable for now and may look at it later again
8794  */
8795 #ifdef BRANCHTOLINEARITY
8796  if( SCIPvarIsIntegral(x) && SCIPvarIsIntegral(y) )
8797  {
8798  if( SCIPisLT(scip, xub-xlb, yub-ylb) )
8799  {
8801  ++*nnotify;
8802  continue;
8803  }
8804  if( SCIPisGT(scip, xub-xlb, yub-ylb) )
8805  {
8807  ++*nnotify;
8808  continue;
8809  }
8810  }
8811 #endif
8812 
8813  /* in the regular case, suggest those variables which are not at its bounds for branching
8814  * this is, because after branching both variables will be one the bounds, and McCormick will be exact then */
8815  if( !SCIPisLE(scip, xval, xlb) && !SCIPisGE(scip, xval, xub) )
8816  {
8818  ++*nnotify;
8819  }
8820  if( !SCIPisLE(scip, yval, ylb) && !SCIPisGE(scip, yval, yub) )
8821  {
8823  ++*nnotify;
8824  }
8825  }
8826  }
8827 
8828  SCIPdebugMsg(scip, "registered %d branching candidates\n", *nnotify);
8829 
8830  return SCIP_OKAY;
8831 }
8832 
8833 /** registers branching candidates according to constraint violation rule
8834  *
8835  * That is, registers all variables appearing in nonconvex terms^1 with a score that is the violation of the constraint.
8836  * This is the same rule as is applied in cons_nonlinear and other nonlinear constraint handlers.
8837  *
8838  * 1) We mean all quadratic variables that appear either in a nonconvex square term or in a bilinear term, if the constraint
8839  * itself is nonconvex. (and this under the assumption that the rhs is violated; for violated lhs, swap terms)
8840  */
8841 static
8843  SCIP* scip, /**< SCIP data structure */
8844  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8845  SCIP_CONS** conss, /**< constraints to check */
8846  int nconss, /**< number of constraints to check */
8847  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8848  int* nnotify /**< counter for number of notifications performed */
8849  )
8850 {
8851  SCIP_CONSDATA* consdata;
8852  SCIP_QUADVARTERM* quadvarterm;
8853  int c;
8854  int j;
8855  SCIP_VAR* x;
8856  SCIP_Real xlb;
8857  SCIP_Real xub;
8858  SCIP_Real xval;
8859 
8860  assert(scip != NULL);
8861  assert(conshdlr != NULL);
8862  assert(conss != NULL || nconss == 0);
8863 
8864  *nnotify = 0;
8865 
8866  for( c = 0; c < nconss; ++c )
8867  {
8868  assert(conss != NULL);
8869  consdata = SCIPconsGetData(conss[c]);
8870  assert(consdata != NULL);
8871 
8872  if( !consdata->nquadvars )
8873  continue;
8874 
8875  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || consdata->isconcave) &&
8876  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || consdata->isconvex ) )
8877  continue;
8878  SCIPdebugMsg(scip, "cons %s violation: %g %g convex: %u %u\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->isconvex, consdata->isconcave);
8879 
8880  for( j = 0; j < consdata->nquadvars; ++j )
8881  {
8882  quadvarterm = &consdata->quadvarterms[j];
8883  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef < 0) ||
8884  (SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef > 0) ||
8885  quadvarterm->nadjbilin > 0 )
8886  {
8887  x = quadvarterm->var;
8888  xlb = SCIPvarGetLbLocal(x);
8889  xub = SCIPvarGetUbLocal(x);
8890 
8891  if( quadvarterm->nadjbilin == 0 )
8892  {
8893  xval = SCIPgetSolVal(scip, sol, x);
8894 
8895  /* if variable is at bounds and only in a nonconvex square term, then no need to branch, since secant is exact there */
8896  if( SCIPisLE(scip, xval, xlb) || SCIPisGE(scip, xval, xub) )
8897  continue;
8898  }
8899 
8900  if( SCIPisRelEQ(scip, xlb, xub) )
8901  {
8902  SCIPdebugMsg(scip, "ignore fixed variable <%s>[%g, %g], diff %g\n", SCIPvarGetName(x), xlb, xub, xub-xlb);
8903  continue;
8904  }
8905 
8906  SCIP_CALL( SCIPaddExternBranchCand(scip, x, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
8907  ++*nnotify;
8908  }
8909  }
8910  }
8911 
8912  SCIPdebugMsg(scip, "registered %d branching candidates\n", *nnotify);
8913 
8914  return SCIP_OKAY;
8915 }
8916 
8917 /** registers branching candidates according to centrality rule
8918  *
8919  * That is, registers all variables appearing in nonconvex terms^1 with a score that is given by the distance of the
8920  * variable value from its bounds. This rule should not make sense, as the distance to the bounds is also (often) considered
8921  * by the branching rule later on.
8922  *
8923  * 1) We mean all quadratic variables that appear either in a nonconvex square term or in a bilinear term, if the constraint
8924  * itself is nonconvex. (and this under the assumption that the rhs is violated; for violated lhs, swap terms)
8925  */
8926 static
8928  SCIP* scip, /**< SCIP data structure */
8929  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8930  SCIP_CONS** conss, /**< constraints to check */
8931  int nconss, /**< number of constraints to check */
8932  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8933  int* nnotify /**< counter for number of notifications performed */
8934  )
8935 {
8936  SCIP_CONSDATA* consdata;
8937  SCIP_QUADVARTERM* quadvarterm;
8938  int c;
8939  int j;
8940  SCIP_VAR* x;
8941  SCIP_Real xlb;
8942  SCIP_Real xub;
8943  SCIP_Real xval;
8944  SCIP_Real score;
8945 
8946  assert(scip != NULL);
8947  assert(conshdlr != NULL);
8948  assert(conss != NULL || nconss == 0);
8949 
8950  *nnotify = 0;
8951 
8952  for( c = 0; c < nconss; ++c )
8953  {
8954  assert(conss != NULL);
8955  consdata = SCIPconsGetData(conss[c]);
8956  assert(consdata != NULL);
8957 
8958  if( !consdata->nquadvars )
8959  continue;
8960 
8961  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || consdata->isconcave) &&
8962  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || consdata->isconvex ) )
8963  continue;
8964  SCIPdebugMsg(scip, "cons %s violation: %g %g convex: %u %u\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->isconvex, consdata->isconcave);
8965 
8966  for( j = 0; j < consdata->nquadvars; ++j )
8967  {
8968  quadvarterm = &consdata->quadvarterms[j];
8969  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef < 0) ||
8970  (SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef > 0) ||
8971  quadvarterm->nadjbilin > 0 )
8972  {
8973  x = quadvarterm->var;
8974  xlb = SCIPvarGetLbLocal(x);
8975  xub = SCIPvarGetUbLocal(x);
8976 
8977  if( SCIPisRelEQ(scip, xlb, xub) )
8978  {
8979  SCIPdebugMsg(scip, "ignore fixed variable <%s>[%g, %g], diff %g\n", SCIPvarGetName(x), xlb, xub, xub-xlb);
8980  continue;
8981  }
8982 
8983  xval = SCIPgetSolVal(scip, sol, x);
8984  xval = MAX(xlb, MIN(xub, xval));
8985 
8986  /* compute relative difference of xval to each of its bounds
8987  * and scale such that if xval were in the middle, we get a score of 1
8988  * and if xval is on one its bounds, the score is 0
8989  */
8990  if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) )
8991  {
8992  if( (!SCIPisInfinity(scip, -xlb) && SCIPisEQ(scip, xval, xlb)) || (!SCIPisInfinity(scip, xub) && SCIPisEQ(scip, xval, xub)) )
8993  score = 0.0;
8994  else
8995  score = 1.0;
8996  }
8997  else
8998  {
8999  score = 4.0 * (xval - xlb) * (xub - xval) / ((xub - xlb) * (xub - xlb));
9000  }
9001 
9002  SCIP_CALL( SCIPaddExternBranchCand(scip, x, score, SCIP_INVALID) );
9003  ++*nnotify;
9004  }
9005  }
9006  }
9007 
9008  SCIPdebugMsg(scip, "registered %d branching candidates\n", *nnotify);
9009 
9010  return SCIP_OKAY;
9011 }
9012 
9013 /** registers branching candidates */
9014 static
9016  SCIP* scip, /**< SCIP data structure */
9017  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9018  SCIP_CONS** conss, /**< constraints to check */
9019  int nconss, /**< number of constraints to check */
9020  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
9021  int* nnotify /**< counter for number of notifications performed */
9022  )
9023 {
9024  SCIP_CONSHDLRDATA* conshdlrdata;
9025 
9026  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9027  assert(conshdlrdata != NULL);
9028 
9029  switch( conshdlrdata->branchscoring )
9030  {
9031  case 'g' :
9032  SCIP_CALL( registerBranchingCandidatesGap(scip, conshdlr, conss, nconss, sol, nnotify) );
9033  break;
9034 
9035  case 'v' :
9036  SCIP_CALL( registerBranchingCandidatesViolation(scip, conshdlr, conss, nconss, sol, nnotify) );
9037  break;
9038 
9039  case 'c' :
9040  SCIP_CALL( registerBranchingCandidatesCentrality(scip, conshdlr, conss, nconss, sol, nnotify) );
9041  break;
9042 
9043  default :
9044  SCIPerrorMessage("invalid branchscoring selection");
9045  SCIPABORT();
9046  return SCIP_ERROR; /*lint !e527*/
9047  }
9048 
9049  return SCIP_OKAY;
9050 }
9051 
9052 
9053 /** registers a quadratic variable from a violated constraint as branching candidate that has a large absolute value in the (LP) relaxation */
9054 static
9056  SCIP* scip, /**< SCIP data structure */
9057  SCIP_CONS** conss, /**< constraints */
9058  int nconss, /**< number of constraints */
9059  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
9060  SCIP_VAR** brvar /**< buffer to store branching variable */
9061  )
9062 {
9063  SCIP_CONSDATA* consdata;
9064  SCIP_Real val;
9065  SCIP_Real brvarval;
9066  int i;
9067  int c;
9068 
9069  assert(scip != NULL);
9070  assert(conss != NULL || nconss == 0);
9071 
9072  *brvar = NULL;
9073  brvarval = -1.0;
9074 
9075  for( c = 0; c < nconss; ++c )
9076  {
9077  assert(conss != NULL);
9078  consdata = SCIPconsGetData(conss[c]);
9079  assert(consdata != NULL);
9080 
9081  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
9082  continue;
9083 
9084  for( i = 0; i < consdata->nquadvars; ++i )
9085  {
9086  /* do not propose fixed variables */
9087  if( SCIPisRelEQ(scip, SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
9088  continue;
9089  val = SCIPgetSolVal(scip, sol, consdata->quadvarterms[i].var);
9090  if( ABS(val) > brvarval )
9091  {
9092  brvarval = ABS(val);
9093  *brvar = consdata->quadvarterms[i].var;
9094  }
9095  }
9096  }
9097 
9098  if( *brvar != NULL )
9099  {
9100  SCIP_CALL( SCIPaddExternBranchCand(scip, *brvar, brvarval, SCIP_INVALID) );
9101  }
9102 
9103  return SCIP_OKAY;
9104 }
9105 
9106 /** replaces violated quadratic constraints where all quadratic variables are fixed by linear constraints */
9107 static
9109  SCIP* scip, /**< SCIP data structure */
9110  SCIP_CONS** conss, /**< constraints */
9111  int nconss, /**< number of constraints */
9112  SCIP_Bool* addedcons, /**< buffer to store whether a linear constraint was added */
9113  SCIP_Bool* reduceddom, /**< whether a domain has been reduced */
9114  SCIP_Bool* infeasible /**< whether we detected infeasibility */
9115  )
9116 {
9117  SCIP_CONS* cons;
9118  SCIP_CONSDATA* consdata;
9119  SCIP_RESULT checkresult;
9120  SCIP_Real constant;
9121  SCIP_Real val1;
9122  SCIP_Real val2;
9123  int i;
9124  int c;
9125 
9126  assert(scip != NULL);
9127  assert(conss != NULL || nconss == 0);
9128  assert(addedcons != NULL);
9129  assert(reduceddom != NULL);
9130  assert(infeasible != NULL);
9131 
9132  *addedcons = FALSE;
9133  *reduceddom = FALSE;
9134  *infeasible = FALSE;
9135 
9136  for( c = 0; c < nconss; ++c )
9137  {
9138  assert(conss != NULL);
9139  consdata = SCIPconsGetData(conss[c]);
9140  assert(consdata != NULL);
9141 
9142  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
9143  continue;
9144 
9145  constant = 0.0;
9146 
9147  for( i = 0; i < consdata->nquadvars; ++i )
9148  {
9149  /* variables should be fixed if constraint is violated */
9150  assert(SCIPisRelEQ(scip, SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var)));
9151 
9152  val1 = (SCIPvarGetUbLocal(consdata->quadvarterms[i].var) + SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) / 2.0;
9153  constant += (consdata->quadvarterms[i].lincoef + consdata->quadvarterms[i].sqrcoef * val1) * val1;
9154  }
9155 
9156  for( i = 0; i < consdata->nbilinterms; ++i )
9157  {
9158  val1 = (SCIPvarGetUbLocal(consdata->bilinterms[i].var1) + SCIPvarGetLbLocal(consdata->bilinterms[i].var1)) / 2.0;
9159  val2 = (SCIPvarGetUbLocal(consdata->bilinterms[i].var2) + SCIPvarGetLbLocal(consdata->bilinterms[i].var2)) / 2.0;
9160  constant += consdata->bilinterms[i].coef * val1 * val2;
9161  }
9162 
9163  /* check if we have a bound change */
9164  if ( consdata->nlinvars == 1 )
9165  {
9166  SCIP_Bool tightened;
9167  SCIP_Real coef;
9168  SCIP_Real lhs;
9169  SCIP_Real rhs;
9170 
9171  coef = *consdata->lincoefs;
9172 
9173  /* compute lhs/rhs */
9174  if ( SCIPisInfinity(scip, -consdata->lhs) )
9175  lhs = -SCIPinfinity(scip);
9176  else
9177  lhs = consdata->lhs - constant;
9178 
9179  if ( SCIPisInfinity(scip, consdata->rhs) )
9180  rhs = SCIPinfinity(scip);
9181  else
9182  rhs = consdata->rhs - constant;
9183 
9184  SCIPdebugMsg(scip, "Linear constraint with one variable: %g <= %g <%s> <= %g\n", lhs, coef, SCIPvarGetName(*consdata->linvars), rhs);
9185 
9186  /* possibly correct lhs/rhs */
9187  assert( ! SCIPisZero(scip, coef) );
9188  if ( coef >= 0.0 )
9189  {
9190  if ( ! SCIPisInfinity(scip, -lhs) )
9191  lhs /= coef;
9192  if ( ! SCIPisInfinity(scip, rhs) )
9193  rhs /= coef;
9194  }
9195  else
9196  {
9197  SCIP_Real h;
9198  h = rhs;
9199  if ( ! SCIPisInfinity(scip, -lhs) )
9200  rhs = lhs/coef;
9201  else
9202  rhs = SCIPinfinity(scip);
9203 
9204  if ( ! SCIPisInfinity(scip, h) )
9205  lhs = h/coef;
9206  else
9207  lhs = -SCIPinfinity(scip);
9208  }
9209  SCIPdebugMsg(scip, "Linear constraint is a bound: %g <= <%s> <= %g\n", lhs, SCIPvarGetName(*consdata->linvars), rhs);
9210 
9211  if( SCIPisInfinity(scip, -rhs) || SCIPisInfinity(scip, lhs) )
9212  {
9213  SCIPdebugMsg(scip, "node will marked as infeasible since lb/ub of %s is +/-infinity\n",
9214  SCIPvarGetName(consdata->linvars[0]));
9215 
9216  *infeasible = TRUE;
9217  return SCIP_OKAY;
9218  }
9219 
9220  if ( ! SCIPisInfinity(scip, -lhs) )
9221  {
9222  SCIP_CALL( SCIPtightenVarLb(scip, *consdata->linvars, lhs, TRUE, infeasible, &tightened) );
9223  if ( *infeasible )
9224  {
9225  SCIPdebugMsg(scip, "Lower bound leads to infeasibility.\n");
9226  return SCIP_OKAY;
9227  }
9228  if ( tightened )
9229  {
9230  SCIPdebugMsg(scip, "Lower boundx changed.\n");
9231  *reduceddom = TRUE;
9232  return SCIP_OKAY;
9233  }
9234  }
9235 
9236  if ( ! SCIPisInfinity(scip, rhs) )
9237  {
9238  SCIP_CALL( SCIPtightenVarUb(scip, *consdata->linvars, rhs, TRUE, infeasible, &tightened) );
9239  if ( *infeasible )
9240  {
9241  SCIPdebugMsg(scip, "Upper bound leads to infeasibility.\n");
9242  return SCIP_OKAY;
9243  }
9244  if ( tightened )
9245  {
9246  SCIPdebugMsg(scip, "Upper bound changed.\n");
9247  *reduceddom = TRUE;
9248  return SCIP_OKAY;
9249  }
9250  }
9251  }
9252  else
9253  {
9254  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, SCIPconsGetName(conss[c]),
9255  consdata->nlinvars, consdata->linvars, consdata->lincoefs,
9256  (SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : (consdata->lhs - constant)),
9257  (SCIPisInfinity(scip, consdata->rhs) ? SCIPinfinity(scip) : (consdata->rhs - constant)),
9258  SCIPconsIsInitial(conss[c]), SCIPconsIsSeparated(conss[c]), SCIPconsIsEnforced(conss[c]),
9259  SCIPconsIsChecked(conss[c]), SCIPconsIsPropagated(conss[c]), TRUE,
9260  SCIPconsIsModifiable(conss[c]), SCIPconsIsDynamic(conss[c]), SCIPconsIsRemovable(conss[c]),
9261  SCIPconsIsStickingAtNode(conss[c])) );
9262 
9263  SCIPdebugMsg(scip, "replace quadratic constraint <%s> by linear constraint after all quadratic vars have been fixed\n", SCIPconsGetName(conss[c]) );
9264  SCIPdebugPrintCons(scip, cons, NULL);
9265 
9266  SCIP_CALL( SCIPcheckCons(scip, cons, NULL, FALSE, FALSE, FALSE, &checkresult) );
9267 
9268  if( checkresult != SCIP_INFEASIBLE && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
9269  {
9270  SCIPdebugMsg(scip, "linear constraint is feasible and LP optimal, thus do not add\n");
9271  }
9272  else
9273  {
9274  SCIP_CALL( SCIPaddConsLocal(scip, cons, NULL) );
9275  *addedcons = TRUE;
9276  }
9277  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9278  }
9279  SCIP_CALL( SCIPdelConsLocal(scip, conss[c]) );
9280  }
9281 
9282  return SCIP_OKAY;
9283 }
9284 
9285 /** tightens a lower bound on a variable and checks the result */
9286 static
9288  SCIP* scip, /**< SCIP data structure */
9289  SCIP_CONS* cons, /**< constraint where we currently propagate */
9290  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
9291  SCIP_VAR* var, /**< variable which domain we might reduce */
9292  SCIP_Real bnd, /**< new lower bound for variable */
9293  SCIP_RESULT* result, /**< result to update if there was a tightening or cutoff */
9294  int* nchgbds /**< counter to increase if a bound was tightened */
9295  )
9296 {
9297  SCIP_Bool infeas;
9298  SCIP_Bool tightened;
9299 
9300  assert(scip != NULL);
9301  assert(cons != NULL);
9302  assert(intervalinfty > 0.0);
9303  assert(bnd > -intervalinfty);
9304  assert(var != NULL);
9305  assert(result != NULL);
9306  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
9307  assert(nchgbds != NULL);
9308 
9309  /* new bound is no improvement */
9310  if( SCIPisHugeValue(scip, -bnd) || SCIPisLE(scip, bnd, SCIPvarGetLbLocal(var)) )
9311  return SCIP_OKAY;
9312 
9313  if( SCIPisInfinity(scip, bnd) )
9314  { /* domain will be outside [-infty, +infty] -> declare node infeasible */
9315  *result = SCIP_CUTOFF;
9316  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9317  return SCIP_OKAY;
9318  }
9319 
9320  /* new lower bound is very low (between -intervalinfty and -SCIPinfinity()) */
9321  if( SCIPisInfinity(scip, -bnd) )
9322  return SCIP_OKAY;
9323 
9324  bnd = SCIPadjustedVarLb(scip, var, bnd);
9325  SCIP_CALL( SCIPtightenVarLb(scip, var, bnd, FALSE, &infeas, &tightened) );
9326  if( infeas )
9327  {
9328  SCIPdebugMsg(scip, "%s found constraint <%s> infeasible due to tightened lower bound %g for variable <%s>\n",
9329  SCIPinProbing(scip) ? "in probing" : "", SCIPconsGetName(cons), bnd, SCIPvarGetName(var));
9330  *result = SCIP_CUTOFF;
9331  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9332  return SCIP_OKAY;
9333  }
9334  if( tightened )
9335  {
9336  SCIPdebugMsg(scip, "%s tightened lower bound of variable <%s> in constraint <%s> to %g\n",
9337  SCIPinProbing(scip) ? "in probing" : "", SCIPvarGetName(var), SCIPconsGetName(cons), bnd);
9338  ++*nchgbds;
9339  *result = SCIP_REDUCEDDOM;
9340  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9341  }
9342 
9343  return SCIP_OKAY;
9344 }
9345 
9346 /** tightens an upper bound on a variable and checks the result */
9347 static
9349  SCIP* scip, /**< SCIP data structure */
9350  SCIP_CONS* cons, /**< constraint where we currently propagate */
9351  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
9352  SCIP_VAR* var, /**< variable which domain we might reduce */
9353  SCIP_Real bnd, /**< new upper bound for variable */
9354  SCIP_RESULT* result, /**< result to update if there was a tightening or cutoff */
9355  int* nchgbds /**< counter to increase if a bound was tightened */
9356  )
9357 {
9358  SCIP_Bool infeas;
9359  SCIP_Bool tightened;
9360 
9361  assert(scip != NULL);
9362  assert(cons != NULL);
9363  assert(intervalinfty > 0.0);
9364  assert(bnd < intervalinfty);
9365  assert(var != NULL);
9366  assert(result != NULL);
9367  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
9368  assert(nchgbds != NULL);
9369 
9370  /* new bound is no improvement */
9371  if( SCIPisHugeValue(scip, bnd) || SCIPisGE(scip, bnd, SCIPvarGetUbLocal(var)) )
9372  return SCIP_OKAY;
9373 
9374  if( SCIPisInfinity(scip, -bnd) )
9375  { /* domain will be outside [-infty, +infty] -> declare node infeasible */
9376  *result = SCIP_CUTOFF;
9377  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9378  return SCIP_OKAY;
9379  }
9380 
9381  /* new upper bound is very high (between SCIPinfinity() and intervalinfty) */
9382  if( SCIPisInfinity(scip, bnd) )
9383  return SCIP_OKAY;
9384 
9385  bnd = SCIPadjustedVarUb(scip, var, bnd);
9386  SCIP_CALL( SCIPtightenVarUb(scip, var, bnd, FALSE, &infeas, &tightened) );
9387  if( infeas )
9388  {
9389  SCIPdebugMsg(scip, "%s found constraint <%s> infeasible due to tightened upper bound %g for variable <%s>\n",
9390  SCIPinProbing(scip) ? "in probing" : "", SCIPconsGetName(cons), bnd, SCIPvarGetName(var));
9391  *result = SCIP_CUTOFF;
9392  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9393  return SCIP_OKAY;
9394  }
9395  if( tightened )
9396  {
9397  SCIPdebugMsg(scip, "%s tightened upper bound of variable <%s> in constraint <%s> to %g\n",
9398  SCIPinProbing(scip) ? "in probing" : "", SCIPvarGetName(var), SCIPconsGetName(cons), bnd);
9399  ++*nchgbds;
9400  *result = SCIP_REDUCEDDOM;
9401  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9402  }
9403 
9404  return SCIP_OKAY;
9405 }
9406 
9407 /** 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 */
9408 static
9410  SCIP* scip, /**< SCIP data structure */
9411  SCIP_CONS* cons, /**< constraint where we currently propagate */
9412  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
9413  SCIP_VAR* var, /**< variable which bounds with might tighten */
9414  SCIP_Real a, /**< coefficient in square term */
9415  SCIP_INTERVAL b, /**< coefficient in linear term */
9416  SCIP_INTERVAL rhs, /**< right hand side of quadratic equation */
9417  SCIP_RESULT* result, /**< result of propagation */
9418  int* nchgbds /**< buffer where to add number of tightened bounds */
9419  )
9420 {
9421  SCIP_INTERVAL newrange;
9422 
9423  assert(scip != NULL);
9424  assert(cons != NULL);
9425  assert(var != NULL);
9426  assert(result != NULL);
9427  assert(nchgbds != NULL);
9428 
9429  /* compute solution of a*x^2 + b*x \in rhs */
9430  if( a == 0.0 && SCIPintervalGetInf(b) == 0.0 && SCIPintervalGetSup(b) == 0.0 )
9431  {
9432  /* relatively easy case: 0.0 \in rhs, thus check if infeasible or just redundant */
9433  if( SCIPintervalGetInf(rhs) > 0.0 || SCIPintervalGetSup(rhs) < 0.0 )
9434  {
9435  SCIPdebugMsg(scip, "found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(var));
9436  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9437  *result = SCIP_CUTOFF;
9438  }
9439  return SCIP_OKAY;
9440  }
9441  else if( SCIPvarGetLbLocal(var) >= 0.0 )
9442  {
9443  SCIP_INTERVAL a_;
9444 
9445  /* need only positive solutions */
9446  SCIPintervalSet(&a_, a);
9447  SCIPintervalSolveUnivariateQuadExpressionPositive(intervalinfty, &newrange, a_, b, rhs);
9448  }
9449  else if( SCIPvarGetUbLocal(var) <= 0.0 )
9450  {
9451  /* need only negative solutions */
9452  SCIP_INTERVAL a_;
9453  SCIP_INTERVAL tmp;
9454  SCIPintervalSet(&a_, a);
9456  SCIPintervalSolveUnivariateQuadExpressionPositive(intervalinfty, &tmp, a_, tmp, rhs);
9457  if( SCIPintervalIsEmpty(intervalinfty, tmp) )
9458  {
9459  SCIPdebugMsg(scip, "found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(var));
9460  *result = SCIP_CUTOFF;
9461  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9462  return SCIP_OKAY;
9463  }
9465  }
9466  else
9467  {
9468  /* need both positive and negative solution */
9469  SCIP_INTERVAL a_;
9470  SCIPintervalSet(&a_, a);
9471  SCIPintervalSolveUnivariateQuadExpression(intervalinfty, &newrange, a_, b, rhs);
9472  }
9473 
9474  /* SCIPdebugMsg(scip, "%g x^2 + [%g, %g] x in [%g, %g] -> [%g, %g]\n", a, b.inf, b.sup, rhs.inf, rhs.sup, newrange.inf, newrange.sup); */
9475 
9476  if( SCIPisInfinity(scip, SCIPintervalGetInf(newrange)) || SCIPisInfinity(scip, -SCIPintervalGetSup(newrange)) )
9477  {
9478  /* domain outside [-infty, +infty] -> declare node infeasible */
9479  SCIPdebugMsg(scip, "found <%s> infeasible because propagated domain of quadratic variable <%s> is outside of (-infty, +infty)\n",
9480  SCIPconsGetName(cons), SCIPvarGetName(var));
9481  *result = SCIP_CUTOFF;
9482  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9483  return SCIP_OKAY;
9484  }
9485 
9486  if( SCIPintervalIsEmpty(intervalinfty, newrange) )
9487  {
9488  SCIPdebugMsg(scip, "found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(var));
9489  *result = SCIP_CUTOFF;
9490  return SCIP_OKAY;
9491  }
9492 
9493  if( !SCIPisInfinity(scip, -SCIPintervalGetInf(newrange)) )
9494  {
9495  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, SCIPintervalGetInf(newrange), result, nchgbds) );
9496  if( *result == SCIP_CUTOFF )
9497  return SCIP_OKAY;
9498  }
9499 
9500  if( !SCIPisInfinity(scip, SCIPintervalGetSup(newrange)) )
9501  {
9502  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, SCIPintervalGetSup(newrange), result, nchgbds) );
9503  if( *result == SCIP_CUTOFF )
9504  return SCIP_OKAY;
9505  }
9506 
9507  return SCIP_OKAY;
9508 }
9509 
9510 /* The new version below computes potentially tighter bounds, but also always adds a small safety area since it is not implemented roundingsafe.
9511  * This may be a reason why it gives worse results on one of two instances.
9512  * Further, I have only very few instances where one can expect a difference.
9513  */
9514 #ifndef PROPBILINNEW
9515 /** tries to deduce domain reductions for x in xsqrcoef x^2 + xlincoef x + ysqrcoef y^2 + ylincoef y + bilincoef x y \\in rhs
9516  *
9517  * @note Domain reductions for y are not deduced.
9518  */
9519 static
9521  SCIP* scip, /**< SCIP data structure */
9522  SCIP_CONS* cons, /**< the constraint, where the bilinear term belongs to */
9523  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
9524  SCIP_VAR* x, /**< first variable */
9525  SCIP_Real xsqrcoef, /**< square coefficient of x */
9526  SCIP_Real xlincoef, /**< linear coefficient of x */
9527  SCIP_VAR* y, /**< second variable */
9528  SCIP_Real ysqrcoef, /**< square coefficient of y */
9529  SCIP_Real ylincoef, /**< linear coefficient of y */
9530  SCIP_Real bilincoef, /**< bilinear coefficient of x*y */
9531  SCIP_INTERVAL rhs, /**< right hand side of quadratic equation */
9532  SCIP_RESULT* result, /**< pointer to store result of domain propagation */
9533  int* nchgbds /**< counter to increment if domain reductions are found */
9534  )
9535 {
9536  SCIP_INTERVAL myrhs;
9537  SCIP_INTERVAL varbnds;
9538  SCIP_INTERVAL lincoef;
9539 
9540  assert(scip != NULL);
9541  assert(cons != NULL);
9542  assert(x != NULL);
9543  assert(y != NULL);
9544  assert(x != y);
9545  assert(result != NULL);
9546  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
9547  assert(nchgbds != NULL);
9548  assert(bilincoef != 0.0);
9549 
9550  if( SCIPintervalIsEntire(intervalinfty, rhs) )
9551  return SCIP_OKAY;
9552 
9553  /* try to find domain reductions for x */
9555 
9556  /* put ysqrcoef*y^2 + ylincoef * y into rhs */
9557  if( SCIPintervalGetSup(rhs) >= intervalinfty )
9558  {
9559  /* if rhs is unbounded by above, it is sufficient to get an upper bound on ysqrcoef*y^2 + ylincoef * y */
9560  SCIP_ROUNDMODE roundmode;
9561  SCIP_Real tmp;
9562 
9563  SCIPintervalSet(&lincoef, ylincoef);
9564  tmp = SCIPintervalQuadUpperBound(intervalinfty, ysqrcoef, lincoef, varbnds);
9565  roundmode = SCIPintervalGetRoundingMode();
9567  SCIPintervalSetBounds(&myrhs, SCIPintervalGetInf(rhs) - tmp, intervalinfty);
9568  SCIPintervalSetRoundingMode(roundmode);
9569  }
9570  else if( SCIPintervalGetInf(rhs) <= -intervalinfty )
9571  {
9572  /* if rhs is unbounded by below, it is sufficient to get a lower bound on ysqrcoef*y^2 + ylincoef * y */
9573  SCIP_ROUNDMODE roundmode;
9574  SCIP_Real tmp;
9575 
9576  SCIPintervalSet(&lincoef, -ylincoef);
9577  tmp = -SCIPintervalQuadUpperBound(intervalinfty, -ysqrcoef, lincoef, varbnds);
9578  roundmode = SCIPintervalGetRoundingMode();
9580  SCIPintervalSetBounds(&myrhs, -intervalinfty, SCIPintervalGetSup(rhs) - tmp);
9581  SCIPintervalSetRoundingMode(roundmode);
9582  }
9583  else
9584  {
9585  /* if rhs is bounded, we need both bounds on ysqrcoef*y^2 + ylincoef * y */
9586  SCIP_INTERVAL tmp;
9587 
9588  SCIPintervalSet(&lincoef, ylincoef);
9589  SCIPintervalQuad(intervalinfty, &tmp, ysqrcoef, lincoef, varbnds);
9590  SCIPintervalSub(intervalinfty, &myrhs, rhs, tmp);
9591  }
9592 
9593  /* create equation xsqrcoef * x^2 + (xlincoef + bilincoef * [ylb, yub]) * x \in myrhs */
9594  SCIPintervalMulScalar(intervalinfty, &lincoef, varbnds, bilincoef);
9595  SCIPintervalAddScalar(intervalinfty, &lincoef, lincoef, xlincoef);
9596 
9597  /* propagate bounds on x */
9598  SCIP_CALL( propagateBoundsQuadVar(scip, cons, intervalinfty, x, xsqrcoef, lincoef, myrhs, result, nchgbds) );
9599 
9600  return SCIP_OKAY;
9601 }
9602 #else
9603 /** tries to deduce domain reductions for x in xsqrcoef x^2 + xlincoef x + ysqrcoef y^2 + ylincoef y + bilincoef x y \\in rhs
9604  *
9605  * @note Domain reductions for y are not deduced.
9606  */
9607 static
9609  SCIP* scip, /**< SCIP data structure */
9610  SCIP_CONS* cons, /**< the constraint, where the bilinear term belongs to */
9611  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
9612  SCIP_VAR* x, /**< first variable */
9613  SCIP_Real xsqrcoef, /**< square coefficient of x */
9614  SCIP_Real xlincoef, /**< linear coefficient of x */
9615  SCIP_VAR* y, /**< second variable */
9616  SCIP_Real ysqrcoef, /**< square coefficient of y */
9617  SCIP_Real ylincoef, /**< linear coefficient of y */
9618  SCIP_Real bilincoef, /**< bilinear coefficient of x*y */
9619  SCIP_INTERVAL rhs, /**< right hand side of quadratic equation */
9620  SCIP_RESULT* result, /**< pointer to store result of domain propagation */
9621  int* nchgbds /**< counter to increment if domain reductions are found */
9622  )
9623 {
9624  SCIP_INTERVAL xbnds;
9625  SCIP_INTERVAL ybnds;
9626 
9627  assert(scip != NULL);
9628  assert(cons != NULL);
9629  assert(x != NULL);
9630  assert(y != NULL);
9631  assert(x != y);
9632  assert(result != NULL);
9633  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
9634  assert(nchgbds != NULL);
9635  assert(bilincoef != 0.0);
9636 
9637  if( SCIPintervalIsEntire(intervalinfty, rhs) )
9638  return SCIP_OKAY;
9639 
9640  SCIPintervalSetBounds(&xbnds,
9641  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(x), SCIPvarGetUbLocal(x))), /*lint !e666*/
9642  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(x), SCIPvarGetUbLocal(x)))); /*lint !e666*/
9643  SCIPintervalSetBounds(&ybnds,
9644  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(y), SCIPvarGetUbLocal(y))), /*lint !e666*/
9645  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(y), SCIPvarGetUbLocal(y)))); /*lint !e666*/
9646 
9647  /* try to find domain reductions for x */
9648  SCIPintervalSolveBivariateQuadExpressionAllScalar(intervalinfty, &xbnds, xsqrcoef, ysqrcoef, bilincoef, xlincoef, ylincoef, rhs, xbnds, ybnds);
9649 
9650  if( SCIPintervalIsEmpty(intervalinfty, xbnds) )
9651  {
9652  SCIPdebugMsg(scip, "found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(x));
9653  *result = SCIP_CUTOFF;
9654  return SCIP_OKAY;
9655  }
9656 
9657  if( !SCIPisInfinity(scip, -SCIPintervalGetInf(xbnds)) )
9658  {
9659  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, x, SCIPintervalGetInf(xbnds), result, nchgbds) );
9660  if( *result == SCIP_CUTOFF )
9661  return SCIP_OKAY;
9662  }
9663 
9664  if( !SCIPisInfinity(scip, SCIPintervalGetSup(xbnds)) )
9665  {
9666  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, x, SCIPintervalGetSup(xbnds), result, nchgbds) );
9667  if( *result == SCIP_CUTOFF )
9668  return SCIP_OKAY;
9669  }
9670 
9671  return SCIP_OKAY;
9672 }
9673 #endif
9674 
9675 /** computes the minimal and maximal activity for the quadratic part in a constraint data
9676  *
9677  * Only sums up terms that contribute finite values.
9678  * Gives the number of terms that contribute infinite values.
9679  * Only computes those activities where the corresponding side of the constraint is finite.
9680  */
9681 static
9683  SCIP* scip, /**< SCIP data structure */
9684  SCIP_CONSDATA* consdata, /**< constraint data */
9685  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
9686  SCIP_Real* minquadactivity, /**< minimal activity of quadratic variable terms where only terms with finite minimal activity contribute */
9687  SCIP_Real* maxquadactivity, /**< maximal activity of quadratic variable terms where only terms with finite maximal activity contribute */
9688  int* minactivityinf, /**< number of quadratic variables that contribute -infinity to minimal activity */
9689  int* maxactivityinf, /**< number of quadratic variables that contribute +infinity to maximal activity */
9690  SCIP_INTERVAL* quadactcontr /**< contribution of each quadratic variables to quadactivity */
9691  )
9692 { /*lint --e{666}*/
9693  SCIP_ROUNDMODE prevroundmode;
9694  int i;
9695  int j;
9696  int k;
9697  SCIP_INTERVAL tmp;
9698  SCIP_Real bnd;
9699  SCIP_INTERVAL xrng;
9700  SCIP_INTERVAL lincoef;
9701 
9702  assert(scip != NULL);
9703  assert(consdata != NULL);
9704  assert(minquadactivity != NULL);
9705  assert(maxquadactivity != NULL);
9706  assert(minactivityinf != NULL);
9707  assert(maxactivityinf != NULL);
9708  assert(quadactcontr != NULL);
9709 
9710  /* if lhs is -infinite, then we do not compute a maximal activity, so we set it to infinity
9711  * if rhs is infinite, then we do not compute a minimal activity, so we set it to -infinity
9712  */
9713  *minquadactivity = SCIPisInfinity(scip, consdata->rhs) ? -intervalinfty : 0.0;
9714  *maxquadactivity = SCIPisInfinity(scip, -consdata->lhs) ? intervalinfty : 0.0;
9715 
9716  *minactivityinf = 0;
9717  *maxactivityinf = 0;
9718 
9719  if( consdata->nquadvars == 0 )
9720  {
9721  SCIPintervalSet(&consdata->quadactivitybounds, 0.0);
9722  return;
9723  }
9724 
9725  for( i = 0; i < consdata->nquadvars; ++i )
9726  {
9727  /* there should be no quadratic variables fixed at -/+ infinity due to our locks */
9728  assert(!SCIPisInfinity(scip, SCIPvarGetLbLocal(consdata->quadvarterms[i].var)));
9729  assert(!SCIPisInfinity(scip, -SCIPvarGetUbLocal(consdata->quadvarterms[i].var)));
9730 
9731  SCIPintervalSetBounds(&quadactcontr[i], -intervalinfty, intervalinfty);
9732 
9733  SCIPintervalSetBounds(&xrng,
9734  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var))),
9735  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var))));
9736 
9737  SCIPintervalSet(&lincoef, consdata->quadvarterms[i].lincoef);
9738  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
9739  {
9740  k = consdata->quadvarterms[i].adjbilin[j];
9741  if( consdata->bilinterms[k].var1 != consdata->quadvarterms[i].var )
9742  continue; /* handle this term later */
9743 
9744  SCIPintervalSetBounds(&tmp,
9745  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
9746  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
9747  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
9748  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
9749  }
9750 
9751  if( !SCIPisInfinity(scip, -consdata->lhs) )
9752  {
9753  /* compute maximal activity only if there is a finite left hand side */
9754  bnd = SCIPintervalQuadUpperBound(intervalinfty, consdata->quadvarterms[i].sqrcoef, lincoef, xrng);
9755  if( SCIPisInfinity(scip, bnd) )
9756  {
9757  ++*maxactivityinf;
9758  }
9759  else if( SCIPisInfinity(scip, -bnd) )
9760  {
9761  /* if maximal activity is below value for -infinity, let's take -1e10 as upper bound on maximal activity
9762  * @todo Something better?
9763  */
9764  bnd = -sqrt(SCIPinfinity(scip));
9765  *maxquadactivity += bnd;
9766  quadactcontr[i].sup = bnd;
9767  }
9768  else
9769  {
9770  prevroundmode = SCIPintervalGetRoundingMode();
9772  *maxquadactivity += bnd;
9773  SCIPintervalSetRoundingMode(prevroundmode);
9774  quadactcontr[i].sup = bnd;
9775  }
9776  }
9777 
9778  if( !SCIPisInfinity(scip, consdata->rhs) )
9779  {
9780  /* compute minimal activity only if there is a finite right hand side */
9781  SCIPintervalSetBounds(&lincoef, -SCIPintervalGetSup(lincoef), -SCIPintervalGetInf(lincoef));
9782  bnd = -SCIPintervalQuadUpperBound(intervalinfty, -consdata->quadvarterms[i].sqrcoef, lincoef, xrng);
9783 
9784  if( SCIPisInfinity(scip, -bnd) )
9785  {
9786  ++*minactivityinf;
9787  }
9788  else if( SCIPisInfinity(scip, bnd) )
9789  {
9790  /* if minimal activity is above value for infinity, let's take 1e10 as lower bound on minimal activity
9791  * @todo Something better?
9792  */
9793  bnd = sqrt(SCIPinfinity(scip));
9794  *minquadactivity += bnd;
9795  quadactcontr[i].inf = bnd;
9796  }
9797  else
9798  {
9799  prevroundmode = SCIPintervalGetRoundingMode();
9801  *minquadactivity += bnd;
9802  SCIPintervalSetRoundingMode(prevroundmode);
9803  quadactcontr[i].inf = bnd;
9804  }
9805  }
9806 
9807  }
9808 
9809  SCIPintervalSetBounds(&consdata->quadactivitybounds,
9810  (*minactivityinf > 0 ? -intervalinfty : *minquadactivity),
9811  (*maxactivityinf > 0 ? intervalinfty : *maxquadactivity));
9812  assert(!SCIPintervalIsEmpty(intervalinfty, consdata->quadactivitybounds));
9813 }
9814 
9815 /** propagates bounds on a quadratic constraint */
9816 static
9818  SCIP* scip, /**< SCIP data structure */
9819  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9820  SCIP_CONS* cons, /**< constraint to process */
9821  SCIP_RESULT* result, /**< pointer to store the result of the propagation call */
9822  int* nchgbds, /**< buffer where to add the the number of changed bounds */
9823  SCIP_Bool* redundant /**< buffer where to store whether constraint has been found to be redundant */
9824  )
9825 { /*lint --e{666}*/
9826  SCIP_CONSDATA* consdata;
9827  SCIP_INTERVAL consbounds; /* lower and upper bounds of constraint */
9828  SCIP_INTERVAL consactivity; /* activity of linear plus quadratic part */
9829  SCIP_Real intervalinfty; /* infinity used for interval computation */
9830  SCIP_Real minquadactivity; /* lower bound on finite activities of quadratic part */
9831  SCIP_Real maxquadactivity; /* upper bound on finite activities of quadratic part */
9832  int quadminactinf; /* number of quadratic variables that contribute -infinity to minimal activity of quadratic term */
9833  int quadmaxactinf; /* number of quadratic variables that contribute +infinity to maximal activity of quadratic term */
9834  SCIP_INTERVAL* quadactcontr; /* contribution of each quadratic variable term to quadactivity */
9835 
9836  SCIP_VAR* var;
9837  SCIP_INTERVAL rhs; /* right hand side of quadratic equation */
9838  SCIP_INTERVAL tmp;
9839  SCIP_ROUNDMODE roundmode;
9840  SCIP_Real bnd;
9841  int i;
9842 
9843  assert(scip != NULL);
9844  assert(conshdlr != NULL);
9845  assert(cons != NULL);
9846  assert(result != NULL);
9847  assert(nchgbds != NULL);
9848  assert(redundant != NULL);
9849 
9850  consdata = SCIPconsGetData(cons);
9851  assert(consdata != NULL);
9852 
9853  *result = SCIP_DIDNOTRUN;
9854  *redundant = FALSE;
9855 
9856  *result = SCIP_DIDNOTFIND;
9857 
9858  intervalinfty = 1000 * SCIPinfinity(scip) * SCIPinfinity(scip);
9859 
9860  quadactcontr = NULL;
9861  quadminactinf = -1;
9862  quadmaxactinf = -1;
9863 
9864  SCIPdebugMsg(scip, "start domain propagation for constraint <%s>\n", SCIPconsGetName(cons));
9865 
9866  /* make sure we have activity of linear term and that they are consistent */
9867  consdataUpdateLinearActivity(scip, consdata, intervalinfty);
9868  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
9869  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
9870  assert(consdata->minlinactivityinf >= 0);
9871  assert(consdata->maxlinactivityinf >= 0);
9872 
9873  /* sort quadratic variable terms, in case we need to search for terms occuring in bilinear terms later
9874  * we sort here already, since we rely on a constant variable order during this method
9875  */
9876  if( consdata->nbilinterms > 0 )
9877  {
9878  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
9879  }
9880 
9881  /* compute activity of quad term part, if not up to date
9882  * in that case, we also collect the contribution of each quad var term for later */
9883  if( SCIPintervalIsEmpty(intervalinfty, consdata->quadactivitybounds) )
9884  {
9885  SCIP_CALL( SCIPallocBufferArray(scip, &quadactcontr, consdata->nquadvars) );
9886  propagateBoundsGetQuadActivity(scip, consdata, intervalinfty, &minquadactivity, &maxquadactivity, &quadminactinf, &quadmaxactinf, quadactcontr);
9887  assert(!SCIPintervalIsEmpty(intervalinfty, consdata->quadactivitybounds));
9888  }
9889 
9890  SCIPdebugMsg(scip, "linear activity: [%g, %g] quadratic activity: [%g, %g]\n",
9891  (consdata->minlinactivityinf > 0 ? -SCIPinfinity(scip) : consdata->minlinactivity),
9892  (consdata->maxlinactivityinf > 0 ? SCIPinfinity(scip) : consdata->maxlinactivity),
9893  consdata->quadactivitybounds.inf, consdata->quadactivitybounds.sup);
9894 
9895  /* extend constraint bounds by epsilon to avoid some numerical difficulties */
9896  SCIPintervalSetBounds(&consbounds,
9897  -infty2infty(SCIPinfinity(scip), intervalinfty, -consdata->lhs+SCIPepsilon(scip)),
9898  +infty2infty(SCIPinfinity(scip), intervalinfty, consdata->rhs+SCIPepsilon(scip)));
9899 
9900  /* check redundancy and infeasibility */
9901  SCIPintervalSetBounds(&consactivity, consdata->minlinactivityinf > 0 ? -intervalinfty : consdata->minlinactivity,
9902  consdata->maxlinactivityinf > 0 ? intervalinfty : consdata->maxlinactivity);
9903  SCIPintervalAdd(intervalinfty, &consactivity, consactivity, consdata->quadactivitybounds);
9904  if( SCIPintervalIsSubsetEQ(intervalinfty, consactivity, consbounds) )
9905  {
9906  SCIPdebugMsg(scip, "found constraint <%s> to be redundant: sides: [%g, %g], activity: [%g, %g]\n",
9907  SCIPconsGetName(cons), consdata->lhs, consdata->rhs, SCIPintervalGetInf(consactivity), SCIPintervalGetSup(consactivity));
9908  *redundant = TRUE;
9909  goto CLEANUP;
9910  }
9911 
9912  /* was SCIPintervalAreDisjoint(consbounds, consactivity), but that would allow violations up to eps only
9913  * we need to decide feasibility w.r.t. feastol (but still want to propagate w.r.t. eps)
9914  */
9915  if( SCIPisFeasGT(scip, consbounds.inf, consactivity.sup) || SCIPisFeasLT(scip, consbounds.sup, consactivity.inf) )
9916  {
9917  SCIPdebugMsg(scip, "found constraint <%s> to be infeasible; sides: [%g, %g], activity: [%g, %g], infeas: %g\n",
9918  SCIPconsGetName(cons), consdata->lhs, consdata->rhs, SCIPintervalGetInf(consactivity), SCIPintervalGetSup(consactivity),
9919  MAX(consdata->lhs - SCIPintervalGetSup(consactivity), SCIPintervalGetInf(consactivity) - consdata->rhs));
9920  *result = SCIP_CUTOFF;
9921  goto CLEANUP;
9922  }
9923 
9924  /* propagate linear part \in rhs = consbounds - quadactivity (use the one from consdata, since that includes infinities) */
9925  SCIPintervalSub(intervalinfty, &rhs, consbounds, consdata->quadactivitybounds);
9926  if( !SCIPintervalIsEntire(intervalinfty, rhs) )
9927  {
9928  SCIP_Real coef;
9929 
9930  for( i = 0; i < consdata->nlinvars; ++i )
9931  {
9932  coef = consdata->lincoefs[i];
9933  var = consdata->linvars[i];
9934 
9935  /* skip fixed variables
9936  * @todo is that a good or a bad idea?
9937  * we can't expect much more tightening, but may detect infeasiblity, but shouldn't the check on the constraints activity detect that?
9938  */
9939  if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
9940  continue;
9941 
9942  /* due to large variable bounds and large coefficients, it might happen that the activity of the linear part
9943  * exceeds +/-SCIPinfinity() after updating the activities in consdataUpdateLinearActivity{Lb,Ub}Change; in
9944  * order to detect this case we need to check whether the value of consdata->{min,max}linactivity is infinite
9945  * (see #1433)
9946  */
9947  if( coef > 0.0 )
9948  {
9949  if( SCIPintervalGetSup(rhs) < intervalinfty )
9950  {
9951  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
9952  /* try to tighten the upper bound on var x */
9953  if( consdata->minlinactivityinf == 0 && !SCIPisInfinity(scip, -consdata->minlinactivity) )
9954  {
9955  assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
9956  /* tighten upper bound on x to (rhs.sup - (minlinactivity - coef * xlb)) / coef */
9957  roundmode = SCIPintervalGetRoundingMode();
9959  bnd = SCIPintervalGetSup(rhs);
9960  bnd -= consdata->minlinactivity;
9961  bnd += coef * SCIPvarGetLbLocal(var);
9962  bnd /= coef;
9963  SCIPintervalSetRoundingMode(roundmode);
9964  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
9965  if( *result == SCIP_CUTOFF )
9966  break;
9967  }
9968  else if( consdata->minlinactivityinf == 1 && SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
9969  {
9970  /* x was the variable that made the minimal linear activity equal -infinity, so
9971  * we tighten upper bound on x to just (rhs.sup - minlinactivity) / coef */
9972  roundmode = SCIPintervalGetRoundingMode();
9974  bnd = SCIPintervalGetSup(rhs);
9975  bnd -= consdata->minlinactivity;
9976  bnd /= coef;
9977  SCIPintervalSetRoundingMode(roundmode);
9978  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
9979  if( *result == SCIP_CUTOFF )
9980  break;
9981  }
9982  /* otherwise the minimal activity is -infinity and x is not solely responsible for this */
9983  }
9984 
9985  if( SCIPintervalGetInf(rhs) > -intervalinfty )
9986  {
9987  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
9988  /* try to tighten the lower bound on var x */
9989  if( consdata->maxlinactivityinf == 0 && !SCIPisInfinity(scip, consdata->maxlinactivity) )
9990  {
9991  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
9992  /* tighten lower bound on x to (rhs.inf - (maxlinactivity - coef * xub)) / coef */
9993  roundmode = SCIPintervalGetRoundingMode();
9995  bnd = SCIPintervalGetInf(rhs);
9996  bnd -= consdata->maxlinactivity;
9997  bnd += coef * SCIPvarGetUbLocal(var);
9998  bnd /= coef;
9999  SCIPintervalSetRoundingMode(roundmode);
10000  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10001  if( *result == SCIP_CUTOFF )
10002  break;
10003  }
10004  else if( consdata->maxlinactivityinf == 1 && SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
10005  {
10006  /* x was the variable that made the maximal linear activity equal infinity, so
10007  * we tighten upper bound on x to just (rhs.inf - maxlinactivity) / coef */
10008  roundmode = SCIPintervalGetRoundingMode();
10010  bnd = SCIPintervalGetInf(rhs);
10011  bnd -= consdata->maxlinactivity;
10012  bnd /= coef;
10013  SCIPintervalSetRoundingMode(roundmode);
10014  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10015  if( *result == SCIP_CUTOFF )
10016  break;
10017  }
10018  /* otherwise the maximal activity is +infinity and x is not solely responsible for this */
10019  }
10020  }
10021  else
10022  {
10023  assert(coef < 0.0 );
10024  if( SCIPintervalGetInf(rhs) > -intervalinfty )
10025  {
10026  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
10027  /* try to tighten the upper bound on var x */
10028  if( consdata->maxlinactivityinf == 0 && !SCIPisInfinity(scip, consdata->maxlinactivity) )
10029  {
10030  assert(!SCIPisInfinity(scip, SCIPvarGetLbLocal(var)));
10031  /* compute upper bound on x to (maxlinactivity - coef * xlb) - rhs.inf / (-coef) */
10032  roundmode = SCIPintervalGetRoundingMode();
10034  bnd = consdata->maxlinactivity;
10035  bnd += (-coef) * SCIPvarGetLbLocal(var);
10036  bnd -= SCIPintervalGetInf(rhs);
10037  bnd /= (-coef);
10038  SCIPintervalSetRoundingMode(roundmode);
10039  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10040  if( *result == SCIP_CUTOFF )
10041  break;
10042  }
10043  else if( consdata->maxlinactivityinf == 1 && SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
10044  {
10045  /* x was the variable that made the maximal linear activity equal infinity, so
10046  * we tighten upper bound on x to just (maxlinactivity - rhs.inf) / (-coef) */
10047  roundmode = SCIPintervalGetRoundingMode();
10049  bnd = consdata->maxlinactivity;
10050  bnd -= SCIPintervalGetInf(rhs);
10051  bnd /= (-coef);
10052  SCIPintervalSetRoundingMode(roundmode);
10053  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10054  if( *result == SCIP_CUTOFF )
10055  break;
10056  }
10057  /* otherwise the maximal activity is infinity and x is not solely responsible for this */
10058  }
10059 
10060  if( SCIPintervalGetSup(rhs) < intervalinfty )
10061  {
10062  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
10063  /* try to tighten the lower bound on var x */
10064  if( consdata->minlinactivityinf == 0 && !SCIPisInfinity(scip, -consdata->minlinactivity) )
10065  {
10066  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
10067  /* compute lower bound on x to (minlinactivity - coef * xub) - rhs.sup / (-coef) */
10068  roundmode = SCIPintervalGetRoundingMode();
10070  bnd = consdata->minlinactivity;
10071  bnd += (-coef) * SCIPvarGetUbLocal(var);
10072  bnd -= SCIPintervalGetSup(rhs);
10073  bnd /= (-coef);
10074  SCIPintervalSetRoundingMode(roundmode);
10075  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10076  if( *result == SCIP_CUTOFF )
10077  break;
10078  }
10079  else if( consdata->minlinactivityinf == 1 && SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
10080  {
10081  /* x was the variable that made the maximal linear activity equal -infinity, so
10082  * we tighten lower bound on x to just (minlinactivity - rhs.sup) / (-coef) */
10083  roundmode = SCIPintervalGetRoundingMode();
10085  bnd = consdata->minlinactivity;
10086  bnd -= SCIPintervalGetSup(rhs);
10087  bnd /= (-coef);
10088  SCIPintervalSetRoundingMode(roundmode);
10089  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10090  if( *result == SCIP_CUTOFF )
10091  break;
10092  }
10093  /* otherwise the minimal activity is -infinity and x is not solely responsible for this */
10094  }
10095  }
10096  }
10097  if( *result == SCIP_CUTOFF )
10098  goto CLEANUP;
10099  }
10100 
10101  /* propagate quadratic part \in rhs = consbounds - linactivity */
10102  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
10103  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
10104  consdataUpdateLinearActivity(scip, consdata, intervalinfty); /* make sure, activities of linear part did not become invalid by above bound changes, if any */
10105  assert(consdata->minlinactivityinf > 0 || consdata->maxlinactivityinf > 0 || consdata->minlinactivity <= consdata->maxlinactivity);
10106  SCIPintervalSetBounds(&tmp,
10107  (consdata->minlinactivityinf > 0 ? -intervalinfty : consdata->minlinactivity),
10108  (consdata->maxlinactivityinf > 0 ? intervalinfty : consdata->maxlinactivity));
10109  SCIPintervalSub(intervalinfty, &rhs, consbounds, tmp);
10110  if( !SCIPintervalIsEntire(intervalinfty, rhs) )
10111  {
10112  if( consdata->nquadvars == 1 )
10113  {
10114  /* quadratic part is just a*x^2+b*x -> a common case that we treat directly */
10115  SCIP_INTERVAL lincoef; /* linear coefficient of quadratic equation */
10116 
10117  assert(consdata->nbilinterms == 0);
10118 
10119  var = consdata->quadvarterms[0].var;
10120  SCIPintervalSet(&lincoef, consdata->quadvarterms[0].lincoef);
10121 
10122  /* propagate a*x^2 + b*x \in rhs */
10123  SCIP_CALL( propagateBoundsQuadVar(scip, cons, intervalinfty, var, consdata->quadvarterms[0].sqrcoef, lincoef, rhs, result, nchgbds) );
10124  }
10125  else if( consdata->nbilinterms == 1 && consdata->nquadvars == 2 )
10126  {
10127  /* quadratic part is just ax*x^2+bx*x + ay*y^2+by*y + c*xy -> a common case that we treat directly */
10128  assert(consdata->bilinterms[0].var1 == consdata->quadvarterms[0].var || consdata->bilinterms[0].var1 == consdata->quadvarterms[1].var);
10129  assert(consdata->bilinterms[0].var2 == consdata->quadvarterms[0].var || consdata->bilinterms[0].var2 == consdata->quadvarterms[1].var);
10130 
10131  /* 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 */
10132  SCIP_CALL( propagateBoundsBilinearTerm(scip, cons, intervalinfty,
10133  consdata->quadvarterms[0].var, consdata->quadvarterms[0].sqrcoef, consdata->quadvarterms[0].lincoef,
10134  consdata->quadvarterms[1].var, consdata->quadvarterms[1].sqrcoef, consdata->quadvarterms[1].lincoef,
10135  consdata->bilinterms[0].coef,
10136  rhs, result, nchgbds) );
10137  if( *result != SCIP_CUTOFF )
10138  {
10139  /* 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 */
10140  SCIP_CALL( propagateBoundsBilinearTerm(scip, cons, intervalinfty,
10141  consdata->quadvarterms[1].var, consdata->quadvarterms[1].sqrcoef, consdata->quadvarterms[1].lincoef,
10142  consdata->quadvarterms[0].var, consdata->quadvarterms[0].sqrcoef, consdata->quadvarterms[0].lincoef,
10143  consdata->bilinterms[0].coef,
10144  rhs, result, nchgbds) );
10145  }
10146  }
10147  else
10148  {
10149  /* general case */
10150 
10151  /* compute "advanced" information on quad var term activities, if not up-to-date */
10152  if( quadminactinf == -1 )
10153  {
10154  assert(quadactcontr == NULL);
10155  SCIP_CALL( SCIPallocBufferArray(scip, &quadactcontr, consdata->nquadvars) );
10156  propagateBoundsGetQuadActivity(scip, consdata, intervalinfty, &minquadactivity, &maxquadactivity, &quadminactinf, &quadmaxactinf, quadactcontr);
10157  }
10158  assert(quadactcontr != NULL);
10159  assert(quadminactinf >= 0);
10160  assert(quadmaxactinf >= 0);
10161 
10162  /* if the quad activities are not hopelessly unbounded on useful sides, try to deduce domain reductions on quad vars */
10163  if( (SCIPintervalGetSup(rhs) < intervalinfty && quadminactinf <= 1) ||
10164  ( SCIPintervalGetInf(rhs) > -intervalinfty && quadmaxactinf <= 1) )
10165  {
10166  SCIP_INTERVAL lincoef;
10167  SCIP_INTERVAL rhs2;
10168  int j;
10169  int k;
10170 
10171  for( i = 0; i < consdata->nquadvars; ++i )
10172  {
10173  var = consdata->quadvarterms[i].var;
10174 
10175  /* skip fixed variables
10176  * @todo is that a good or a bad idea?
10177  * we can't expect much more tightening, but may detect infeasiblity, but shouldn't the check on the constraints activity detect that?
10178  */
10179  if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
10180  continue;
10181 
10182  /* compute rhs2 such that we can propagate quadvarterm(x_i) \in rhs2 */
10183 
10184  /* setup rhs2.sup = rhs.sup - (quadactivity.inf - quadactcontr[i].inf), if everything were finite
10185  * if only quadactcontr[i].inf is infinite (i.e., the other i are all finite), we just get rhs2.sup = rhs.sup
10186  * otherwise we get rhs2.sup = infinity */
10187  if( SCIPintervalGetSup(rhs) < intervalinfty )
10188  {
10189  if( quadminactinf == 0 || (quadminactinf == 1 && SCIPintervalGetInf(quadactcontr[i]) <= -intervalinfty) )
10190  {
10191  roundmode = SCIPintervalGetRoundingMode();
10193  rhs2.sup = rhs.sup - minquadactivity; /*lint !e644*/
10194  /* if the residual quad min activity w.r.t. quad var term i is finite and nonzero, so add it to right hand side */
10195  if( quadminactinf == 0 && SCIPintervalGetInf(quadactcontr[i]) != 0.0 )
10196  rhs2.sup += SCIPintervalGetInf(quadactcontr[i]);
10197  SCIPintervalSetRoundingMode(roundmode);
10198  }
10199  else
10200  {
10201  /* there are either >= 2 quad var terms contributing -infinity, or there is one which is not i */
10202  rhs2.sup = intervalinfty;
10203  }
10204  }
10205  else
10206  {
10207  rhs2.sup = intervalinfty;
10208  }
10209 
10210  /* setup rhs2.inf = rhs.inf - (quadactivity.sup - quadactcontr[i].sup), see also above */
10211  if( SCIPintervalGetInf(rhs) > -intervalinfty )
10212  {
10213  if( quadmaxactinf == 0 || (quadmaxactinf == 1 && SCIPintervalGetSup(quadactcontr[i]) >= intervalinfty) )
10214  {
10215  roundmode = SCIPintervalGetRoundingMode();
10217  rhs2.inf = rhs.inf - maxquadactivity; /*lint !e644*/
10218  /* if the residual quad max activity w.r.t. quad var term i is finite and nonzero, so add it to right hand side */
10219  if( quadmaxactinf == 0 && SCIPintervalGetSup(quadactcontr[i]) != 0.0 )
10220  rhs2.inf += SCIPintervalGetSup(quadactcontr[i]);
10221  SCIPintervalSetRoundingMode(roundmode);
10222  }
10223  else
10224  {
10225  /* there are either >= 2 quad var terms contributing infinity, or there is one which is not i */
10226  rhs2.inf = -intervalinfty;
10227  }
10228  }
10229  else
10230  {
10231  rhs2.inf = -intervalinfty;
10232  }
10233  assert(!SCIPintervalIsEmpty(intervalinfty, rhs2));
10234 
10235  /* if rhs2 is entire, then there is nothing we could propagate */
10236  if( SCIPintervalIsEntire(intervalinfty, rhs2) )
10237  continue;
10238 
10239  /* assemble linear coefficient for quad equation a*x^2 + b*x \in rhs2 */
10240  SCIPintervalSet(&lincoef, consdata->quadvarterms[i].lincoef);
10241  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
10242  {
10243  k = consdata->quadvarterms[i].adjbilin[j];
10244 #if 1
10245  if( consdata->bilinterms[k].var1 == var )
10246  {
10247  /* bilinear term k contributes to the activity of quad var term i, so just add bounds to linear coef */
10248  SCIPintervalSetBounds(&tmp,
10249  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
10250  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
10251  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
10252  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
10253  }
10254  else
10255  {
10256  /* bilinear term k does not contribute to the activity of quad var term i
10257  * so bounds on term k are contained in rhs2
10258  * if they are finite, we try to remove them from rhs2 and update lincoef instead
10259  * 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
10260  * HOWEVER: when computing rhs2, we may not just have added the bounds for the bilinear term, but for the associated quadratic term
10261  * for this complete term, we used SCIPintervalQuad to compute the bounds
10262  * since we do not want to repeat a call to SCIPintervalQuad for that quadratic term with bilinear term k removed,
10263  * we only remove the bounds for the bilinear term k from rhs2 if the associated quadratic term consists only of this bilinear term,
10264  * i.e., the quadratic term corresponding to var1 should be only var1*var2, but have no square or linear coefs or other bilinear terms
10265  * (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)
10266  */
10267  SCIP_INTERVAL me;
10268  SCIP_INTERVAL bilinbounds;
10269  int otherpos;
10270 
10271  assert(consdata->bilinterms[k].var2 == var);
10272 
10273  assert(consdata->quadvarssorted);
10274  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->bilinterms[k].var1, &otherpos) );
10275  assert(otherpos >= 0);
10276  assert(consdata->quadvarterms[otherpos].var == consdata->bilinterms[k].var1);
10277 
10278  if( (consdata->quadvarterms[otherpos].sqrcoef != 0.0) || consdata->quadvarterms[otherpos].lincoef != 0.0 ||
10279  consdata->quadvarterms[otherpos].nadjbilin > 1 )
10280  continue;
10281 
10282  /* set tmp to bounds of other variable and multiply with bilin coef */
10283  SCIPintervalSetBounds(&tmp,
10284  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var1), SCIPvarGetUbLocal(consdata->bilinterms[k].var1))),
10285  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var1), SCIPvarGetUbLocal(consdata->bilinterms[k].var1))));
10286  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
10287 
10288  /* set me to bounds of i'th variable */
10290  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
10291  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
10292 
10293  /* remove me*tmp from rhs2 */
10294 
10295  roundmode = SCIPintervalGetRoundingMode();
10296 
10297  if( rhs2.inf > -intervalinfty )
10298  {
10299  /* need upward rounding for SCIPintervalMulSup */
10301  SCIPintervalMulSup(intervalinfty, &bilinbounds, me, tmp);
10302  /* rhs2.inf += bilinbounds.sup, but we are in upward rounding */
10303  if( bilinbounds.sup < intervalinfty )
10304  rhs2.inf = SCIPintervalNegateReal(SCIPintervalNegateReal(rhs2.inf) - bilinbounds.sup);
10305  }
10306 
10307  if( rhs2.sup < intervalinfty )
10308  {
10309  /* need downward rounding for SCIPintervalMulInf */
10311  SCIPintervalMulInf(intervalinfty, &bilinbounds, me, tmp);
10312  /* rhs2.sup += bilinbounds.inf, but we are in downward rounding */
10313  if( bilinbounds.inf > -intervalinfty )
10314  rhs2.sup = SCIPintervalNegateReal(SCIPintervalNegateReal(rhs2.sup) - bilinbounds.inf);
10315  }
10316 
10317  SCIPintervalSetRoundingMode(roundmode);
10318 
10319  /* add tmp to lincoef */
10320  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
10321  }
10322 #else
10323  if( consdata->bilinterms[k].var1 != var )
10324  continue; /* this term does not contribute to the activity of quad var term i */
10325 
10326  SCIPintervalSetBounds(&tmp,
10327  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
10328  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
10329  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
10330  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
10331 #endif
10332  }
10333 
10334  /* deduce domain reductions for x_i */
10335  SCIP_CALL( propagateBoundsQuadVar(scip, cons, intervalinfty, var, consdata->quadvarterms[i].sqrcoef, lincoef, rhs2, result, nchgbds) );
10336  if( *result == SCIP_CUTOFF )
10337  goto CLEANUP;
10338  }
10339  }
10340  }
10341  }
10342 
10343  CLEANUP:
10344  SCIPfreeBufferArrayNull(scip, &quadactcontr);
10345 
10346  return SCIP_OKAY;
10347 }
10348 
10349 /** calls domain propagation for a set of constraints */
10350 static
10352  SCIP* scip, /**< SCIP data structure */
10353  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
10354  SCIP_CONS** conss, /**< constraints to process */
10355  int nconss, /**< number of constraints */
10356  SCIP_RESULT* result, /**< pointer to store the result of the propagation calls */
10357  int* nchgbds /**< buffer where to add the the number of changed bounds */
10358  )
10359 {
10360  SCIP_CONSHDLRDATA* conshdlrdata;
10361  SCIP_RESULT propresult;
10362  SCIP_Bool redundant;
10363  int c;
10364  int roundnr;
10365  SCIP_Bool success;
10366  int maxproprounds;
10367 
10368  assert(scip != NULL);
10369  assert(conshdlr != NULL);
10370  assert(conss != NULL || nconss == 0);
10371  assert(result != NULL);
10372  assert(nchgbds != NULL);
10373 
10375 
10376  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10377  assert(conshdlrdata != NULL);
10378 
10379  *result = SCIP_DIDNOTFIND;
10380  roundnr = 0;
10381  if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING )
10382  maxproprounds = conshdlrdata->maxproproundspresolve;
10383  else
10384  maxproprounds = conshdlrdata->maxproprounds;
10385 
10386  do
10387  {
10388  success = FALSE;
10389  ++roundnr;
10390 
10391  SCIPdebugMsg(scip, "starting domain propagation round %d of %d for %d constraints\n", roundnr, maxproprounds, nconss);
10392 
10393  for( c = 0; c < nconss && *result != SCIP_CUTOFF; ++c )
10394  {
10395  assert(conss != NULL);
10396  if( !SCIPconsIsEnabled(conss[c]) )
10397  continue;
10398 
10399  if( SCIPconsIsMarkedPropagate(conss[c]) )
10400  {
10401  /* unmark constraint for propagation */
10402  SCIP_CALL( SCIPunmarkConsPropagate(scip, conss[c]) );
10403 
10404  SCIP_CALL( propagateBoundsCons(scip, conshdlr, conss[c], &propresult, nchgbds, &redundant) );
10405  if( propresult != SCIP_DIDNOTFIND && propresult != SCIP_DIDNOTRUN )
10406  {
10407  *result = propresult;
10408  success = TRUE;
10409  }
10410  if( redundant )
10411  {
10412  SCIPdebugMsg(scip, "deleting constraint <%s> locally\n", SCIPconsGetName(conss[c]));
10413  SCIP_CALL( SCIPdelConsLocal(scip, conss[c]) );
10414  }
10415  }
10416  }
10417 
10418  }
10419  while( success && *result != SCIP_CUTOFF && roundnr < maxproprounds );
10420 
10421  return SCIP_OKAY;
10422 }
10423 
10424 /** checks for a linear variable that can be increase or decreased without harming feasibility */
10425 static
10427  SCIP* scip, /**< SCIP data structure */
10428  SCIP_CONSDATA* consdata /**< constraint data */
10429  )
10430 {
10431  int i;
10432  int poslock;
10433  int neglock;
10434 
10435  consdata->linvar_maydecrease = -1;
10436  consdata->linvar_mayincrease = -1;
10437 
10438  /* check for a linear variable that can be increase or decreased without harming feasibility */
10439  for( i = 0; i < consdata->nlinvars; ++i )
10440  {
10441  /* compute locks of i'th linear variable */
10442  assert(consdata->lincoefs[i] != 0.0);
10443  if( consdata->lincoefs[i] > 0.0 )
10444  {
10445  poslock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
10446  neglock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
10447  }
10448  else
10449  {
10450  poslock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
10451  neglock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
10452  }
10453 
10454  if( SCIPvarGetNLocksDown(consdata->linvars[i]) - neglock == 0 )
10455  {
10456  /* for a*x + q(y) \in [lhs, rhs], we can decrease x without harming other constraints */
10457  /* if we have already one candidate, then take the one where the loss in the objective function is less */
10458  if( (consdata->linvar_maydecrease < 0) ||
10459  (SCIPvarGetObj(consdata->linvars[consdata->linvar_maydecrease]) / consdata->lincoefs[consdata->linvar_maydecrease] > SCIPvarGetObj(consdata->linvars[i]) / consdata->lincoefs[i]) )
10460  consdata->linvar_maydecrease = i;
10461  }
10462 
10463  if( SCIPvarGetNLocksDown(consdata->linvars[i]) - poslock == 0 )
10464  {
10465  /* for a*x + q(y) \in [lhs, rhs], we can increase x without harm */
10466  /* if we have already one candidate, then take the one where the loss in the objective function is less */
10467  if( (consdata->linvar_mayincrease < 0) ||
10468  (SCIPvarGetObj(consdata->linvars[consdata->linvar_mayincrease]) / consdata->lincoefs[consdata->linvar_mayincrease] > SCIPvarGetObj(consdata->linvars[i]) / consdata->lincoefs[i]) )
10469  consdata->linvar_mayincrease = i;
10470  }
10471  }
10472 
10473 #ifdef SCIP_DEBUG
10474  if( consdata->linvar_mayincrease >= 0 )
10475  {
10476  SCIPdebugMsg(scip, "may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvars[consdata->linvar_mayincrease]));
10477  }
10478  if( consdata->linvar_maydecrease >= 0 )
10479  {
10480  SCIPdebugMsg(scip, "may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvars[consdata->linvar_maydecrease]));
10481  }
10482 #endif
10483 }
10484 
10485 /** Given a solution where every quadratic constraint is either feasible or can be made feasible by
10486  * moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
10487  *
10488  * The method assumes that this is always possible and that not all constraints are feasible already.
10489  */
10490 static
10492  SCIP* scip, /**< SCIP data structure */
10493  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
10494  SCIP_CONS** conss, /**< constraints to process */
10495  int nconss, /**< number of constraints */
10496  SCIP_SOL* sol, /**< solution to process */
10497  SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
10498  )
10499 {
10500  SCIP_CONSHDLRDATA* conshdlrdata;
10501  SCIP_CONSDATA* consdata;
10502  char origscaling;
10503  SCIP_SOL* newsol;
10504  SCIP_VAR* var;
10505  int c;
10506  SCIP_Real viol;
10507  SCIP_Real delta;
10508  SCIP_Real gap;
10509  SCIP_Bool solviolbounds;
10510 
10511  assert(scip != NULL);
10512  assert(conshdlr != NULL);
10513  assert(conss != NULL || nconss == 0);
10514  assert(success != NULL);
10515 
10516  *success = FALSE;
10517 
10518  /* don't propose new solutions if not in presolve or solving */
10520  return SCIP_OKAY;
10521 
10522  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10523  assert(conshdlrdata != NULL);
10524 
10525  if( sol != NULL )
10526  {
10527  SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
10528  }
10529  else
10530  {
10531  SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
10532  }
10533  SCIP_CALL( SCIPunlinkSol(scip, newsol) );
10534  SCIPdebugMsg(scip, "attempt to make solution from <%s> feasible by shifting linear variable\n",
10535  sol != NULL ? (SCIPsolGetHeur(sol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(sol)) : "tree") : "LP");
10536 
10537  origscaling = conshdlrdata->scaling;
10538  for( c = 0; c < nconss; ++c )
10539  {
10540  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
10541  assert(consdata != NULL);
10542 
10543  /* recompute violation of solution in case solution has changed
10544  * get absolution violation and sign
10545  * @todo avoid doing it this way
10546  */
10547  conshdlrdata->scaling = 'o';
10548  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
10549  {
10550  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], newsol, &solviolbounds) ); /*lint !e613*/
10551  assert(!solviolbounds);
10552  viol = consdata->lhs - consdata->activity;
10553  }
10554  else if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
10555  {
10556  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], newsol, &solviolbounds) ); /*lint !e613*/
10557  assert(!solviolbounds);
10558  viol = consdata->rhs - consdata->activity;
10559  }
10560  else
10561  continue; /* constraint is satisfied */
10562 
10563  assert(viol != 0.0);
10564  if( consdata->linvar_mayincrease >= 0 &&
10565  ((viol > 0.0 && consdata->lincoefs[consdata->linvar_mayincrease] > 0.0) || (viol < 0.0 && consdata->lincoefs[consdata->linvar_mayincrease] < 0.0)) )
10566  {
10567  /* have variable where increasing makes the constraint less violated */
10568  var = consdata->linvars[consdata->linvar_mayincrease];
10569  /* compute how much we would like to increase var */
10570  delta = viol / consdata->lincoefs[consdata->linvar_mayincrease];
10571  assert(delta > 0.0);
10572  /* if var has an upper bound, may need to reduce delta */
10573  if( !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
10574  {
10575  gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
10576  delta = MIN(MAX(0.0, gap), delta);
10577  }
10578  if( SCIPisPositive(scip, delta) )
10579  {
10580  /* if variable is integral, round delta up so that it will still have an integer value */
10581  if( SCIPvarIsIntegral(var) )
10582  delta = SCIPceil(scip, delta);
10583 
10584  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
10585  /*lint --e{613} */
10586  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]));
10587 
10588  /* adjust constraint violation, if satisfied go on to next constraint */
10589  viol -= consdata->lincoefs[consdata->linvar_mayincrease] * delta;
10590  if( SCIPisZero(scip, viol) )
10591  continue;
10592  }
10593  }
10594 
10595  assert(viol != 0.0);
10596  if( consdata->linvar_maydecrease >= 0 &&
10597  ((viol > 0.0 && consdata->lincoefs[consdata->linvar_maydecrease] < 0.0) || (viol < 0.0 && consdata->lincoefs[consdata->linvar_maydecrease] > 0.0)) )
10598  {
10599  /* have variable where decreasing makes constraint less violated */
10600  var = consdata->linvars[consdata->linvar_maydecrease];
10601  /* compute how much we would like to decrease var */
10602  delta = viol / consdata->lincoefs[consdata->linvar_maydecrease];
10603  assert(delta < 0.0);
10604  /* if var has a lower bound, may need to reduce delta */
10605  if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) )
10606  {
10607  gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
10608  delta = MAX(MIN(0.0, gap), delta);
10609  }
10610  if( SCIPisNegative(scip, delta) )
10611  {
10612  /* if variable is integral, round delta down so that it will still have an integer value */
10613  if( SCIPvarIsIntegral(var) )
10614  delta = SCIPfloor(scip, delta);
10615  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
10616  /*lint --e{613} */
10617  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]));
10618 
10619  /* adjust constraint violation, if satisfied go on to next constraint */
10620  viol -= consdata->lincoefs[consdata->linvar_maydecrease] * delta;
10621  if( SCIPisZero(scip, viol) )
10622  continue;
10623  }
10624  }
10625 
10626  /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
10627  break;
10628  }
10629  conshdlrdata->scaling = origscaling;
10630 
10631  /* if we have a solution that should satisfy all quadratic constraints and has a better objective than the current upper bound,
10632  * then pass it to the trysol heuristic
10633  */
10634  if( c == nconss && (SCIPisInfinity(scip, SCIPgetUpperbound(scip)) || SCIPisSumLT(scip, SCIPgetSolTransObj(scip, newsol), SCIPgetUpperbound(scip))) )
10635  {
10636  SCIPdebugMsg(scip, "pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
10637 
10638  assert(conshdlrdata->trysolheur != NULL);
10639  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
10640 
10641  *success = TRUE;
10642  }
10643 
10644  SCIP_CALL( SCIPfreeSol(scip, &newsol) );
10645 
10646  return SCIP_OKAY;
10647 }
10648 
10649 /** helper function to enforce constraints */
10650 static
10652  SCIP* scip, /**< SCIP data structure */
10653  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
10654  SCIP_CONS** conss, /**< constraints to process */
10655  int nconss, /**< number of constraints */
10656  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
10657  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
10658  SCIP_Bool solinfeasible, /**< was the solution already declared infeasible by a constraint handler? */
10659  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
10660  )
10661 {
10662  SCIP_CONSHDLRDATA* conshdlrdata;
10663  SCIP_CONSDATA* consdata;
10664  SCIP_CONS* maxviolcon;
10665  SCIP_Real maxviol;
10666  SCIP_RESULT propresult;
10667  SCIP_RESULT separateresult;
10668  int nchgbds;
10669  int nnotify;
10670  SCIP_Real sepaefficacy;
10671  SCIP_Real minefficacy;
10672  SCIP_Real leastpossibleefficacy;
10673  SCIP_Bool solviolbounds;
10674 
10675  assert(scip != NULL);
10676  assert(conshdlr != NULL);
10677  assert(conss != NULL || nconss == 0);
10678  assert(nconss >= 0);
10679  assert(nusefulconss >= 0);
10680  assert(result != NULL);
10681 
10682  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10683  assert(conshdlrdata != NULL);
10684 
10685  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, sol, &solviolbounds, &maxviolcon) );
10686 
10687  if( maxviolcon == NULL )
10688  {
10689  *result = SCIP_FEASIBLE;
10690  return SCIP_OKAY;
10691  }
10692 
10693  *result = SCIP_INFEASIBLE;
10694 
10695  if( solviolbounds )
10696  {
10697  /* if LP solution violates variable bounds, then this should be because a row was added that
10698  * introduced this variable newly to the LP, in which case it gets value 0.0; the row should
10699  * have been added to resolve an infeasibility, so solinfeasible should be TRUE
10700  * see also issue #627
10701  */
10702  assert(solinfeasible);
10703  /* however, if solinfeasible is actually not TRUE, then better cut off the node to avoid that SCIP
10704  * stops because infeasible cannot be resolved */
10705  /*lint --e{774} */
10706  if( !solinfeasible )
10707  *result = SCIP_CUTOFF;
10708  return SCIP_OKAY;
10709  }
10710 
10711  consdata = SCIPconsGetData(maxviolcon);
10712  assert(consdata != NULL);
10713  maxviol = consdata->lhsviol + consdata->rhsviol;
10714  assert(SCIPisGT(scip, maxviol, SCIPfeastol(scip)));
10715 
10716  SCIPdebugMsg(scip, "enforcement with max violation %g in cons <%s> for %s solution\n", maxviol, SCIPconsGetName(maxviolcon),
10717  sol == NULL ? "LP" : "relaxation");
10718 
10719  /* if we are above the 100'th enforcement round for this node, something is strange
10720  * (maybe the LP / relaxator does not think that the cuts we add are violated, or we do ECP on a high-dimensional convex function)
10721  * 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
10722  * (in optimized more, returning SCIP_INFEASIBLE in *result would be sufficient, but in debug mode this would give an assert in scip.c)
10723  * the reason to wait for 100 rounds is to avoid calls to SCIPisStopped in normal runs, which may be expensive
10724  * we only increment nenforounds until 101 to avoid an overflow
10725  */
10726  if( conshdlrdata->lastenfonode == SCIPgetCurrentNode(scip) )
10727  {
10728  if( conshdlrdata->nenforounds > 100 )
10729  {
10730  if( SCIPisStopped(scip) )
10731  {
10732  SCIP_NODE* child;
10733 
10734  SCIP_CALL( SCIPcreateChild(scip, &child, 1.0, SCIPnodeGetEstimate(SCIPgetCurrentNode(scip))) );
10735  *result = SCIP_BRANCHED;
10736 
10737  return SCIP_OKAY;
10738  }
10739  }
10740 
10741  ++conshdlrdata->nenforounds;
10742 
10743  /* cut off the current subtree, if a limit on the enforcement rounds should be applied. At this point, feasible
10744  * solutions might get cut off; the enfolplimit parameter should therefore only be set if SCIP is used as a
10745  * heuristic solver and when the returned result (infeasible, optimal, the gap) can be ignored
10746  */
10747  if( conshdlrdata->enfolplimit != -1 && conshdlrdata->nenforounds > conshdlrdata->enfolplimit )
10748  {
10750  "cut off subtree because enforcement limit was reached; this might lead to incorrect results\n");
10751  *result = SCIP_CUTOFF;
10752  return SCIP_OKAY;
10753  }
10754  }
10755  else
10756  {
10757  conshdlrdata->lastenfonode = SCIPgetCurrentNode(scip);
10758  conshdlrdata->nenforounds = 0;
10759  }
10760 
10761  /* run domain propagation */
10762  nchgbds = 0;
10763  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, &propresult, &nchgbds) );
10764  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
10765  {
10766  SCIPdebugMsg(scip, "propagation succeeded (%s)\n", propresult == SCIP_CUTOFF ? "cutoff" : "reduceddom");
10767  *result = propresult;
10768  return SCIP_OKAY;
10769  }
10770 
10771  /* we would like a cut that is efficient enough that it is not redundant in the LP (>feastol)
10772  * however, if the maximal violation is very small, also the best cut efficacy cannot be large
10773  * thus, in the latter case, we are also happy if the efficacy is at least, say, 75% of the maximal violation
10774  * but in any case we need an efficacy that is at least feastol
10775  */
10776  minefficacy = MIN(0.75*maxviol, conshdlrdata->mincutefficacyenfofac * SCIPfeastol(scip)); /*lint !e666 */
10777  minefficacy = MAX(minefficacy, SCIPfeastol(scip)); /*lint !e666 */
10778  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, minefficacy, TRUE, &separateresult, &sepaefficacy) );
10779  if( separateresult == SCIP_CUTOFF )
10780  {
10781  SCIPdebugMsg(scip, "separation found cutoff\n");
10782  *result = SCIP_CUTOFF;
10783  return SCIP_OKAY;
10784  }
10785  if( separateresult == SCIP_SEPARATED )
10786  {
10787  SCIPdebugMsg(scip, "separation succeeded (bestefficacy = %g, minefficacy = %g)\n", sepaefficacy, minefficacy);
10788  *result = SCIP_SEPARATED;
10789  return SCIP_OKAY;
10790  }
10791 
10792  /* we are not feasible, the whole node is not infeasible, and we cannot find a good cut
10793  * -> collect variables for branching
10794  */
10795 
10796  SCIPdebugMsg(scip, "separation failed (bestefficacy = %g < %g = minefficacy ); max viol: %g\n", sepaefficacy, minefficacy, maxviol);
10797 
10798  /* find branching candidates */
10799  SCIP_CALL( registerBranchingCandidates(scip, conshdlr, conss, nconss, sol, &nnotify) );
10800 
10801  /* if sepastore can decrease feasibility tolerance, we can add cuts with efficacy in [eps, feastol] */
10802  leastpossibleefficacy = SCIPgetRelaxFeastolFactor(scip) > 0.0 ? SCIPepsilon(scip) : SCIPfeastol(scip);
10803  if( nnotify == 0 && !solinfeasible && minefficacy > leastpossibleefficacy )
10804  {
10805  /* fallback 1: we also have no branching candidates, so try to find a weak cut */
10806  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, leastpossibleefficacy, TRUE, &separateresult, &sepaefficacy) );
10807  if( separateresult == SCIP_CUTOFF )
10808  {
10809  SCIPdebugMsg(scip, "separation found cutoff\n");
10810  *result = SCIP_CUTOFF;
10811  return SCIP_OKAY;
10812  }
10813  if( separateresult == SCIP_SEPARATED )
10814  {
10815  SCIPdebugMsg(scip, "separation fallback succeeded, efficacy = %g\n", sepaefficacy);
10816  *result = SCIP_SEPARATED;
10817  return SCIP_OKAY;
10818  }
10819  }
10820 
10821  if( nnotify == 0 && !solinfeasible )
10822  {
10823  /* fallback 2: separation probably failed because of numerical difficulties with a convex constraint;
10824  * if noone declared solution infeasible yet and we had not even found a weak cut, try to resolve by branching
10825  */
10826  SCIP_VAR* brvar = NULL;
10827  SCIP_CALL( registerLargeRelaxValueVariableForBranching(scip, conss, nconss, sol, &brvar) );
10828  if( brvar == NULL )
10829  {
10830  /* fallback 3: all quadratic variables seem to be fixed -> replace by linear constraint */
10831  SCIP_Bool addedcons;
10832  SCIP_Bool reduceddom;
10833  SCIP_Bool infeasible;
10834 
10835  SCIP_CALL( replaceByLinearConstraints(scip, conss, nconss, &addedcons, &reduceddom, &infeasible) );
10836  /* if the linear constraints are actually feasible, then adding them and returning SCIP_CONSADDED confuses SCIP
10837  * when it enforces the new constraints again and nothing resolves the infeasiblity that we declare here thus,
10838  * we only add them if considered violated, and otherwise claim the solution is feasible (but print a
10839  * warning) */
10840  if ( infeasible )
10841  *result = SCIP_CUTOFF;
10842  else if ( addedcons )
10843  *result = SCIP_CONSADDED;
10844  else if ( reduceddom )
10845  *result = SCIP_REDUCEDDOM;
10846  else
10847  {
10848  *result = SCIP_FEASIBLE;
10849  SCIPwarningMessage(scip, "could not enforce feasibility by separating or branching; declaring solution with viol %g as feasible\n", maxviol);
10850  assert(!SCIPisInfinity(scip, maxviol));
10851  }
10852  return SCIP_OKAY;
10853  }
10854  else
10855  {
10856  SCIPdebugMsg(scip, "Could not find any usual branching variable candidate. Proposed variable <%s> with LP value %g for branching.\n",
10857  SCIPvarGetName(brvar), SCIPgetSolVal(scip, sol, brvar));
10858  nnotify = 1;
10859  }
10860  }
10861 
10862  assert(*result == SCIP_INFEASIBLE && (solinfeasible || nnotify > 0));
10863  return SCIP_OKAY;
10864 }
10865 
10866 /** tries to upgrade a nonlinear constraint into a quadratic constraint */
10867 static
10868 SCIP_DECL_NONLINCONSUPGD(nonlinconsUpgdQuadratic)
10870  SCIP_EXPRGRAPH* exprgraph;
10871  SCIP_EXPRGRAPHNODE* node;
10872  int i;
10873 
10874  assert(nupgdconss != NULL);
10875  assert(upgdconss != NULL);
10876 
10877  *nupgdconss = 0;
10878 
10879  node = SCIPgetExprgraphNodeNonlinear(scip, cons);
10880 
10881  /* no interest in linear constraints */
10882  if( node == NULL )
10883  return SCIP_OKAY;
10884 
10885  /* if a quadratic expression has been simplified, then all children of the node should be variables */
10887  return SCIP_OKAY;
10888 
10889  switch( SCIPexprgraphGetNodeOperator(node) )
10890  {
10891  case SCIP_EXPR_VARIDX:
10892  case SCIP_EXPR_CONST:
10893  case SCIP_EXPR_PLUS:
10894  case SCIP_EXPR_MINUS:
10895  case SCIP_EXPR_SUM:
10896  case SCIP_EXPR_LINEAR:
10897  /* these should not appear as exprgraphnodes after constraint presolving */
10898  return SCIP_OKAY;
10899 
10900  case SCIP_EXPR_DIV:
10901  case SCIP_EXPR_SQRT:
10902  case SCIP_EXPR_REALPOWER:
10903  case SCIP_EXPR_INTPOWER:
10904  case SCIP_EXPR_SIGNPOWER:
10905  case SCIP_EXPR_EXP:
10906  case SCIP_EXPR_LOG:
10907  case SCIP_EXPR_SIN:
10908  case SCIP_EXPR_COS:
10909  case SCIP_EXPR_TAN:
10910  /* case SCIP_EXPR_ERF: */
10911  /* case SCIP_EXPR_ERFI: */
10912  case SCIP_EXPR_MIN:
10913  case SCIP_EXPR_MAX:
10914  case SCIP_EXPR_ABS:
10915  case SCIP_EXPR_SIGN:
10916  case SCIP_EXPR_PRODUCT:
10917  case SCIP_EXPR_POLYNOMIAL:
10918  case SCIP_EXPR_USER:
10919  /* these do not look like an quadratic expression (assuming the expression graph simplifier did run) */
10920  return SCIP_OKAY;
10921 
10922  case SCIP_EXPR_MUL:
10923  case SCIP_EXPR_SQUARE:
10924  case SCIP_EXPR_QUADRATIC:
10925  /* these mean that we have something quadratic */
10926  break;
10927 
10928  case SCIP_EXPR_PARAM:
10929  case SCIP_EXPR_LAST:
10930  default:
10931  SCIPwarningMessage(scip, "unexpected expression operator %d in nonlinear constraint <%s>\n", SCIPexprgraphGetNodeOperator(node), SCIPconsGetName(cons));
10932  return SCIP_OKAY;
10933  }
10934 
10935  /* setup a quadratic constraint */
10936 
10937  if( upgdconsssize < 1 )
10938  {
10939  /* request larger upgdconss array */
10940  *nupgdconss = -1;
10941  return SCIP_OKAY;
10942  }
10943 
10944  *nupgdconss = 1;
10945  SCIP_CALL( SCIPcreateConsQuadratic(scip, &upgdconss[0], SCIPconsGetName(cons),
10947  0, NULL, 0, NULL,
10948  SCIPgetLhsNonlinear(scip, cons), SCIPgetRhsNonlinear(scip, cons),
10952  assert(!SCIPconsIsStickingAtNode(cons));
10953 
10954  exprgraph = SCIPgetExprgraphNonlinear(scip, SCIPconsGetHdlr(cons));
10955 
10956  /* add variables from expression tree as "quadratic" variables to quadratic constraint */
10957  for( i = 0; i < SCIPexprgraphGetNodeNChildren(node); ++i )
10958  {
10959  assert(SCIPexprgraphGetNodeChildren(node)[i] != NULL);
10960  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, upgdconss[0], (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[i]), 0.0, 0.0) );
10961  }
10962 
10963  switch( SCIPexprgraphGetNodeOperator(node) )
10964  {
10965  case SCIP_EXPR_MUL:
10966  /* expression is product of two variables, so add bilinear term to constraint */
10967  assert(SCIPexprgraphGetNodeNChildren(node) == 2);
10968 
10969  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, upgdconss[0],
10972  1.0) );
10973 
10974  break;
10975 
10976  case SCIP_EXPR_SQUARE:
10977  /* expression is square of a variable, so change square coefficient of quadratic variable */
10978  assert(SCIPexprgraphGetNodeNChildren(node) == 1);
10979 
10980  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, upgdconss[0],
10982  1.0) );
10983 
10984  break;
10985 
10986  case SCIP_EXPR_QUADRATIC:
10987  {
10988  /* expression is quadratic */
10989  SCIP_QUADELEM* quadelems;
10990  int nquadelems;
10991  SCIP_Real* lincoefs;
10992 
10994  nquadelems = SCIPexprgraphGetNodeQuadraticNQuadElements(node);
10996 
10998 
10999  if( lincoefs != NULL )
11000  for( i = 0; i < SCIPexprgraphGetNodeNChildren(node); ++i )
11001  if( lincoefs[i] != 0.0 )
11002  {
11003  /* linear term */
11004  SCIP_CALL( SCIPaddQuadVarLinearCoefQuadratic(scip, upgdconss[0],
11006  lincoefs[i]) );
11007  }
11008 
11009  for( i = 0; i < nquadelems; ++i )
11010  {
11011  assert(quadelems[i].idx1 < SCIPexprgraphGetNodeNChildren(node));
11012  assert(quadelems[i].idx2 < SCIPexprgraphGetNodeNChildren(node));
11013 
11014  if( quadelems[i].idx1 == quadelems[i].idx2 )
11015  {
11016  /* square term */
11017  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, upgdconss[0],
11018  (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[quadelems[i].idx1]),
11019  quadelems[i].coef) );
11020  }
11021  else
11022  {
11023  /* bilinear term */
11024  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, upgdconss[0],
11025  (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[quadelems[i].idx1]),
11026  (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[quadelems[i].idx2]),
11027  quadelems[i].coef) );
11028  }
11029  }
11030 
11031  break;
11032  }
11033 
11034  default:
11035  SCIPerrorMessage("you should not be here\n");
11036  return SCIP_ERROR;
11037  } /*lint !e788 */
11038 
11039  return SCIP_OKAY;
11040 }
11041 
11042 /*
11043  * Callback methods of constraint handler
11044  */
11045 
11046 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
11047 static
11048 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyQuadratic)
11049 { /*lint --e{715}*/
11050  assert(scip != NULL);
11051  assert(conshdlr != NULL);
11052  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
11053 
11054  /* call inclusion method of constraint handler */
11056 
11057  *valid = TRUE;
11058 
11059  return SCIP_OKAY;
11060 }
11061 
11062 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
11063 static
11064 SCIP_DECL_CONSFREE(consFreeQuadratic)
11066  SCIP_CONSHDLRDATA* conshdlrdata;
11067  int i;
11068 
11069  assert(scip != NULL);
11070  assert(conshdlr != NULL);
11071 
11072  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11073  assert(conshdlrdata != NULL);
11074 
11075  for( i = 0; i < conshdlrdata->nquadconsupgrades; ++i )
11076  {
11077  assert(conshdlrdata->quadconsupgrades[i] != NULL);
11078  SCIPfreeBlockMemory(scip, &conshdlrdata->quadconsupgrades[i]); /*lint !e866*/
11079  }
11080  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->quadconsupgrades, conshdlrdata->quadconsupgradessize);
11081 
11082  SCIPfreeBlockMemory(scip, &conshdlrdata);
11083 
11084  return SCIP_OKAY;
11085 }
11086 
11087 /** initialization method of constraint handler (called after problem was transformed) */
11088 static
11089 SCIP_DECL_CONSINIT(consInitQuadratic)
11090 { /*lint --e{715} */
11091  SCIP_CONSHDLRDATA* conshdlrdata;
11092 
11093  assert(scip != NULL);
11094  assert(conshdlr != NULL);
11095 
11096  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11097  assert(conshdlrdata != NULL);
11098 
11099  conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
11100  conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
11101 
11102  return SCIP_OKAY;
11103 }
11104 
11105 
11106 /** deinitialization method of constraint handler (called before transformed problem is freed) */
11107 static
11108 SCIP_DECL_CONSEXIT(consExitQuadratic)
11109 { /*lint --e{715} */
11110  SCIP_CONSHDLRDATA* conshdlrdata;
11111 
11112  assert(scip != NULL);
11113  assert(conshdlr != NULL);
11114 
11115  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11116  assert(conshdlrdata != NULL);
11117 
11118  conshdlrdata->subnlpheur = NULL;
11119  conshdlrdata->trysolheur = NULL;
11120 
11121  return SCIP_OKAY;
11122 }
11123 
11124 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
11125 #if 0
11126 static
11127 SCIP_DECL_CONSINITPRE(consInitpreQuadratic)
11128 { /*lint --e{715}*/
11129  SCIP_CONSHDLRDATA* conshdlrdata;
11130  SCIP_CONSDATA* consdata;
11131  int c;
11132 
11133  assert(scip != NULL);
11134  assert(conshdlr != NULL);
11135  assert(conss != NULL || nconss == 0);
11136 
11137  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11138  assert(conshdlrdata != NULL);
11139 
11140  return SCIP_OKAY;
11141 }
11142 #endif
11143 
11144 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
11145 static
11146 SCIP_DECL_CONSEXITPRE(consExitpreQuadratic)
11147 { /*lint --e{715}*/
11148  SCIP_CONSDATA* consdata;
11149  int c;
11150 #ifndef NDEBUG
11151  int i;
11152 #endif
11153 
11154  assert(scip != NULL);
11155  assert(conshdlr != NULL);
11156  assert(conss != NULL || nconss == 0);
11157 
11158  for( c = 0; c < nconss; ++c )
11159  {
11160  assert(conss != NULL);
11161  consdata = SCIPconsGetData(conss[c]);
11162  assert(consdata != NULL);
11163 
11164  if( !consdata->isremovedfixings )
11165  {
11166  SCIP_CALL( removeFixedVariables(scip, conss[c]) );
11167  }
11168 
11169  /* make sure we do not have duplicate bilinear terms, quad var terms, or linear vars */
11170  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
11171  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
11172  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
11173 
11174  assert(consdata->isremovedfixings);
11175  assert(consdata->linvarsmerged);
11176  assert(consdata->quadvarsmerged);
11177  assert(consdata->bilinmerged);
11178 
11179 #ifndef NDEBUG
11180  for( i = 0; i < consdata->nlinvars; ++i )
11181  assert(SCIPvarIsActive(consdata->linvars[i]));
11182 
11183  for( i = 0; i < consdata->nquadvars; ++i )
11184  assert(SCIPvarIsActive(consdata->quadvarterms[i].var));
11185 #endif
11186 
11187  /* tell SCIP that we have something nonlinear */
11188  if( SCIPconsIsAdded(conss[c]) && consdata->nquadvars > 0 )
11189  SCIPenableNLP(scip);
11190  }
11191 
11192  return SCIP_OKAY;
11193 }
11194 
11195 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin)
11196  *
11197  * @note Also called from consEnableQuadratic during solving stage.
11198  */
11199 static
11200 SCIP_DECL_CONSINITSOL(consInitsolQuadratic)
11202  SCIP_CONSHDLRDATA* conshdlrdata;
11203  SCIP_CONSDATA* consdata;
11204  int c;
11205  int i;
11206 
11207  assert(scip != NULL);
11208  assert(conshdlr != NULL);
11209  assert(conss != NULL || nconss == 0);
11210 
11211  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11212  assert(conshdlrdata != NULL);
11213 
11214  for( c = 0; c < nconss; ++c )
11215  {
11216  assert(conss != NULL);
11217  consdata = SCIPconsGetData(conss[c]);
11218  assert(consdata != NULL);
11219 
11220  /* check for a linear variable that can be increase or decreased without harming feasibility */
11221  consdataFindUnlockedLinearVar(scip, consdata);
11222 
11223  /* setup lincoefsmin, lincoefsmax */
11224  consdata->lincoefsmin = SCIPinfinity(scip);
11225  consdata->lincoefsmax = 0.0;
11226  for( i = 0; i < consdata->nlinvars; ++i )
11227  {
11228  consdata->lincoefsmin = MIN(consdata->lincoefsmin, REALABS(consdata->lincoefs[i])); /*lint !e666 */
11229  consdata->lincoefsmax = MAX(consdata->lincoefsmax, REALABS(consdata->lincoefs[i])); /*lint !e666 */
11230  }
11231 
11232  /* add nlrow representation to NLP, if NLP had been constructed */
11233  if( SCIPisNLPConstructed(scip) && SCIPconsIsEnabled(conss[c]) )
11234  {
11235  if( consdata->nlrow == NULL )
11236  {
11237  /* compute curvature for the quadratic constraint if not done yet */
11238  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) );
11239 
11240  SCIP_CALL( createNlRow(scip, conss[c]) );
11241  assert(consdata->nlrow != NULL);
11242  }
11243  SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
11244  }
11245 
11246  /* setup sepaquadvars and sepabilinvar2pos */
11247  assert(consdata->sepaquadvars == NULL);
11248  assert(consdata->sepabilinvar2pos == NULL);
11249  if( consdata->nquadvars > 0 )
11250  {
11251  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->sepaquadvars, consdata->nquadvars) );
11252  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->sepabilinvar2pos, consdata->nbilinterms) );
11253 
11254  /* make sure, quadratic variable terms are sorted */
11255  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
11256 
11257  for( i = 0; i < consdata->nquadvars; ++i )
11258  consdata->sepaquadvars[i] = consdata->quadvarterms[i].var;
11259 
11260  for( i = 0; i < consdata->nbilinterms; ++i )
11261  {
11262  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->bilinterms[i].var2, &consdata->sepabilinvar2pos[i]) );
11263  }
11264  }
11265 
11266  if( conshdlrdata->checkfactorable )
11267  {
11268  /* check if constraint function is factorable, i.e., can be written as product of two linear functions */
11269  SCIP_CALL( checkFactorable(scip, conss[c]) );
11270  }
11271 
11272  /* compute gauge function using interior points per constraint, only when there are quadratic variables */
11273  if( conshdlrdata->gaugecuts && SCIPgetSubscipDepth(scip) == 0 && consdata->nquadvars > 0 )
11274  {
11275  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
11276  if( (consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
11277  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)) )
11278  {
11279  SCIP_CALL( computeGauge(scip, conshdlr, conss[c]) );
11280  }
11281  }
11282 
11283  /* compute eigendecomposition for convex quadratics */
11284  if( conshdlrdata->projectedcuts && SCIPgetSubscipDepth(scip) == 0 && consdata->nquadvars > 0 )
11285  {
11286  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
11287  if( (consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
11288  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)) )
11289  {
11290  SCIP_CALL( computeED(scip, conshdlr, conss[c]) );
11291  }
11292  }
11293 
11294  /* mark constraint for propagation */
11295  SCIP_CALL( SCIPmarkConsPropagate(scip, conss[c]) );
11296  consdata->ispropagated = FALSE;
11297  }
11298 
11299  if( SCIPgetStage(scip) != SCIP_STAGE_INITSOLVE )
11300  {
11301  /* if called from consEnableQuadratic, then don't do below */
11302  return SCIP_OKAY;
11303  }
11304 
11305  conshdlrdata->newsoleventfilterpos = -1;
11306  if( nconss != 0 && conshdlrdata->linearizeheursol )
11307  {
11308  SCIP_EVENTHDLR* eventhdlr;
11309 
11310  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
11311  assert(eventhdlr != NULL);
11312 
11313  /* @todo Should we catch every new solution or only new *best* solutions */
11314  SCIP_CALL( SCIPcatchEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
11315  }
11316 
11317  if( nconss != 0 && !SCIPisIpoptAvailableIpopt() && !SCIPisInRestart(scip) )
11318  {
11319  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");
11320  }
11321 
11322  /* reset flags and counters */
11323  conshdlrdata->sepanlp = FALSE;
11324  conshdlrdata->lastenfonode = NULL;
11325  conshdlrdata->nenforounds = 0;
11326 
11327  return SCIP_OKAY;
11328 }
11329 
11330 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed)
11331  *
11332  * @note Also called from consDisableQuadratic during solving stage.
11333  */
11334 static
11335 SCIP_DECL_CONSEXITSOL(consExitsolQuadratic)
11336 { /*lint --e{715}*/
11337  SCIP_CONSHDLRDATA* conshdlrdata;
11338  SCIP_CONSDATA* consdata;
11339  int c;
11340 
11341  assert(scip != NULL);
11342  assert(conshdlr != NULL);
11343  assert(conss != NULL || nconss == 0);
11344 
11345  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11346  assert(conshdlrdata != NULL);
11347 
11348  for( c = 0; c < nconss; ++c )
11349  {
11350  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
11351  assert(consdata != NULL);
11352 
11353  /* free nonlinear row representation */
11354  if( consdata->nlrow != NULL )
11355  {
11356  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
11357  }
11358 
11359  assert(!SCIPconsIsEnabled(conss[c]) || consdata->sepaquadvars != NULL || consdata->nquadvars == 0); /*lint !e613 */
11360  assert(!SCIPconsIsEnabled(conss[c]) || consdata->sepabilinvar2pos != NULL || consdata->nquadvars == 0); /*lint !e613 */
11361  SCIPfreeBlockMemoryArrayNull(scip, &consdata->sepaquadvars, consdata->nquadvars);
11362  SCIPfreeBlockMemoryArrayNull(scip, &consdata->sepabilinvar2pos, consdata->nbilinterms);
11363 
11364  SCIPfreeBlockMemoryArrayNull(scip, &consdata->factorleft, consdata->nquadvars + 1);
11365  SCIPfreeBlockMemoryArrayNull(scip, &consdata->factorright, consdata->nquadvars + 1);
11366 
11367  SCIPfreeBlockMemoryArrayNull(scip, &consdata->interiorpoint, consdata->nquadvars);
11368  SCIPfreeBlockMemoryArrayNull(scip, &consdata->gaugecoefs, consdata->nquadvars);
11369  SCIPfreeBlockMemoryArrayNull(scip, &consdata->eigenvalues, consdata->nquadvars);
11370  SCIPfreeBlockMemoryArrayNull(scip, &consdata->eigenvectors, (int)(consdata->nquadvars*consdata->nquadvars));
11371  SCIPfreeBlockMemoryArrayNull(scip, &consdata->bp, consdata->nquadvars);
11372  }
11373 
11374  if( SCIPgetStage(scip) != SCIP_STAGE_EXITSOLVE )
11375  {
11376  /* if called from consDisableQuadratic, then don't do below */
11377  return SCIP_OKAY;
11378  }
11379 
11380  if( conshdlrdata->newsoleventfilterpos >= 0 )
11381  {
11382  SCIP_EVENTHDLR* eventhdlr;
11383 
11384  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
11385  assert(eventhdlr != NULL);
11386 
11387  SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
11388  conshdlrdata->newsoleventfilterpos = -1;
11389  }
11390 
11391  return SCIP_OKAY;
11392 }
11393 
11394 /** frees specific constraint data */
11395 static
11396 SCIP_DECL_CONSDELETE(consDeleteQuadratic)
11398  assert(scip != NULL);
11399  assert(conshdlr != NULL);
11400  assert(cons != NULL);
11401  assert(consdata != NULL);
11402  assert(SCIPconsGetData(cons) == *consdata);
11403 
11404  SCIP_CALL( consdataFree(scip, consdata) );
11405 
11406  assert(*consdata == NULL);
11407 
11408  return SCIP_OKAY;
11409 }
11410 
11411 /** transforms constraint data into data belonging to the transformed problem */
11412 static
11413 SCIP_DECL_CONSTRANS(consTransQuadratic)
11414 {
11415  SCIP_CONSDATA* sourcedata;
11416  SCIP_CONSDATA* targetdata;
11417  int i;
11418 
11419  sourcedata = SCIPconsGetData(sourcecons);
11420  assert(sourcedata != NULL);
11421 
11422  SCIP_CALL( consdataCreate(scip, &targetdata,
11423  sourcedata->lhs, sourcedata->rhs,
11424  sourcedata->nlinvars, sourcedata->linvars, sourcedata->lincoefs,
11425  sourcedata->nquadvars, sourcedata->quadvarterms,
11426  sourcedata->nbilinterms, sourcedata->bilinterms,
11427  FALSE) );
11428 
11429  for( i = 0; i < targetdata->nlinvars; ++i )
11430  {
11431  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->linvars[i], &targetdata->linvars[i]) );
11432  SCIP_CALL( SCIPcaptureVar(scip, targetdata->linvars[i]) );
11433  }
11434 
11435  for( i = 0; i < targetdata->nquadvars; ++i )
11436  {
11437  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->quadvarterms[i].var, &targetdata->quadvarterms[i].var) );
11438  SCIP_CALL( SCIPcaptureVar(scip, targetdata->quadvarterms[i].var) );
11439  }
11440 
11441  for( i = 0; i < targetdata->nbilinterms; ++i )
11442  {
11443  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->bilinterms[i].var1, &targetdata->bilinterms[i].var1) );
11444  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->bilinterms[i].var2, &targetdata->bilinterms[i].var2) );
11445 
11446  if( SCIPvarCompare(targetdata->bilinterms[i].var1, targetdata->bilinterms[i].var2) > 0 )
11447  {
11448  SCIP_VAR* tmp;
11449  tmp = targetdata->bilinterms[i].var2;
11450  targetdata->bilinterms[i].var2 = targetdata->bilinterms[i].var1;
11451  targetdata->bilinterms[i].var1 = tmp;
11452  }
11453  }
11454 
11455  /* create target constraint */
11456  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
11457  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
11458  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
11459  SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons),
11460  SCIPconsIsStickingAtNode(sourcecons)) );
11461 
11462  SCIPdebugMsg(scip, "created transformed quadratic constraint ");
11463  SCIPdebugPrintCons(scip, *targetcons, NULL);
11464 
11465  return SCIP_OKAY;
11466 }
11467 
11468 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
11469 static
11470 SCIP_DECL_CONSINITLP(consInitlpQuadratic)
11472  SCIP_CONSHDLRDATA* conshdlrdata;
11473  SCIP_CONSDATA* consdata;
11474  SCIP_VAR* var;
11475  SCIP_ROW* row;
11476  SCIP_Real* x;
11477  int c;
11478  int i;
11479 
11480  assert(scip != NULL);
11481  assert(conshdlr != NULL);
11482  assert(conss != NULL || nconss == 0);
11483 
11484  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11485  assert(conshdlrdata != NULL);
11486 
11487  *infeasible = FALSE;
11488 
11489  for( c = 0; c < nconss && !(*infeasible); ++c )
11490  {
11491  assert(conss[c] != NULL); /*lint !e613 */
11492 
11493  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
11494 
11495  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
11496  assert(consdata != NULL);
11497 
11498  row = NULL;
11499 
11500  if( consdata->nquadvars == 0 )
11501  {
11502  /* if we are actually linear, add the constraint as row to the LP */
11503  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(conss[c]), SCIPconsGetName(conss[c]), consdata->lhs, consdata->rhs,
11504  SCIPconsIsLocal(conss[c]), FALSE , TRUE) ); /*lint !e613 */
11505  SCIP_CALL( SCIPaddVarsToRow(scip, row, consdata->nlinvars, consdata->linvars, consdata->lincoefs) );
11506  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, infeasible) );
11507  SCIP_CALL( SCIPreleaseRow (scip, &row) );
11508  continue;
11509  }
11510 
11511  /* alloc memory for reference point */
11512  SCIP_CALL( SCIPallocBufferArray(scip, &x, consdata->nquadvars) );
11513 
11514  /* for convex parts, add linearizations in 5 points */
11515  if( (consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
11516  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)) )
11517  {
11518  SCIP_Real lb;
11519  SCIP_Real ub;
11520  SCIP_Real lambda;
11521  int k;
11522 
11523  for( k = 0; k < 5; ++k )
11524  {
11525  lambda = 0.1 * (k+1); /* lambda = 0.1, 0.2, 0.3, 0.4, 0.5 */
11526  for( i = 0; i < consdata->nquadvars; ++i )
11527  {
11528  var = consdata->quadvarterms[i].var;
11529  lb = SCIPvarGetLbGlobal(var);
11530  ub = SCIPvarGetUbGlobal(var);
11531 
11532  if( ub > -INITLPMAXVARVAL )
11533  lb = MAX(lb, -INITLPMAXVARVAL);
11534  if( lb < INITLPMAXVARVAL )
11535  ub = MIN(ub, INITLPMAXVARVAL);
11536 
11537  /* make bounds finite */
11538  if( SCIPisInfinity(scip, -lb) )
11539  lb = MIN(-10.0, ub - 0.1*REALABS(ub)); /*lint !e666 */
11540  if( SCIPisInfinity(scip, ub) )
11541  ub = MAX( 10.0, lb + 0.1*REALABS(lb)); /*lint !e666 */
11542 
11544  x[i] = lambda * ub + (1.0 - lambda) * lb;
11545  else
11546  x[i] = lambda * lb + (1.0 - lambda) * ub;
11547  }
11548 
11549  SCIP_CALL( generateCut(scip, conshdlr, conss[c], x, NULL, consdata->isconvex ? SCIP_SIDETYPE_RIGHT : SCIP_SIDETYPE_LEFT, &row, NULL,
11550  FALSE, -SCIPinfinity(scip)) ); /*lint !e613 */
11551  if( row != NULL )
11552  {
11553  SCIPdebugMsg(scip, "initlp adds row <%s> for lambda = %g of conss <%s>\n", SCIProwGetName(row), lambda, SCIPconsGetName(conss[c])); /*lint !e613 */
11554  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
11555 
11556  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, infeasible) );
11557  SCIP_CALL( SCIPreleaseRow (scip, &row) );
11558  }
11559  }
11560  }
11561 
11562  /* for concave parts, add underestimator w.r.t. at most 2 reference points */
11563  if( !(*infeasible) && ((! consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs))
11564  || (! consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs))) )
11565  {
11566  SCIP_Bool unbounded;
11567  SCIP_Bool possquare;
11568  SCIP_Bool negsquare;
11569  SCIP_Real lb;
11570  SCIP_Real ub;
11571  SCIP_Real lambda;
11572  int k;
11573 
11574  unbounded = FALSE; /* whether there are unbounded variables */
11575  possquare = FALSE; /* whether there is a positive square term */
11576  negsquare = FALSE; /* whether there is a negative square term */
11577  for( k = 0; k < 2; ++k )
11578  {
11579  /* Set reference point to 0 projected on bounds for unbounded variables or in between lower and upper bound
11580  * for bounded variables in the first round, we set it closer to the best bound for one part of the
11581  * variables, in the second closer to the best bound for the other part of the variables.
11582  * Additionally, we use slightly different weights for each variable.
11583  * The reason for the latter is, that for a bilinear term with bounded variables, there are always two linear underestimators
11584  * if the same weight is used for both variables of a product, then rounding and luck decides which underestimator is chosen
11585  * of course, the possible number of cuts is something in the order of 2^nquadvars, and we choose two of them here.
11586  */
11587  for( i = 0; i < consdata->nquadvars; ++i )
11588  {
11589  var = consdata->quadvarterms[i].var;
11590  lb = SCIPvarGetLbGlobal(var);
11591  ub = SCIPvarGetUbGlobal(var);
11592 
11593  if( SCIPisInfinity(scip, -lb) )
11594  {
11595  if( SCIPisInfinity(scip, ub) )
11596  x[i] = 0.0;
11597  else
11598  x[i] = MIN(0.0, ub);
11599  unbounded = TRUE;
11600  }
11601  else
11602  {
11603  if( SCIPisInfinity(scip, ub) )
11604  {
11605  x[i] = MAX(0.0, lb);
11606  unbounded = TRUE;
11607  }
11608  else
11609  {
11610  lambda = 0.4 + 0.2 * ((i+k)%2) + 0.01 * i / (double)consdata->nquadvars;
11611  x[i] = lambda * SCIPvarGetBestBoundLocal(var) + (1.0-lambda) * SCIPvarGetWorstBoundLocal(var);
11612  }
11613  }
11614 
11615  possquare |= consdata->quadvarterms[i].sqrcoef > 0.0; /*lint !e514 */
11616  negsquare |= consdata->quadvarterms[i].sqrcoef < 0.0; /*lint !e514 */
11617  }
11618 
11619  if( !consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs) )
11620  {
11621  SCIP_CALL( generateCut(scip, conshdlr, conss[c], x, NULL, SCIP_SIDETYPE_RIGHT, &row, NULL,
11622  conshdlrdata->checkcurvature, -SCIPinfinity(scip)) ); /*lint !e613 */
11623  if( row != NULL )
11624  {
11625  SCIPdebugMsg(scip, "initlp adds row <%s> for rhs of conss <%s>, round %d\n", SCIProwGetName(row), SCIPconsGetName(conss[c]), k); /*lint !e613 */
11626  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
11627 
11628  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, infeasible) );
11629  SCIP_CALL( SCIPreleaseRow (scip, &row) );
11630  }
11631  }
11632  if( !(*infeasible) && !consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs) )
11633  {
11634  SCIP_CALL( generateCut(scip, conshdlr, conss[c], x, NULL, SCIP_SIDETYPE_LEFT, &row, NULL,
11635  conshdlrdata->checkcurvature, -SCIPinfinity(scip)) ); /*lint !e613 */
11636  if( row != NULL )
11637  {
11638  SCIPdebugMsg(scip, "initlp adds row <%s> for lhs of conss <%s>, round %d\n", SCIProwGetName(row), SCIPconsGetName(conss[c]), k); /*lint !e613 */
11639  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
11640 
11641  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, infeasible) );
11642  SCIP_CALL( SCIPreleaseRow (scip, &row) );
11643  }
11644  }
11645 
11646  /* if there are unbounded variables, then there is typically only at most one possible underestimator, so don't try another round
11647  * 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 */
11648  if( unbounded ||
11649  (consdata->nbilinterms == 0 && (!possquare || SCIPisInfinity(scip, consdata->rhs))) ||
11650  (consdata->nbilinterms == 0 && (!negsquare || SCIPisInfinity(scip, -consdata->lhs))) )
11651  break;
11652  }
11653  }
11654 
11655  SCIPfreeBufferArray(scip, &x);
11656  }
11657 
11658  return SCIP_OKAY;
11659 }
11660 
11661 /** separation method of constraint handler for LP solutions */
11662 static
11663 SCIP_DECL_CONSSEPALP(consSepalpQuadratic)
11664 {
11665  SCIP_CONSHDLRDATA* conshdlrdata;
11666  SCIP_Bool solviolbounds;
11667  SCIP_CONS* maxviolcon;
11668 
11669  assert(scip != NULL);
11670  assert(conshdlr != NULL);
11671  assert(conss != NULL || nconss == 0);
11672  assert(result != NULL);
11673 
11674  *result = SCIP_DIDNOTFIND;
11675 
11676  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11677  assert(conshdlrdata != NULL);
11678 
11679  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &solviolbounds, &maxviolcon) );
11680 
11681  /* don't try to separate solutions that violate variable bounds */
11682  if( solviolbounds )
11683  return SCIP_OKAY;
11684 
11685  /* if nothing violated, then nothing to separate */
11686  if( maxviolcon == NULL )
11687  return SCIP_OKAY;
11688 
11689  /* at root, check if we want to solve the NLP relaxation and use its solutions as reference point
11690  * if there is something convex, then linearizing in the solution of the NLP relaxation can be very useful
11691  */
11692  if( SCIPgetDepth(scip) == 0 && !conshdlrdata->sepanlp &&
11693  (SCIPgetNContVars(scip) >= conshdlrdata->sepanlpmincont * SCIPgetNVars(scip) ||
11694  (SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY && conshdlrdata->sepanlpmincont <= 1.0)) &&
11695  SCIPisNLPConstructed(scip) && SCIPgetNNlpis(scip) > 0 )
11696  {
11697  SCIP_CONSDATA* consdata;
11698  SCIP_NLPSOLSTAT solstat;
11699  SCIP_Bool solvednlp;
11700  int c;
11701 
11702  solstat = SCIPgetNLPSolstat(scip);
11703  solvednlp = FALSE;
11704  if( solstat == SCIP_NLPSOLSTAT_UNKNOWN )
11705  {
11706  /* NLP is not solved yet, so we might want to do this
11707  * but first check whether there is a violated constraint side which corresponds to a convex function
11708  */
11709  for( c = 0; c < nconss; ++c )
11710  {
11711  assert(conss[c] != NULL); /*lint !e613 */
11712 
11713  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
11714  assert(consdata != NULL);
11715 
11716  /* skip feasible constraints */
11717  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
11718  continue;
11719 
11720  /* make sure curvature has been checked */
11721  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
11722 
11723  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && consdata->isconvex) ||
11724  ( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && consdata->isconcave) )
11725  break;
11726  }
11727 
11728  if( c < nconss )
11729  {
11730  /* try to solve NLP and update solstat */
11731 
11732  /* ensure linear conss are in NLP */
11733  if( conshdlrdata->subnlpheur != NULL )
11734  {
11735  SCIP_CALL( SCIPaddLinearConsToNlpHeurSubNlp(scip, conshdlrdata->subnlpheur, TRUE, TRUE) );
11736  }
11737 
11738  /* set LP solution as starting values, if available */
11740  {
11742  }
11743 
11744  /* SCIP_CALL( SCIPsetNLPIntPar(scip, SCIP_NLPPAR_VERBLEVEL, 1) ); */
11745  SCIP_CALL( SCIPsolveNLP(scip) );
11746 
11747  solstat = SCIPgetNLPSolstat(scip);
11748  SCIPdebugMsg(scip, "solved NLP relax, solution status: %d\n", solstat);
11749 
11750  solvednlp = TRUE;
11751  }
11752  }
11753 
11754  conshdlrdata->sepanlp = TRUE;
11755 
11756  if( solstat == SCIP_NLPSOLSTAT_GLOBINFEASIBLE )
11757  {
11758  SCIPdebugMsg(scip, "NLP relaxation is globally infeasible, thus can cutoff node\n");
11759  *result = SCIP_CUTOFF;
11760  return SCIP_OKAY;
11761  }
11762 
11763  if( solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
11764  {
11765  /* if we have feasible NLP solution, generate linearization cuts there */
11766  SCIP_Bool lpsolseparated;
11767  SCIP_SOL* nlpsol;
11768 
11769  SCIP_CALL( SCIPcreateNLPSol(scip, &nlpsol, NULL) );
11770  assert(nlpsol != NULL);
11771 
11772  /* if we solved the NLP and solution is integral, then pass it to trysol heuristic */
11773  if( solvednlp && conshdlrdata->trysolheur != NULL )
11774  {
11775  int nfracvars;
11776 
11777  nfracvars = 0;
11778  if( SCIPgetNBinVars(scip) > 0 || SCIPgetNIntVars(scip) > 0 )
11779  {
11780  SCIP_CALL( SCIPgetNLPFracVars(scip, NULL, NULL, NULL, &nfracvars, NULL) );
11781  }
11782 
11783  if( nfracvars == 0 )
11784  {
11785  SCIPdebugMsg(scip, "pass solution with obj. value %g to trysol\n", SCIPgetSolOrigObj(scip, nlpsol));
11786  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, nlpsol) );
11787  }
11788  }
11789 
11790  SCIP_CALL( addLinearizationCuts(scip, conshdlr, conss, nconss, nlpsol, &lpsolseparated, conshdlrdata->mincutefficacysepa) );
11791 
11792  SCIP_CALL( SCIPfreeSol(scip, &nlpsol) );
11793 
11794  /* if a cut that separated the LP solution was added, then return, otherwise continue with usual separation in LP solution */
11795  if( lpsolseparated )
11796  {
11797  SCIPdebugMsg(scip, "linearization cuts separate LP solution\n");
11798  *result = SCIP_SEPARATED;
11799 
11800  return SCIP_OKAY;
11801  }
11802  }
11803  }
11804  /* if we do not want to try solving the NLP, or have no NLP, or have no NLP solver, or solving the NLP failed,
11805  * or separating with NLP solution as reference point failed, then try (again) with LP solution as reference point
11806  */
11807 
11808  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, NULL, conshdlrdata->mincutefficacysepa, FALSE, result, NULL) );
11809 
11810  return SCIP_OKAY;
11811 }
11812 
11813 /** separation method of constraint handler for arbitrary primal solutions */
11814 static
11815 SCIP_DECL_CONSSEPASOL(consSepasolQuadratic)
11817  SCIP_CONSHDLRDATA* conshdlrdata;
11818  SCIP_Bool solviolbounds;
11819  SCIP_CONS* maxviolcon;
11820 
11821  assert(scip != NULL);
11822  assert(conshdlr != NULL);
11823  assert(conss != NULL || nconss == 0);
11824  assert(sol != NULL);
11825  assert(result != NULL);
11826 
11827  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11828  assert(conshdlrdata != NULL);
11829 
11830  *result = SCIP_DIDNOTFIND;
11831 
11832  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, sol, &solviolbounds, &maxviolcon) );
11833 
11834  /* don't separate solution that are outside variable bounds */
11835  if( solviolbounds )
11836  return SCIP_OKAY;
11837 
11838  /* if nothing violated, then nothing to separate */
11839  if( maxviolcon == NULL )
11840  return SCIP_OKAY;
11841 
11842  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, conshdlrdata->mincutefficacysepa, FALSE, result, NULL) );
11843 
11844  return SCIP_OKAY;
11845 }
11846 
11847 /** constraint enforcing method of constraint handler for LP solutions */
11848 static
11849 SCIP_DECL_CONSENFOLP(consEnfolpQuadratic)
11850 { /*lint --e{715}*/
11851  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, solinfeasible, result) );
11852 
11853  return SCIP_OKAY;
11854 }
11855 
11856 /** constraint enforcing method of constraint handler for relaxation solutions */
11857 static
11858 SCIP_DECL_CONSENFORELAX(consEnforelaxQuadratic)
11859 { /*lint --e{715}*/
11860  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, solinfeasible, result) );
11861 
11862  return SCIP_OKAY;
11863 }
11864 
11865 /** constraint enforcing method of constraint handler for pseudo solutions */
11866 static
11867 SCIP_DECL_CONSENFOPS(consEnfopsQuadratic)
11868 { /*lint --e{715}*/
11869  SCIP_Bool solviolbounds;
11870  SCIP_CONS* maxviolcon;
11871  SCIP_CONSDATA* consdata;
11872  SCIP_RESULT propresult;
11873  SCIP_VAR* var;
11874  int c;
11875  int i;
11876  int nchgbds;
11877  int nnotify;
11878 
11879  assert(scip != NULL);
11880  assert(conss != NULL || nconss == 0);
11881 
11882  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &solviolbounds, &maxviolcon) );
11883 
11884  /* pseudo solutions should be within bounds by definition */
11885  assert(!solviolbounds);
11886 
11887  if( maxviolcon == NULL )
11888  {
11889  *result = SCIP_FEASIBLE;
11890  return SCIP_OKAY;
11891  }
11892 
11893  *result = SCIP_INFEASIBLE;
11894 
11895  SCIPdebugMsg(scip, "enfops with max violation in cons <%s>\n", SCIPconsGetName(maxviolcon));
11896 
11897  /* run domain propagation */
11898  nchgbds = 0;
11899  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, &propresult, &nchgbds) );
11900  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
11901  {
11902  *result = propresult;
11903  return SCIP_OKAY;
11904  }
11905 
11906  /* we are not feasible and we cannot proof that the whole node is infeasible
11907  * -> collect all variables in violated constraints for branching
11908  */
11909  nnotify = 0;
11910  for( c = 0; c < nconss; ++c )
11911  {
11912  assert(conss != NULL);
11913  consdata = SCIPconsGetData(conss[c]);
11914  assert(consdata != NULL);
11915 
11916  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
11917  continue;
11918 
11919  for( i = 0; i < consdata->nlinvars; ++i )
11920  {
11921  var = consdata->linvars[i];
11922  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
11923  {
11924  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
11925  ++nnotify;
11926  }
11927  }
11928 
11929  for( i = 0; i < consdata->nquadvars; ++i )
11930  {
11931  var = consdata->quadvarterms[i].var;
11932  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
11933  {
11934  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
11935  ++nnotify;
11936  }
11937  }
11938  }
11939 
11940  if( nnotify == 0 )
11941  {
11942  SCIPdebugMsg(scip, "All variables in violated constraints fixed (up to epsilon). Cannot find branching candidate. Forcing solution of LP.\n");
11943  *result = SCIP_SOLVELP;
11944  }
11945 
11946  assert(*result == SCIP_SOLVELP || (*result == SCIP_INFEASIBLE && nnotify > 0));
11947  return SCIP_OKAY;
11948 }
11949 
11950 /** domain propagation method of constraint handler */
11951 static
11952 SCIP_DECL_CONSPROP(consPropQuadratic)
11954  int nchgbds;
11955 
11956  assert(scip != NULL);
11957  assert(conshdlr != NULL);
11958  assert(conss != NULL || nconss == 0);
11959  assert(result != NULL);
11960 
11961  nchgbds = 0;
11962  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nmarkedconss, result, &nchgbds) );
11963 
11964  return SCIP_OKAY;
11965 } /*lint !e715 */
11966 
11967 /** presolving method of constraint handler */
11968 static
11969 SCIP_DECL_CONSPRESOL(consPresolQuadratic)
11970 { /*lint --e{715,788}*/
11971  SCIP_CONSHDLRDATA* conshdlrdata;
11972  SCIP_CONSDATA* consdata;
11973  SCIP_RESULT solveresult;
11974  SCIP_Bool redundant;
11975  SCIP_Bool havechange;
11976  SCIP_Bool doreformulations;
11977  int c;
11978  int i;
11979 
11980  assert(scip != NULL);
11981  assert(conshdlr != NULL);
11982  assert(conss != NULL || nconss == 0);
11983  assert(result != NULL);
11984 
11985  *result = SCIP_DIDNOTFIND;
11986 
11987  /* if other presolvers did not find enough changes for another presolving round,
11988  * then try the reformulations (replacing products with binaries, disaggregation, setting default variable bounds)
11989  * otherwise, we wait with these
11990  * @todo first do all usual presolving steps, then check SCIPisPresolveFinished(scip), and if true then do reformulations (and usual steps again)
11991  */
11992  doreformulations = nrounds > 0 && ((presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 || SCIPisPresolveFinished(scip));
11993  SCIPdebugMsg(scip, "presolving will %swait with reformulation\n", doreformulations ? "not " : "");
11994 
11995  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11996  assert(conshdlrdata != NULL);
11997 
11998  for( c = 0; c < nconss; ++c )
11999  {
12000  assert(conss != NULL);
12001  consdata = SCIPconsGetData(conss[c]);
12002  assert(consdata != NULL);
12003 
12004  SCIPdebugMsg(scip, "process constraint <%s>\n", SCIPconsGetName(conss[c]));
12005  SCIPdebugPrintCons(scip, conss[c], NULL);
12006 
12007  if( !consdata->initialmerge )
12008  {
12009  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
12010  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
12011  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
12012  consdata->initialmerge = TRUE;
12013  }
12014 
12015  havechange = FALSE;
12016 #ifdef CHECKIMPLINBILINEAR
12017  if( consdata->isimpladded && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
12018  {
12019  int nbilinremoved;
12020  SCIP_CALL( presolveApplyImplications(scip, conss[c], &nbilinremoved) );
12021  if( nbilinremoved > 0 )
12022  {
12023  *nchgcoefs += nbilinremoved;
12024  havechange = TRUE;
12025  *result = SCIP_SUCCESS;
12026  }
12027  assert(!consdata->isimpladded);
12028  }
12029 #endif
12030  /* 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
12031  * we want to do this before (multi)aggregated variables are replaced, since that may change structure, e.g., introduce bilinear terms
12032  */
12033  if( !consdata->ispresolved || !consdata->ispropagated || nnewchgvartypes > 0 )
12034  {
12035  SCIP_Bool upgraded;
12036 
12037  SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss, presoltiming) );
12038  if( upgraded )
12039  {
12040  *result = SCIP_SUCCESS;
12041  continue;
12042  }
12043  }
12044 
12045  if( !consdata->isremovedfixings )
12046  {
12047  SCIP_CALL( removeFixedVariables(scip, conss[c]) );
12048  assert(consdata->isremovedfixings);
12049  havechange = TRUE;
12050  }
12051 
12052  /* try to "solve" the constraint, e.g., reduce to a variable aggregation */
12053  SCIP_CALL( presolveSolve(scip, conss[c], &solveresult, &redundant, naggrvars) );
12054  if( solveresult == SCIP_CUTOFF )
12055  {
12056  SCIPdebugMsg(scip, "solving constraint <%s> says problem is infeasible in presolve\n", SCIPconsGetName(conss[c]));
12057  *result = SCIP_CUTOFF;
12058  return SCIP_OKAY;
12059  }
12060  if( redundant )
12061  {
12062  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
12063  ++*ndelconss;
12064  *result = SCIP_SUCCESS;
12065  break;
12066  }
12067  if( solveresult == SCIP_SUCCESS )
12068  {
12069  *result = SCIP_SUCCESS;
12070  havechange = TRUE;
12071  }
12072 
12073  /* @todo divide constraint by gcd of coefficients if all are integral */
12074 
12075  if( doreformulations )
12076  {
12077  int naddconss_old;
12078 
12079  naddconss_old = *naddconss;
12080 
12081  SCIP_CALL( presolveTryAddAND(scip, conshdlr, conss[c], naddconss) );
12082  assert(*naddconss >= naddconss_old);
12083 
12084  if( *naddconss == naddconss_old )
12085  {
12086  /* user not so empathic about AND, or we don't have products of two binaries, so try this more general reformulation */
12087  SCIP_CALL( presolveTryAddLinearReform(scip, conshdlr, conss[c], naddconss) );
12088  assert(*naddconss >= naddconss_old);
12089  }
12090 
12091  if( conshdlrdata->disaggregate )
12092  {
12093  /* try disaggregation, if enabled */
12094  SCIP_CALL( presolveDisaggregate(scip, conshdlr, conss[c], naddconss) );
12095  }
12096 
12097  if( *naddconss > naddconss_old )
12098  {
12099  /* if something happened, report success and cleanup constraint */
12100  *result = SCIP_SUCCESS;
12101  havechange = TRUE;
12102  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
12103  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
12104  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
12105  }
12106  }
12107 
12108  if( consdata->nlinvars == 0 && consdata->nquadvars == 0 )
12109  {
12110  /* all variables fixed or removed, constraint function is 0.0 now */
12111  if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasPositive(scip, consdata->lhs)) ||
12112  ( !SCIPisInfinity(scip, consdata->rhs) && SCIPisFeasNegative(scip, consdata->rhs)) )
12113  { /* left hand side positive or right hand side negative */
12114  SCIPdebugMsg(scip, "constraint <%s> is constant and infeasible\n", SCIPconsGetName(conss[c]));
12115  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
12116  ++*ndelconss;
12117  *result = SCIP_CUTOFF;
12118  return SCIP_OKAY;
12119  }
12120 
12121  /* left and right hand side are consistent */
12122  SCIPdebugMsg(scip, "constraint <%s> is constant and feasible, deleting\n", SCIPconsGetName(conss[c]));
12123  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
12124  ++*ndelconss;
12125  *result = SCIP_SUCCESS;
12126  continue;
12127  }
12128 
12129  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 && !consdata->ispropagated )
12130  {
12131  /* try domain propagation if there were bound changes or constraint has changed (in which case, processVarEvents may have set ispropagated to false) */
12132  SCIP_RESULT propresult;
12133  int roundnr;
12134 
12135  roundnr = 0;
12136  do
12137  {
12138  ++roundnr;
12139 
12140  SCIPdebugMsg(scip, "starting domain propagation round %d of %d\n", roundnr, conshdlrdata->maxproproundspresolve);
12141 
12142  if( !consdata->ispropagated )
12143  {
12144  consdata->ispropagated = TRUE;
12145 
12146  SCIP_CALL( propagateBoundsCons(scip, conshdlr, conss[c], &propresult, nchgbds, &redundant) );
12147 
12148  if( propresult == SCIP_CUTOFF )
12149  {
12150  SCIPdebugMsg(scip, "propagation on constraint <%s> says problem is infeasible in presolve\n",
12151  SCIPconsGetName(conss[c]));
12152  *result = SCIP_CUTOFF;
12153  return SCIP_OKAY;
12154  }
12155 
12156  /* delete constraint if found redundant by bound tightening */
12157  if( redundant )
12158  {
12159  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
12160  ++*ndelconss;
12161  *result = SCIP_SUCCESS;
12162  break;
12163  }
12164 
12165  if( propresult == SCIP_REDUCEDDOM )
12166  {
12167  *result = SCIP_SUCCESS;
12168  havechange = TRUE;
12169  }
12170  }
12171  }
12172  while( !consdata->ispropagated && roundnr < conshdlrdata->maxproproundspresolve );
12173 
12174  if( redundant )
12175  continue;
12176  }
12177 
12178  /* check if we have a single linear continuous variable that we can make implicit integer */
12179  if( (nnewchgvartypes != 0 || havechange || !consdata->ispresolved)
12180  && (SCIPisEQ(scip, consdata->lhs, consdata->rhs) && SCIPisIntegral(scip, consdata->lhs)) )
12181  {
12182  int ncontvar;
12183  SCIP_VAR* candidate;
12184  SCIP_Bool fail;
12185 
12186  fail = FALSE;
12187  candidate = NULL;
12188  ncontvar = 0;
12189 
12190  for( i = 0; !fail && i < consdata->nlinvars; ++i )
12191  {
12192  if( !SCIPisIntegral(scip, consdata->lincoefs[i]) )
12193  {
12194  fail = TRUE;
12195  }
12196  else if( SCIPvarGetType(consdata->linvars[i]) == SCIP_VARTYPE_CONTINUOUS )
12197  {
12198  if( ncontvar > 0 ) /* now at 2nd continuous variable */
12199  fail = TRUE;
12200  else if( SCIPisEQ(scip, ABS(consdata->lincoefs[i]), 1.0) )
12201  candidate = consdata->linvars[i];
12202  ++ncontvar;
12203  }
12204  }
12205  for( i = 0; !fail && i < consdata->nquadvars; ++i )
12206  fail = SCIPvarGetType(consdata->quadvarterms[i].var) == SCIP_VARTYPE_CONTINUOUS ||
12207  !SCIPisIntegral(scip, consdata->quadvarterms[i].lincoef) ||
12208  !SCIPisIntegral(scip, consdata->quadvarterms[i].sqrcoef);
12209  for( i = 0; !fail && i < consdata->nbilinterms; ++i )
12210  fail = !SCIPisIntegral(scip, consdata->bilinterms[i].coef);
12211 
12212  if( !fail && candidate != NULL )
12213  {
12214  SCIP_Bool infeasible;
12215 
12216  SCIPdebugMsg(scip, "make variable <%s> implicit integer due to constraint <%s>\n", SCIPvarGetName(candidate), SCIPconsGetName(conss[c]));
12217 
12218  SCIP_CALL( SCIPchgVarType(scip, candidate, SCIP_VARTYPE_IMPLINT, &infeasible) );
12219  if( infeasible )
12220  {
12221  SCIPdebugMsg(scip, "infeasible upgrade of variable <%s> to integral type, domain is empty\n", SCIPvarGetName(candidate));
12222  *result = SCIP_CUTOFF;
12223 
12224  return SCIP_OKAY;
12225  }
12226 
12227  ++(*nchgvartypes);
12228  *result = SCIP_SUCCESS;
12229  havechange = TRUE;
12230  }
12231  }
12232 
12233  /* call upgrade methods again if constraint has been changed */
12234  if( havechange )
12235  {
12236  SCIP_Bool upgraded;
12237 
12238  SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss, presoltiming) );
12239  if( upgraded )
12240  {
12241  *result = SCIP_SUCCESS;
12242  continue;
12243  }
12244  }
12245 
12246  /* fix quadratic variables with proper square coefficients contained in a single quadratic constraint to their
12247  * upper or lower bounds
12248  */
12249  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 && conshdlrdata->checkquadvarlocks != 'd'
12250  && SCIPisPresolveFinished(scip) )
12251  {
12252  SCIP_CONS* cons;
12253  SCIP_VAR* vars[2];
12254  SCIP_BOUNDTYPE boundtypes[2];
12255  SCIP_Real bounds[2];
12256  char name[SCIP_MAXSTRLEN];
12257 
12258  /* merge variables in order to get correct locks for quadratic variables */
12259  if( !consdata->initialmerge )
12260  {
12261  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
12262  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
12263  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
12264  consdata->initialmerge = TRUE;
12265  }
12266 
12267  for( i = 0; i < consdata->nquadvars; ++i )
12268  {
12269  if( hasQuadvarHpProperty(scip, consdata, i) )
12270  {
12271  SCIP_VAR* var;
12272 
12273  var = consdata->quadvarterms[i].var;
12274  assert(var != NULL);
12275 
12276  /* try to change the variable type to binary */
12277  if( conshdlrdata->checkquadvarlocks == 't' && SCIPisEQ(scip, SCIPvarGetLbGlobal(var), 0.0) && SCIPisEQ(scip, SCIPvarGetUbGlobal(var), 1.0) )
12278  {
12279  SCIP_Bool infeasible;
12280 
12281  assert(SCIPvarGetType(var) != SCIP_VARTYPE_BINARY);
12282  SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, &infeasible) );
12283 
12284  if( infeasible )
12285  {
12286  SCIPdebugMsg(scip, "detect infeasibility after changing variable <%s> to binary type\n", SCIPvarGetName(var));
12287  *result = SCIP_CUTOFF;
12288  return SCIP_OKAY;
12289  }
12290  }
12291  /* add bound disjunction constraint if bounds of variable are finite */
12292  else if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
12293  {
12294  vars[0] = var;
12295  vars[1] = var;
12296  boundtypes[0] = SCIP_BOUNDTYPE_LOWER;
12297  boundtypes[1] = SCIP_BOUNDTYPE_UPPER;
12298  bounds[0] = SCIPvarGetUbGlobal(var);
12299  bounds[1] = SCIPvarGetLbGlobal(var);
12300 
12301  SCIPdebugMsg(scip, "add bound disjunction constraint for %s\n", SCIPvarGetName(var));
12302 
12303  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "quadvarbnddisj_%s", SCIPvarGetName(var));
12304  SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &cons, name, 2, vars, boundtypes, bounds, TRUE, TRUE,
12305  TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
12306 
12307  SCIP_CALL( SCIPaddCons(scip, cons) );
12308  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
12309  }
12310 
12311  *result = SCIP_SUCCESS;
12312  }
12313  }
12314  }
12315 
12316  consdata->ispresolved = TRUE;
12317  }
12318 
12319  return SCIP_OKAY;
12320 }
12321 
12322 /** variable rounding lock method of constraint handler */
12323 static
12324 SCIP_DECL_CONSLOCK(consLockQuadratic)
12325 { /*lint --e{715}*/
12326  SCIP_CONSDATA* consdata;
12327  SCIP_Bool haslb;
12328  SCIP_Bool hasub;
12329  int i;
12330 
12331  assert(scip != NULL);
12332  assert(cons != NULL);
12333 
12334  consdata = SCIPconsGetData(cons);
12335  assert(consdata != NULL);
12336 
12337  haslb = !SCIPisInfinity(scip, -consdata->lhs);
12338  hasub = !SCIPisInfinity(scip, consdata->rhs);
12339 
12340  for( i = 0; i < consdata->nlinvars; ++i )
12341  {
12342  if( consdata->lincoefs[i] > 0 )
12343  {
12344  if( haslb )
12345  {
12346  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlockspos, nlocksneg) );
12347  }
12348  if( hasub )
12349  {
12350  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlocksneg, nlockspos) );
12351  }
12352  }
12353  else
12354  {
12355  if( haslb )
12356  {
12357  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlocksneg, nlockspos) );
12358  }
12359  if( hasub )
12360  {
12361  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlockspos, nlocksneg) );
12362  }
12363  }
12364  }
12365 
12366  for( i = 0; i < consdata->nquadvars; ++i )
12367  {
12368  /* @todo try to be more clever, but variable locks that depend on the bounds of other variables are not trival to maintain */
12369  SCIP_CALL( SCIPaddVarLocks(scip, consdata->quadvarterms[i].var, nlockspos+nlocksneg, nlockspos+nlocksneg) );
12370  }
12371 
12372  return SCIP_OKAY;
12373 }
12374 
12375 /** constraint enabling notification method of constraint handler */
12376 static
12377 SCIP_DECL_CONSENABLE(consEnableQuadratic)
12379  SCIP_CONSHDLRDATA* conshdlrdata;
12380 
12381  assert(scip != NULL);
12382  assert(conshdlr != NULL);
12383  assert(cons != NULL);
12384  assert(SCIPconsIsTransformed(cons));
12385  assert(SCIPconsIsActive(cons));
12386 
12387  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12388  assert(conshdlrdata != NULL);
12389 
12390  SCIPdebugMsg(scip, "enable cons <%s>\n", SCIPconsGetName(cons));
12391 
12392  if( SCIPgetStage(scip) >= SCIP_STAGE_EXITPRESOLVE )
12393  {
12394  /* merge duplicate bilinear terms, move quad terms that are linear to linear vars */
12395  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
12396  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, cons) );
12397  SCIP_CALL( mergeAndCleanLinearVars(scip, cons) );
12398  }
12399 
12400  /* catch variable events */
12401  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
12402 
12403  /* initialize solving data */
12404  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
12405  {
12406  SCIP_CALL( consInitsolQuadratic(scip, conshdlr, &cons, 1) );
12407  }
12408 
12409  return SCIP_OKAY;
12410 }
12411 
12412 /** constraint disabling notification method of constraint handler */
12413 static
12414 SCIP_DECL_CONSDISABLE(consDisableQuadratic)
12415 { /*lint --e{715}*/
12416  SCIP_CONSHDLRDATA* conshdlrdata;
12417 
12418  assert(scip != NULL);
12419  assert(conshdlr != NULL);
12420  assert(cons != NULL);
12421  assert(SCIPconsIsTransformed(cons));
12422 
12423  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12424  assert(conshdlrdata != NULL);
12425 
12426  SCIPdebugMsg(scip, "disable cons <%s>\n", SCIPconsGetName(cons));
12427 
12428  /* free solving data */
12429  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
12430  {
12431  SCIP_CALL( consExitsolQuadratic(scip, conshdlr, &cons, 1, FALSE) );
12432  }
12433 
12434  /* drop variable events */
12435  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
12436 
12437  return SCIP_OKAY;
12438 }
12439 
12440 /** constraint display method of constraint handler */
12441 static
12442 SCIP_DECL_CONSPRINT(consPrintQuadratic)
12443 { /*lint --e{715}*/
12444  SCIP_CONSDATA* consdata;
12445 
12446  assert(scip != NULL);
12447  assert(cons != NULL);
12448 
12449  consdata = SCIPconsGetData(cons);
12450  assert(consdata != NULL);
12451 
12452  /* print left hand side for ranged rows */
12453  if( !SCIPisInfinity(scip, -consdata->lhs)
12454  && !SCIPisInfinity(scip, consdata->rhs)
12455  && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
12456  SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
12457 
12458  /* print coefficients and variables */
12459  if( consdata->nlinvars == 0 && consdata->nquadvars == 0 )
12460  {
12461  SCIPinfoMessage(scip, file, "0 ");
12462  }
12463  else
12464  {
12465  SCIP_VAR*** monomialvars;
12466  SCIP_Real** monomialexps;
12467  SCIP_Real* monomialcoefs;
12468  int* monomialnvars;
12469  int nmonomials;
12470  int monomialssize;
12471  int j;
12472 
12473  monomialssize = consdata->nlinvars + 2 * consdata->nquadvars + consdata->nbilinterms;
12474  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars, monomialssize) );
12475  SCIP_CALL( SCIPallocBufferArray(scip, &monomialexps, monomialssize) );
12476  SCIP_CALL( SCIPallocBufferArray(scip, &monomialcoefs, monomialssize) );
12477  SCIP_CALL( SCIPallocBufferArray(scip, &monomialnvars, monomialssize) );
12478 
12479  nmonomials = 0;
12480  for( j = 0; j < consdata->nlinvars; ++j )
12481  {
12482  assert(nmonomials < monomialssize);
12483 
12484  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 1) ); /*lint !e866 */
12485 
12486  monomialvars[nmonomials][0] = consdata->linvars[j];
12487  monomialexps[nmonomials] = NULL;
12488  monomialcoefs[nmonomials] = consdata->lincoefs[j];
12489  monomialnvars[nmonomials] = 1;
12490  ++nmonomials;
12491  }
12492 
12493  for( j = 0; j < consdata->nquadvars; ++j )
12494  {
12495  if( consdata->quadvarterms[j].lincoef != 0.0 )
12496  {
12497  assert(nmonomials < monomialssize);
12498 
12499  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 1) ); /*lint !e866 */
12500 
12501  monomialvars[nmonomials][0] = consdata->quadvarterms[j].var;
12502  monomialexps[nmonomials] = NULL;
12503  monomialcoefs[nmonomials] = consdata->quadvarterms[j].lincoef;
12504  monomialnvars[nmonomials] = 1;
12505  ++nmonomials;
12506  }
12507 
12508  if( consdata->quadvarterms[j].sqrcoef != 0.0 )
12509  {
12510  assert(nmonomials < monomialssize);
12511 
12512  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 1) ); /*lint !e866 */
12513  SCIP_CALL( SCIPallocBufferArray(scip, &monomialexps[nmonomials], 1) ); /*lint !e866 */
12514 
12515  monomialvars[nmonomials][0] = consdata->quadvarterms[j].var;
12516  monomialexps[nmonomials][0] = 2.0;
12517  monomialcoefs[nmonomials] = consdata->quadvarterms[j].sqrcoef;
12518  monomialnvars[nmonomials] = 1;
12519  ++nmonomials;
12520  }
12521  }
12522 
12523  for( j = 0; j < consdata->nbilinterms; ++j )
12524  {
12525  assert(nmonomials < monomialssize);
12526 
12527  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 2) ); /*lint !e866 */
12528 
12529  monomialvars[nmonomials][0] = consdata->bilinterms[j].var1;
12530  monomialvars[nmonomials][1] = consdata->bilinterms[j].var2;
12531  monomialexps[nmonomials] = NULL;
12532  monomialcoefs[nmonomials] = consdata->bilinterms[j].coef;
12533  monomialnvars[nmonomials] = 2;
12534  ++nmonomials;
12535  }
12536 
12537  SCIP_CALL( SCIPwriteVarsPolynomial(scip, file, monomialvars, monomialexps, monomialcoefs, monomialnvars, nmonomials, TRUE) );
12538 
12539  for( j = 0; j < nmonomials; ++j )
12540  {
12541  SCIPfreeBufferArray(scip, &monomialvars[j]);
12542  SCIPfreeBufferArrayNull(scip, &monomialexps[j]);
12543  }
12544 
12545  SCIPfreeBufferArray(scip, &monomialvars);
12546  SCIPfreeBufferArray(scip, &monomialexps);
12547  SCIPfreeBufferArray(scip, &monomialcoefs);
12548  SCIPfreeBufferArray(scip, &monomialnvars);
12549  }
12550 
12551  /* print right hand side */
12552  if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
12553  {
12554  SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
12555  }
12556  else if( !SCIPisInfinity(scip, consdata->rhs) )
12557  {
12558  SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
12559  }
12560  else if( !SCIPisInfinity(scip, -consdata->lhs) )
12561  {
12562  SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
12563  }
12564  else
12565  {
12566  /* should be ignored by parser */
12567  SCIPinfoMessage(scip, file, " [free]");
12568  }
12569 
12570  return SCIP_OKAY;
12571 }
12572 
12573 /** feasibility check method of constraint handler for integral solutions */
12574 static
12575 SCIP_DECL_CONSCHECK(consCheckQuadratic)
12576 { /*lint --e{715}*/
12577  SCIP_CONSHDLRDATA* conshdlrdata;
12578  SCIP_CONSDATA* consdata;
12579  SCIP_Real maxviol;
12580  int c;
12581  SCIP_Bool maypropfeasible; /* whether we may be able to propose a feasible solution */
12582  SCIP_Bool solviolbounds;
12583 
12584  assert(scip != NULL);
12585  assert(conss != NULL || nconss == 0);
12586  assert(result != NULL);
12587 
12588  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12589  assert(conshdlrdata != NULL);
12590 
12591  *result = SCIP_FEASIBLE;
12592 
12593  maxviol = 0.0;
12594  maypropfeasible = conshdlrdata->linfeasshift && (conshdlrdata->trysolheur != NULL) &&
12596  for( c = 0; c < nconss; ++c )
12597  {
12598  assert(conss != NULL);
12599  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], sol, &solviolbounds) );
12600  assert(!solviolbounds); /* see also issue #627 */
12601 
12602  consdata = SCIPconsGetData(conss[c]);
12603  assert(consdata != NULL);
12604 
12605  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
12606  {
12607  *result = SCIP_INFEASIBLE;
12608  if( printreason )
12609  {
12610  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
12611  SCIPinfoMessage(scip, NULL, ";\n");
12612  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
12613  {
12614  SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g (scaled: %.15g)\n", consdata->lhs - consdata->activity, consdata->lhsviol);
12615  }
12616  if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
12617  {
12618  SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g (scaled: %.15g)\n", consdata->activity - consdata->rhs, consdata->rhsviol);
12619  }
12620  }
12621  if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible && !completely )
12622  return SCIP_OKAY;
12623  if( consdata->lhsviol > maxviol || consdata->rhsviol > maxviol )
12624  maxviol = consdata->lhsviol + consdata->rhsviol;
12625 
12626  /* do not try to shift linear variables if activity is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
12627  if( maypropfeasible && SCIPisInfinity(scip, REALABS(consdata->activity)) )
12628  maypropfeasible = FALSE;
12629 
12630  if( maypropfeasible )
12631  {
12632  /* update information on linear variables that may be in- or decreased, if initsolve has not done so yet */
12634  consdataFindUnlockedLinearVar(scip, consdata);
12635 
12636  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
12637  {
12638  /* check if there is a variable which may help to get the left hand side satisfied
12639  * if there is no such var, then we cannot get feasible */
12640  if( !(consdata->linvar_mayincrease >= 0 && consdata->lincoefs[consdata->linvar_mayincrease] > 0.0) &&
12641  ! (consdata->linvar_maydecrease >= 0 && consdata->lincoefs[consdata->linvar_maydecrease] < 0.0) )
12642  maypropfeasible = FALSE;
12643  }
12644  else
12645  {
12646  assert(SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)));
12647  /* check if there is a variable which may help to get the right hand side satisfied
12648  * if there is no such var, then we cannot get feasible */
12649  if( !(consdata->linvar_mayincrease >= 0 && consdata->lincoefs[consdata->linvar_mayincrease] < 0.0) &&
12650  ! (consdata->linvar_maydecrease >= 0 && consdata->lincoefs[consdata->linvar_maydecrease] > 0.0) )
12651  maypropfeasible = FALSE;
12652  }
12653  }
12654  }
12655  }
12656 
12657  if( *result == SCIP_INFEASIBLE && maypropfeasible )
12658  {
12659  SCIP_Bool success;
12660 
12661  SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
12662 
12663  /* do not pass solution to NLP heuristic if we made it feasible this way */
12664  if( success )
12665  return SCIP_OKAY;
12666  }
12667 
12668  if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL && !SCIPisInfinity(scip, maxviol) )
12669  {
12670  SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
12671  }
12672 
12673  return SCIP_OKAY;
12674 }
12675 
12676 /** constraint copying method of constraint handler */
12677 static
12678 SCIP_DECL_CONSCOPY(consCopyQuadratic)
12680  SCIP_CONSDATA* consdata;
12681  SCIP_CONSDATA* targetconsdata;
12682  SCIP_VAR** linvars;
12683  SCIP_QUADVARTERM* quadvarterms;
12684  SCIP_BILINTERM* bilinterms;
12685  int i;
12686  int j;
12687  int k;
12688 
12689  assert(scip != NULL);
12690  assert(cons != NULL);
12691  assert(sourcescip != NULL);
12692  assert(sourceconshdlr != NULL);
12693  assert(sourcecons != NULL);
12694  assert(varmap != NULL);
12695  assert(valid != NULL);
12696 
12697  consdata = SCIPconsGetData(sourcecons);
12698  assert(consdata != NULL);
12699 
12700  linvars = NULL;
12701  quadvarterms = NULL;
12702  bilinterms = NULL;
12703 
12704  *valid = TRUE;
12705 
12706  if( consdata->nlinvars != 0 )
12707  {
12708  SCIP_CALL( SCIPallocBufferArray(sourcescip, &linvars, consdata->nlinvars) );
12709  for( i = 0; i < consdata->nlinvars; ++i )
12710  {
12711  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, consdata->linvars[i], &linvars[i], varmap, consmap, global, valid) );
12712  assert(!(*valid) || linvars[i] != NULL);
12713 
12714  /* we do not copy, if a variable is missing */
12715  if( !(*valid) )
12716  goto TERMINATE;
12717  }
12718  }
12719 
12720  if( consdata->nbilinterms != 0 )
12721  {
12722  SCIP_CALL( SCIPallocBufferArray(sourcescip, &bilinterms, consdata->nbilinterms) );
12723  }
12724 
12725  if( consdata->nquadvars != 0 )
12726  {
12727  SCIP_CALL( SCIPallocBufferArray(sourcescip, &quadvarterms, consdata->nquadvars) );
12728  for( i = 0; i < consdata->nquadvars; ++i )
12729  {
12730  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, consdata->quadvarterms[i].var, &quadvarterms[i].var, varmap, consmap, global, valid) );
12731  assert(!(*valid) || quadvarterms[i].var != NULL);
12732 
12733  /* we do not copy, if a variable is missing */
12734  if( !(*valid) )
12735  goto TERMINATE;
12736 
12737  quadvarterms[i].lincoef = consdata->quadvarterms[i].lincoef;
12738  quadvarterms[i].sqrcoef = consdata->quadvarterms[i].sqrcoef;
12739  quadvarterms[i].eventdata = NULL;
12740  quadvarterms[i].nadjbilin = consdata->quadvarterms[i].nadjbilin;
12741  quadvarterms[i].adjbilin = consdata->quadvarterms[i].adjbilin;
12742 
12743  assert(consdata->nbilinterms != 0 || consdata->quadvarterms[i].nadjbilin == 0);
12744 
12745  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
12746  {
12747  assert(bilinterms != NULL);
12748 
12749  k = consdata->quadvarterms[i].adjbilin[j];
12750  assert(consdata->bilinterms[k].var1 != NULL);
12751  assert(consdata->bilinterms[k].var2 != NULL);
12752  if( consdata->bilinterms[k].var1 == consdata->quadvarterms[i].var )
12753  {
12754  assert(consdata->bilinterms[k].var2 != consdata->quadvarterms[i].var);
12755  bilinterms[k].var1 = quadvarterms[i].var;
12756  }
12757  else
12758  {
12759  assert(consdata->bilinterms[k].var2 == consdata->quadvarterms[i].var);
12760  bilinterms[k].var2 = quadvarterms[i].var;
12761  }
12762  bilinterms[k].coef = consdata->bilinterms[k].coef;
12763  }
12764  }
12765  }
12766 
12767  assert(stickingatnode == FALSE);
12768  SCIP_CALL( SCIPcreateConsQuadratic2(scip, cons, name ? name : SCIPconsGetName(sourcecons),
12769  consdata->nlinvars, linvars, consdata->lincoefs,
12770  consdata->nquadvars, quadvarterms,
12771  consdata->nbilinterms, bilinterms,
12772  consdata->lhs, consdata->rhs,
12773  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12774 
12775  /* copy information on curvature */
12776  targetconsdata = SCIPconsGetData(*cons);
12777  targetconsdata->isconvex = consdata->isconvex;
12778  targetconsdata->isconcave = consdata->isconcave;
12779  targetconsdata->iscurvchecked = consdata->iscurvchecked;
12780 
12781  TERMINATE:
12782  SCIPfreeBufferArrayNull(sourcescip, &quadvarterms);
12783  SCIPfreeBufferArrayNull(sourcescip, &bilinterms);
12784  SCIPfreeBufferArrayNull(sourcescip, &linvars);
12785 
12786  return SCIP_OKAY;
12787 }
12788 
12789 /** constraint parsing method of constraint handler */
12790 static
12791 SCIP_DECL_CONSPARSE(consParseQuadratic)
12792 { /*lint --e{715}*/
12793  SCIP_VAR*** monomialvars;
12794  SCIP_Real** monomialexps;
12795  SCIP_Real* monomialcoefs;
12796  char* endptr;
12797  int* monomialnvars;
12798  int nmonomials;
12799 
12800  SCIP_Real lhs;
12801  SCIP_Real rhs;
12802 
12803  assert(scip != NULL);
12804  assert(success != NULL);
12805  assert(str != NULL);
12806  assert(name != NULL);
12807  assert(cons != NULL);
12808 
12809  /* set left and right hand side to their default values */
12810  lhs = -SCIPinfinity(scip);
12811  rhs = SCIPinfinity(scip);
12812 
12813  (*success) = FALSE;
12814 
12815  /* return of string empty */
12816  if( !*str )
12817  return SCIP_OKAY;
12818 
12819  /* ignore whitespace */
12820  while( isspace((unsigned char)*str) )
12821  ++str;
12822 
12823  /* check for left hand side */
12824  if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
12825  {
12826  /* there is a number coming, maybe it is a left-hand-side */
12827  if( !SCIPstrToRealValue(str, &lhs, &endptr) )
12828  {
12829  SCIPerrorMessage("error parsing number from <%s>\n", str);
12830  return SCIP_OKAY;
12831  }
12832 
12833  /* ignore whitespace */
12834  while( isspace((unsigned char)*endptr) )
12835  ++endptr;
12836 
12837  if( endptr[0] != '<' || endptr[1] != '=' )
12838  {
12839  /* no '<=' coming, so it was the first coefficient, but not a left-hand-side */
12840  lhs = -SCIPinfinity(scip);
12841  }
12842  else
12843  {
12844  /* it was indeed a left-hand-side, so continue parsing after it */
12845  str = endptr + 2;
12846 
12847  /* ignore whitespace */
12848  while( isspace((unsigned char)*str) )
12849  ++str;
12850  }
12851  }
12852 
12853  SCIP_CALL( SCIPparseVarsPolynomial(scip, str, &monomialvars, &monomialexps, &monomialcoefs, &monomialnvars, &nmonomials, &endptr, success) );
12854 
12855  if( *success )
12856  {
12857  /* check for right hand side */
12858  str = endptr;
12859 
12860  /* ignore whitespace */
12861  while( isspace((unsigned char)*str) )
12862  ++str;
12863 
12864  if( *str && str[0] == '<' && str[1] == '=' )
12865  {
12866  /* we seem to get a right-hand-side */
12867  str += 2;
12868 
12869  if( !SCIPstrToRealValue(str, &rhs, &endptr) )
12870  {
12871  SCIPerrorMessage("error parsing right-hand-side from %s\n", str);
12872  *success = FALSE;
12873  }
12874  }
12875  else if( *str && str[0] == '>' && str[1] == '=' )
12876  {
12877  /* we seem to get a left-hand-side */
12878  str += 2;
12879 
12880  /* we should not have a left-hand-side already */
12881  assert(SCIPisInfinity(scip, -lhs));
12882 
12883  if( !SCIPstrToRealValue(str, &lhs, &endptr) )
12884  {
12885  SCIPerrorMessage("error parsing left-hand-side from %s\n", str);
12886  *success = FALSE;
12887  }
12888  }
12889  else if( *str && str[0] == '=' && str[1] == '=' )
12890  {
12891  /* we seem to get a left- and right-hand-side */
12892  str += 2;
12893 
12894  /* we should not have a left-hand-side already */
12895  assert(SCIPisInfinity(scip, -lhs));
12896 
12897  if( !SCIPstrToRealValue(str, &lhs, &endptr) )
12898  {
12899  SCIPerrorMessage("error parsing left-hand-side from %s\n", str);
12900  *success = FALSE;
12901  }
12902  else
12903  {
12904  rhs = lhs;
12905  }
12906  }
12907  }
12908 
12909  if( *success )
12910  {
12911  int i;
12912 
12913  /* setup constraint */
12914  assert(stickingatnode == FALSE);
12915  SCIP_CALL( SCIPcreateConsQuadratic(scip, cons, name, 0, NULL, NULL,
12916  0, NULL, NULL, NULL, lhs, rhs,
12917  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12918 
12919  for( i = 0; i < nmonomials; ++i )
12920  {
12921  if( monomialnvars[i] == 0 )
12922  {
12923  /* constant monomial */
12924  SCIPaddConstantQuadratic(scip, *cons, monomialcoefs[i]);
12925  }
12926  else if( monomialnvars[i] == 1 && monomialexps[i][0] == 1.0 )
12927  {
12928  /* linear monomial */
12929  SCIP_CALL( SCIPaddLinearVarQuadratic(scip, *cons, monomialvars[i][0], monomialcoefs[i]) );
12930  }
12931  else if( monomialnvars[i] == 1 && monomialexps[i][0] == 2.0 )
12932  {
12933  /* square monomial */
12934  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, monomialvars[i][0], 0.0, monomialcoefs[i]) );
12935  }
12936  else if( monomialnvars[i] == 2 && monomialexps[i][0] == 1.0 && monomialexps[i][1] == 1.0 )
12937  {
12938  /* bilinear term */
12939  SCIP_VAR* var1;
12940  SCIP_VAR* var2;
12941  int pos;
12942 
12943  var1 = monomialvars[i][0];
12944  var2 = monomialvars[i][1];
12945  if( var1 == var2 )
12946  {
12947  /* actually a square term */
12948  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, var1, 0.0, monomialcoefs[i]) );
12949  }
12950  else
12951  {
12952  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, *cons, var1, &pos) );
12953  if( pos == -1 )
12954  {
12955  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, var1, 0.0, 0.0) );
12956  }
12957 
12958  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, *cons, var2, &pos) );
12959  if( pos == -1 )
12960  {
12961  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, var2, 0.0, 0.0) );
12962  }
12963  }
12964 
12965  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, *cons, var1, var2, monomialcoefs[i]) );
12966  }
12967  else
12968  {
12969  SCIPerrorMessage("polynomial in quadratic constraint does not have degree at most 2\n");
12970  *success = FALSE;
12971  SCIP_CALL( SCIPreleaseCons(scip, cons) );
12972  break;
12973  }
12974  }
12975  }
12976 
12977  SCIPfreeParseVarsPolynomialData(scip, &monomialvars, &monomialexps, &monomialcoefs, &monomialnvars, nmonomials);
12978 
12979  return SCIP_OKAY;
12980 }
12981 
12982 /** constraint method of constraint handler which returns the variables (if possible) */
12983 static
12984 SCIP_DECL_CONSGETVARS(consGetVarsQuadratic)
12985 { /*lint --e{715}*/
12986  SCIP_CONSDATA* consdata;
12987 
12988  assert(cons != NULL);
12989  assert(success != NULL);
12990 
12991  consdata = SCIPconsGetData(cons);
12992  assert(consdata != NULL);
12993 
12994  if( varssize < consdata->nlinvars + consdata->nquadvars )
12995  (*success) = FALSE;
12996  else
12997  {
12998  int i;
12999 
13000  assert(vars != NULL);
13001 
13002  BMScopyMemoryArray(vars, consdata->linvars, consdata->nlinvars);
13003 
13004  for( i = 0; i < consdata->nquadvars; ++i )
13005  vars[consdata->nlinvars+i] = consdata->quadvarterms[i].var;
13006 
13007  (*success) = TRUE;
13008  }
13009 
13010  return SCIP_OKAY;
13011 }
13012 
13013 /** constraint method of constraint handler which returns the number of variables (if possible) */
13014 static
13015 SCIP_DECL_CONSGETNVARS(consGetNVarsQuadratic)
13016 { /*lint --e{715}*/
13017  SCIP_CONSDATA* consdata;
13018 
13019  assert(cons != NULL);
13020  assert(success != NULL);
13021 
13022  consdata = SCIPconsGetData(cons);
13023  assert(consdata != NULL);
13024 
13025  (*nvars) = consdata->nlinvars + consdata->nquadvars;
13026  (*success) = TRUE;
13027 
13028  return SCIP_OKAY;
13029 }
13030 
13031 
13032 /*
13033  * constraint specific interface methods
13034  */
13035 
13036 /** creates the handler for quadratic constraints and includes it in SCIP */
13038  SCIP* scip /**< SCIP data structure */
13039  )
13040 {
13041  SCIP_CONSHDLRDATA* conshdlrdata;
13042  SCIP_CONSHDLR* conshdlr;
13043 
13044  /* create quadratic constraint handler data */
13045  SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
13046  BMSclearMemory(conshdlrdata);
13047 
13048  /* include constraint handler */
13051  consEnfolpQuadratic, consEnfopsQuadratic, consCheckQuadratic, consLockQuadratic,
13052  conshdlrdata) );
13053  assert(conshdlr != NULL);
13054 
13055 
13056  /* set non-fundamental callbacks via specific setter functions */
13057  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyQuadratic, consCopyQuadratic) );
13058  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteQuadratic) );
13059  SCIP_CALL( SCIPsetConshdlrDisable(scip, conshdlr, consDisableQuadratic) );
13060  SCIP_CALL( SCIPsetConshdlrEnable(scip, conshdlr, consEnableQuadratic) );
13061  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitQuadratic) );
13062  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreQuadratic) );
13063  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolQuadratic) );
13064  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeQuadratic) );
13065  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsQuadratic) );
13066  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsQuadratic) );
13067  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitQuadratic) );
13068  SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolQuadratic) );
13069  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpQuadratic) );
13070  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseQuadratic) );
13071  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolQuadratic, CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
13072  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintQuadratic) );
13073  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropQuadratic, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
13075  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpQuadratic, consSepasolQuadratic, CONSHDLR_SEPAFREQ,
13077  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransQuadratic) );
13078  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxQuadratic) );
13079 
13080  /* add quadratic constraint handler parameters */
13081  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/replacebinaryprod",
13082  "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)",
13083  &conshdlrdata->replacebinaryprodlength, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
13084 
13085  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/empathy4and",
13086  "empathy level for using the AND constraint handler: 0 always avoid using AND; 1 use AND sometimes; 2 use AND as often as possible",
13087  &conshdlrdata->empathy4and, FALSE, 0, 0, 2, NULL, NULL) );
13088 
13089  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/binreforminitial",
13090  "whether to make non-varbound linear constraints added due to replacing products with binary variables initial",
13091  &conshdlrdata->binreforminitial, TRUE, FALSE, NULL, NULL) );
13092 
13093  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/binreformmaxcoef",
13094  "limit (as factor on 1/feastol) on coefficients and coef. range in linear constraints created when replacing products with binary variables",
13095  &conshdlrdata->binreformmaxcoef, TRUE, 1e-4, 0.0, SCIPinfinity(scip), NULL, NULL) );
13096 
13097  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/minefficacysepa",
13098  "minimal efficacy for a cut to be added to the LP during separation; overwrites separating/efficacy",
13099  &conshdlrdata->mincutefficacysepa, TRUE, 0.0001, 0.0, SCIPinfinity(scip), NULL, NULL) );
13100 
13101  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/minefficacyenfofac",
13102  "minimal target efficacy of a cut in order to add it to relaxation during enforcement as a factor of the feasibility tolerance (may be ignored)",
13103  &conshdlrdata->mincutefficacyenfofac, TRUE, 2.0, 1.0, SCIPinfinity(scip), NULL, NULL) );
13104 
13105  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/scaling",
13106  "whether scaling of infeasibility is 'o'ff, by sup-norm of function 'g'radient, or by left/right hand 's'ide",
13107  &conshdlrdata->scaling, TRUE, 'o', "ogs", NULL, NULL) );
13108 
13109  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/cutmaxrange",
13110  "maximal coef range of a cut (maximal coefficient divided by minimal coefficient) in order to be added to LP relaxation",
13111  &conshdlrdata->cutmaxrange, TRUE, 1e+7, 0.0, SCIPinfinity(scip), NULL, NULL) );
13112 
13113  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/linearizeheursol",
13114  "whether linearizations of convex quadratic constraints should be added to cutpool in a solution found by some heuristic",
13115  &conshdlrdata->linearizeheursol, TRUE, TRUE, NULL, NULL) );
13116 
13117  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/checkcurvature",
13118  "whether multivariate quadratic functions should be checked for convexity/concavity",
13119  &conshdlrdata->checkcurvature, FALSE, TRUE, NULL, NULL) );
13120 
13121  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/checkfactorable",
13122  "whether constraint functions should be checked to be factorable",
13123  &conshdlrdata->checkfactorable, TRUE, TRUE, NULL, NULL) );
13124 
13125  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/checkquadvarlocks",
13126  "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)",
13127  &conshdlrdata->checkquadvarlocks, TRUE, 't', "bdt", NULL, NULL) );
13128 
13129  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/linfeasshift",
13130  "whether to try to make solutions in check function feasible by shifting a linear variable (esp. useful if constraint was actually objective function)",
13131  &conshdlrdata->linfeasshift, TRUE, TRUE, NULL, NULL) );
13132 
13133  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/disaggregate",
13134  "whether to disaggregate quadratic parts that decompose into a sum of non-overlapping quadratic terms",
13135  &conshdlrdata->disaggregate, TRUE, FALSE, NULL, NULL) );
13136 
13137  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
13138  "limit on number of propagation rounds for a single constraint within one round of SCIP propagation during solve",
13139  &conshdlrdata->maxproprounds, TRUE, 1, 0, INT_MAX, NULL, NULL) );
13140 
13141  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproproundspresolve",
13142  "limit on number of propagation rounds for a single constraint within one round of SCIP presolve",
13143  &conshdlrdata->maxproproundspresolve, TRUE, 10, 0, INT_MAX, NULL, NULL) );
13144 
13145  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/enfolplimit",
13146  "maximum number of enforcement rounds before declaring the LP relaxation infeasible (-1: no limit); WARNING: changing this parameter might lead to incorrect results!",
13147  &conshdlrdata->enfolplimit, TRUE, -1, -1, INT_MAX, NULL, NULL) );
13148 
13149  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/sepanlpmincont",
13150  "minimal required fraction of continuous variables in problem to use solution of NLP relaxation in root for separation",
13151  &conshdlrdata->sepanlpmincont, FALSE, 1.0, 0.0, 2.0, NULL, NULL) );
13152 
13153  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/enfocutsremovable",
13154  "are cuts added during enforcement removable from the LP in the same node?",
13155  &conshdlrdata->enfocutsremovable, TRUE, FALSE, NULL, NULL) );
13156 
13157  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/gaugecuts",
13158  "should convex quadratics generated strong cuts via gauge function?",
13159  &conshdlrdata->gaugecuts, FALSE, TRUE, NULL, NULL) );
13160 
13161  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/interiorcomputation",
13162  "how the interior point for gauge cuts should be computed: 'a'ny point per constraint, 'm'ost interior per constraint",
13163  &conshdlrdata->interiorcomputation, TRUE, 'a', "am", NULL, NULL) );
13164 
13165  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/projectedcuts",
13166  "should convex quadratics generated strong cuts via projections?",
13167  &conshdlrdata->projectedcuts, FALSE, FALSE, NULL, NULL) );
13168 
13169  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branchscoring",
13170  "which score to give branching candidates: convexification 'g'ap, constraint 'v'iolation, 'c'entrality of variable value in domain",
13171  &conshdlrdata->branchscoring, TRUE, 'g', "cgv", NULL, NULL) );
13172 
13173  conshdlrdata->eventhdlr = NULL;
13174  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlr),CONSHDLR_NAME"_boundchange", "signals a bound change to a quadratic constraint",
13175  processVarEvent, NULL) );
13176  assert(conshdlrdata->eventhdlr != NULL);
13177 
13178  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME"_newsolution", "handles the event that a new primal solution has been found",
13179  processNewSolutionEvent, NULL) );
13180 
13181  /* include the quadratic constraint upgrade in the nonlinear constraint handler */
13183 
13184  return SCIP_OKAY;
13185 }
13186 
13187 /** includes a quadratic constraint update method into the quadratic constraint handler */
13189  SCIP* scip, /**< SCIP data structure */
13190  SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), /**< method to call for upgrading quadratic constraint */
13191  int priority, /**< priority of upgrading method */
13192  SCIP_Bool active, /**< should the upgrading method be active by default? */
13193  const char* conshdlrname /**< name of the constraint handler */
13194  )
13195 {
13196  SCIP_CONSHDLR* conshdlr;
13197  SCIP_CONSHDLRDATA* conshdlrdata;
13198  SCIP_QUADCONSUPGRADE* quadconsupgrade;
13199  char paramname[SCIP_MAXSTRLEN];
13200  char paramdesc[SCIP_MAXSTRLEN];
13201  int i;
13202 
13203  assert(quadconsupgd != NULL);
13204  assert(conshdlrname != NULL );
13205 
13206  /* find the quadratic constraint handler */
13207  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13208  if( conshdlr == NULL )
13209  {
13210  SCIPerrorMessage("quadratic constraint handler not found\n");
13211  return SCIP_PLUGINNOTFOUND;
13212  }
13213 
13214  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13215  assert(conshdlrdata != NULL);
13216 
13217  if( !conshdlrdataHasUpgrade(scip, conshdlrdata, quadconsupgd, conshdlrname) )
13218  {
13219  /* create a quadratic constraint upgrade data object */
13220  SCIP_CALL( SCIPallocBlockMemory(scip, &quadconsupgrade) );
13221  quadconsupgrade->quadconsupgd = quadconsupgd;
13222  quadconsupgrade->priority = priority;
13223  quadconsupgrade->active = active;
13224 
13225  /* insert quadratic constraint upgrade method into constraint handler data */
13226  assert(conshdlrdata->nquadconsupgrades <= conshdlrdata->quadconsupgradessize);
13227  if( conshdlrdata->nquadconsupgrades+1 > conshdlrdata->quadconsupgradessize )
13228  {
13229  int newsize;
13230 
13231  newsize = SCIPcalcMemGrowSize(scip, conshdlrdata->nquadconsupgrades+1);
13232  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->quadconsupgrades, conshdlrdata->quadconsupgradessize, newsize) );
13233  conshdlrdata->quadconsupgradessize = newsize;
13234  }
13235  assert(conshdlrdata->nquadconsupgrades+1 <= conshdlrdata->quadconsupgradessize);
13236 
13237  for( i = conshdlrdata->nquadconsupgrades; i > 0 && conshdlrdata->quadconsupgrades[i-1]->priority < quadconsupgrade->priority; --i )
13238  conshdlrdata->quadconsupgrades[i] = conshdlrdata->quadconsupgrades[i-1];
13239  assert(0 <= i && i <= conshdlrdata->nquadconsupgrades);
13240  conshdlrdata->quadconsupgrades[i] = quadconsupgrade;
13241  conshdlrdata->nquadconsupgrades++;
13242 
13243  /* adds parameter to turn on and off the upgrading step */
13244  (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
13245  (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable quadratic upgrading for constraint handler <%s>", conshdlrname);
13247  paramname, paramdesc,
13248  &quadconsupgrade->active, FALSE, active, NULL, NULL) );
13249  }
13250 
13251  return SCIP_OKAY;
13252 }
13253 
13254 /** Creates and captures a quadratic constraint.
13255  *
13256  * The constraint should be given in the form
13257  * \f[
13258  * \ell \leq \sum_{i=1}^n b_i x_i + \sum_{j=1}^m a_j y_j z_j \leq u,
13259  * \f]
13260  * where \f$x_i = y_j = z_k\f$ is possible.
13261  *
13262  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13263  */
13265  SCIP* scip, /**< SCIP data structure */
13266  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13267  const char* name, /**< name of constraint */
13268  int nlinvars, /**< number of linear terms (n) */
13269  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
13270  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
13271  int nquadterms, /**< number of quadratic terms (m) */
13272  SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms (y_j) */
13273  SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms (z_j) */
13274  SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms (a_j) */
13275  SCIP_Real lhs, /**< left hand side of quadratic equation (ell) */
13276  SCIP_Real rhs, /**< right hand side of quadratic equation (u) */
13277  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13278  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13279  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13280  * Usually set to TRUE. */
13281  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13282  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13283  SCIP_Bool check, /**< should the constraint be checked for feasibility?
13284  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13285  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13286  * Usually set to TRUE. */
13287  SCIP_Bool local, /**< is constraint only valid locally?
13288  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13289  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13290  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13291  * adds coefficients to this constraint. */
13292  SCIP_Bool dynamic, /**< is constraint subject to aging?
13293  * Usually set to FALSE. Set to TRUE for own cuts which
13294  * are separated as constraints. */
13295  SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
13296  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13297  )
13298 {
13299  SCIP_CONSHDLR* conshdlr;
13300  SCIP_CONSDATA* consdata;
13301  SCIP_HASHMAP* quadvaridxs;
13302  SCIP_Real sqrcoef;
13303  int i;
13304  int var1pos;
13305  int var2pos;
13306 
13307  int nbilinterms;
13308 
13309  assert(linvars != NULL || nlinvars == 0);
13310  assert(lincoefs != NULL || nlinvars == 0);
13311  assert(quadvars1 != NULL || nquadterms == 0);
13312  assert(quadvars2 != NULL || nquadterms == 0);
13313  assert(quadcoefs != NULL || nquadterms == 0);
13314 
13315  assert(modifiable == FALSE); /* we do not support column generation */
13316 
13317  /* find the quadratic constraint handler */
13318  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13319  if( conshdlr == NULL )
13320  {
13321  SCIPerrorMessage("quadratic constraint handler not found\n");
13322  return SCIP_PLUGINNOTFOUND;
13323  }
13324 
13325  /* create constraint data and constraint */
13326  SCIP_CALL( consdataCreateEmpty(scip, &consdata) );
13327 
13328  consdata->lhs = lhs;
13329  consdata->rhs = rhs;
13330 
13331  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
13332  local, modifiable, dynamic, removable, FALSE) );
13333 
13334  /* add quadratic variables and remember their indices */
13335  SCIP_CALL( SCIPhashmapCreate(&quadvaridxs, SCIPblkmem(scip), nquadterms) );
13336  nbilinterms = 0;
13337  for( i = 0; i < nquadterms; ++i )
13338  {
13339  if( SCIPisZero(scip, quadcoefs[i]) ) /*lint !e613*/
13340  continue;
13341 
13342  /* if it is actually a square term, remember it's coefficient */
13343  /* cppcheck-suppress nullPointer */
13344  if( quadvars1[i] == quadvars2[i] ) /*lint !e613*/
13345  sqrcoef = quadcoefs[i]; /*lint !e613 */
13346  else
13347  sqrcoef = 0.0;
13348 
13349  /* add quadvars1[i], if not in there already */
13350  if( !SCIPhashmapExists(quadvaridxs, quadvars1[i]) ) /*lint !e613*/
13351  {
13352  SCIP_CALL( addQuadVarTerm(scip, *cons, quadvars1[i], 0.0, sqrcoef) ); /*lint !e613*/
13353  assert(consdata->nquadvars >= 0);
13354  assert(consdata->quadvarterms[consdata->nquadvars-1].var == quadvars1[i]); /*lint !e613*/
13355 
13356  SCIP_CALL( SCIPhashmapInsert(quadvaridxs, quadvars1[i], (void*)(size_t)(consdata->nquadvars-1)) ); /*lint !e613*/
13357  }
13358  else if( !SCIPisZero(scip, sqrcoef) )
13359  {
13360  /* if it's there already, but we got a square coefficient, add it to the previous one */
13361  var1pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, quadvars1[i]); /*lint !e613*/
13362  assert(consdata->quadvarterms[var1pos].var == quadvars1[i]); /*lint !e613*/
13363  consdata->quadvarterms[var1pos].sqrcoef += sqrcoef;
13364  }
13365 
13366  /* cppcheck-suppress nullPointer */
13367  if( quadvars1[i] == quadvars2[i] ) /*lint !e613*/
13368  continue;
13369 
13370  /* add quadvars2[i], if not in there already */
13371  if( !SCIPhashmapExists(quadvaridxs, quadvars2[i]) ) /*lint !e613*/
13372  {
13373  assert(sqrcoef == 0.0);
13374  SCIP_CALL( addQuadVarTerm(scip, *cons, quadvars2[i], 0.0, 0.0) ); /*lint !e613*/
13375  assert(consdata->nquadvars >= 0);
13376  assert(consdata->quadvarterms[consdata->nquadvars-1].var == quadvars2[i]); /*lint !e613*/
13377 
13378  SCIP_CALL( SCIPhashmapInsert(quadvaridxs, quadvars2[i], (void*)(size_t)(consdata->nquadvars-1)) ); /*lint !e613*/
13379  }
13380 
13381  ++nbilinterms;
13382  }
13383 
13384  /* add bilinear terms, if we saw any */
13385  if( nbilinterms > 0 )
13386  {
13387  SCIP_CALL( consdataEnsureBilinSize(scip, consdata, nbilinterms) );
13388  for( i = 0; i < nquadterms; ++i )
13389  {
13390  if( SCIPisZero(scip, quadcoefs[i]) ) /*lint !e613*/
13391  continue;
13392 
13393  /* square terms have been taken care of already */
13394  if( quadvars1[i] == quadvars2[i] ) /*lint !e613 */
13395  continue;
13396 
13397  assert(SCIPhashmapExists(quadvaridxs, quadvars1[i])); /*lint !e613*/
13398  assert(SCIPhashmapExists(quadvaridxs, quadvars2[i])); /*lint !e613*/
13399 
13400  var1pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, quadvars1[i]); /*lint !e613*/
13401  var2pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, quadvars2[i]); /*lint !e613*/
13402 
13403  SCIP_CALL( addBilinearTerm(scip, *cons, var1pos, var2pos, quadcoefs[i]) ); /*lint !e613*/
13404  }
13405  }
13406 
13407  /* add linear variables */
13408  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, nlinvars) );
13409  for( i = 0; i < nlinvars; ++i )
13410  {
13411  if( SCIPisZero(scip, lincoefs[i]) ) /*lint !e613*/
13412  continue;
13413 
13414  /* if it's a linear coefficient for a quadratic variable, add it there, otherwise add as linear variable */
13415  if( SCIPhashmapExists(quadvaridxs, linvars[i]) ) /*lint !e613*/
13416  {
13417  var1pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, linvars[i]); /*lint !e613*/
13418  assert(consdata->quadvarterms[var1pos].var == linvars[i]); /*lint !e613*/
13419  consdata->quadvarterms[var1pos].lincoef += lincoefs[i]; /*lint !e613*/
13420  }
13421  else
13422  {
13423  SCIP_CALL( addLinearCoef(scip, *cons, linvars[i], lincoefs[i]) ); /*lint !e613*/
13424  }
13425  }
13426 
13427  SCIPhashmapFree(&quadvaridxs);
13428 
13429  SCIPdebugMsg(scip, "created quadratic constraint ");
13430  SCIPdebugPrintCons(scip, *cons, NULL);
13431 
13432  return SCIP_OKAY;
13433 }
13434 
13435 /** creates and captures a quadratic constraint with all its
13436  * flags set to their default values.
13437  *
13438  * The constraint should be given in the form
13439  * \f[
13440  * \ell \leq \sum_{i=1}^n b_i x_i + \sum_{j=1}^m a_j y_j z_j \leq u,
13441  * \f]
13442  * where \f$x_i = y_j = z_k\f$ is possible.
13443  *
13444  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13445  */
13447  SCIP* scip, /**< SCIP data structure */
13448  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13449  const char* name, /**< name of constraint */
13450  int nlinvars, /**< number of linear terms (n) */
13451  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
13452  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
13453  int nquadterms, /**< number of quadratic terms (m) */
13454  SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms (y_j) */
13455  SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms (z_j) */
13456  SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms (a_j) */
13457  SCIP_Real lhs, /**< left hand side of quadratic equation (ell) */
13458  SCIP_Real rhs /**< right hand side of quadratic equation (u) */
13459  )
13460 {
13461  SCIP_CALL( SCIPcreateConsQuadratic(scip, cons, name, nlinvars, linvars, lincoefs,
13462  nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
13463  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
13464 
13465  return SCIP_OKAY;
13466 }
13467 
13468 /** Creates and captures a quadratic constraint.
13469  *
13470  * The constraint should be given in the form
13471  * \f[
13472  * \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.
13473  * \f]
13474  *
13475  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13476  */
13478  SCIP* scip, /**< SCIP data structure */
13479  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13480  const char* name, /**< name of constraint */
13481  int nlinvars, /**< number of linear terms (n) */
13482  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
13483  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
13484  int nquadvarterms, /**< number of quadratic terms (m) */
13485  SCIP_QUADVARTERM* quadvarterms, /**< quadratic variable terms */
13486  int nbilinterms, /**< number of bilinear terms (p) */
13487  SCIP_BILINTERM* bilinterms, /**< bilinear terms */
13488  SCIP_Real lhs, /**< constraint left hand side (ell) */
13489  SCIP_Real rhs, /**< constraint right hand side (u) */
13490  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? */
13491  SCIP_Bool separate, /**< should the constraint be separated during LP processing? */
13492  SCIP_Bool enforce, /**< should the constraint be enforced during node processing? */
13493  SCIP_Bool check, /**< should the constraint be checked for feasibility? */
13494  SCIP_Bool propagate, /**< should the constraint be propagated during node processing? */
13495  SCIP_Bool local, /**< is constraint only valid locally? */
13496  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)? */
13497  SCIP_Bool dynamic, /**< is constraint dynamic? */
13498  SCIP_Bool removable /**< should the constraint be removed from the LP due to aging or cleanup? */
13499  )
13500 {
13501  SCIP_CONSHDLR* conshdlr;
13502  SCIP_CONSDATA* consdata;
13503 
13504  assert(modifiable == FALSE); /* we do not support column generation */
13505  assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
13506  assert(nquadvarterms == 0 || quadvarterms != NULL);
13507  assert(nbilinterms == 0 || bilinterms != NULL);
13508 
13509  /* find the quadratic constraint handler */
13510  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13511  if( conshdlr == NULL )
13512  {
13513  SCIPerrorMessage("quadratic constraint handler not found\n");
13514  return SCIP_PLUGINNOTFOUND;
13515  }
13516 
13517  /* create constraint data */
13518  SCIP_CALL( consdataCreate(scip, &consdata, lhs, rhs,
13519  nlinvars, linvars, lincoefs, nquadvarterms, quadvarterms, nbilinterms, bilinterms,
13520  TRUE) );
13521 
13522  /* create constraint */
13523  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
13524  local, modifiable, dynamic, removable, FALSE) );
13525 
13526  return SCIP_OKAY;
13527 }
13528 
13529 /** creates and captures a quadratic constraint in its most basic version, i.e.,
13530  * all constraint flags are set to their default values.
13531  *
13532  * The constraint should be given in the form
13533  * \f[
13534  * \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.
13535  * \f]
13536  *
13537  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13538  */
13540  SCIP* scip, /**< SCIP data structure */
13541  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13542  const char* name, /**< name of constraint */
13543  int nlinvars, /**< number of linear terms (n) */
13544  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
13545  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
13546  int nquadvarterms, /**< number of quadratic terms (m) */
13547  SCIP_QUADVARTERM* quadvarterms, /**< quadratic variable terms */
13548  int nbilinterms, /**< number of bilinear terms (p) */
13549  SCIP_BILINTERM* bilinterms, /**< bilinear terms */
13550  SCIP_Real lhs, /**< constraint left hand side (ell) */
13551  SCIP_Real rhs /**< constraint right hand side (u) */
13552  )
13553 {
13554  SCIP_CALL( SCIPcreateConsQuadratic2(scip, cons, name, nlinvars, linvars, lincoefs,
13555  nquadvarterms, quadvarterms, nbilinterms, bilinterms, lhs, rhs,
13556  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
13557 
13558  return SCIP_OKAY;
13559 }
13560 
13561 
13562 /** Adds a constant to the constraint function, that is, subtracts a constant from both sides */
13564  SCIP* scip, /**< SCIP data structure */
13565  SCIP_CONS* cons, /**< constraint */
13566  SCIP_Real constant /**< constant to subtract from both sides */
13567  )
13568 {
13569  SCIP_CONSDATA* consdata;
13570 
13571  assert(scip != NULL);
13572  assert(cons != NULL);
13573  assert(!SCIPisInfinity(scip, REALABS(constant)));
13574 
13575  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
13576  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
13577  {
13578  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
13579  SCIPABORT();
13580  }
13581 
13582  consdata = SCIPconsGetData(cons);
13583  assert(consdata != NULL);
13584  assert(consdata->lhs <= consdata->rhs);
13585 
13586  if( !SCIPisInfinity(scip, -consdata->lhs) )
13587  consdata->lhs -= constant;
13588  if( !SCIPisInfinity(scip, consdata->rhs) )
13589  consdata->rhs -= constant;
13590 
13591  if( consdata->lhs > consdata->rhs )
13592  {
13593  assert(SCIPisEQ(scip, consdata->lhs, consdata->rhs));
13594  consdata->lhs = consdata->rhs;
13595  }
13596 }
13597 
13598 /** Adds a linear variable with coefficient to a quadratic constraint. */
13600  SCIP* scip, /**< SCIP data structure */
13601  SCIP_CONS* cons, /**< constraint */
13602  SCIP_VAR* var, /**< variable */
13603  SCIP_Real coef /**< coefficient of variable */
13604  )
13605 {
13606  assert(scip != NULL);
13607  assert(cons != NULL);
13608  assert(var != NULL);
13609  assert(!SCIPisInfinity(scip, REALABS(coef)));
13610 
13611  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
13612  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
13613  {
13614  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
13615  return SCIP_INVALIDCALL;
13616  }
13617 
13618  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
13619 
13620  return SCIP_OKAY;
13621 }
13622 
13623 /** Adds a quadratic variable with linear and square coefficient to a quadratic constraint. */
13625  SCIP* scip, /**< SCIP data structure */
13626  SCIP_CONS* cons, /**< constraint */
13627  SCIP_VAR* var, /**< variable */
13628  SCIP_Real lincoef, /**< linear coefficient of variable */
13629  SCIP_Real sqrcoef /**< square coefficient of variable */
13630  )
13631 {
13632  assert(scip != NULL);
13633  assert(cons != NULL);
13634  assert(var != NULL);
13635  assert(!SCIPisInfinity(scip, REALABS(lincoef)));
13636  assert(!SCIPisInfinity(scip, REALABS(sqrcoef)));
13637 
13638  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
13639  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
13640  {
13641  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
13642  return SCIP_INVALIDCALL;
13643  }
13644 
13645  SCIP_CALL( addQuadVarTerm(scip, cons, var, lincoef, sqrcoef) );
13646 
13647  return SCIP_OKAY;
13648 }
13649 
13650 /** Adds a linear coefficient for a quadratic variable.
13651  *
13652  * Variable will be added with square coefficient 0.0 if not existing yet.
13653  */
13655  SCIP* scip, /**< SCIP data structure */
13656  SCIP_CONS* cons, /**< constraint */
13657  SCIP_VAR* var, /**< variable */
13658  SCIP_Real coef /**< value to add to linear coefficient of variable */
13659  )
13660 {
13661  SCIP_CONSDATA* consdata;
13662  int pos;
13663 
13664  assert(scip != NULL);
13665  assert(cons != NULL);
13666  assert(var != NULL);
13667  assert(!SCIPisInfinity(scip, REALABS(coef)));
13668 
13669  if( SCIPisZero(scip, coef) )
13670  return SCIP_OKAY;
13671 
13672  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
13673  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
13674  {
13675  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
13676  return SCIP_INVALIDCALL;
13677  }
13678 
13679  consdata = SCIPconsGetData(cons);
13680  assert(consdata != NULL);
13681 
13682  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var, &pos) );
13683  if( pos < 0 )
13684  {
13685  SCIP_CALL( addQuadVarTerm(scip, cons, var, coef, 0.0) );
13686  return SCIP_OKAY;
13687  }
13688  assert(pos < consdata->nquadvars);
13689  assert(consdata->quadvarterms[pos].var == var);
13690 
13691  consdata->quadvarterms[pos].lincoef += coef;
13692 
13693  /* update flags and invalid activities */
13694  consdata->ispropagated = FALSE;
13695  consdata->ispresolved = consdata->ispresolved && !SCIPisZero(scip, consdata->quadvarterms[pos].lincoef);
13696 
13697  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
13698  consdata->activity = SCIP_INVALID;
13699 
13700  return SCIP_OKAY;
13701 }
13702 
13703 /** Adds a square coefficient for a quadratic variable.
13704  *
13705  * Variable will be added with linear coefficient 0.0 if not existing yet.
13706  */
13708  SCIP* scip, /**< SCIP data structure */
13709  SCIP_CONS* cons, /**< constraint */
13710  SCIP_VAR* var, /**< variable */
13711  SCIP_Real coef /**< value to add to square coefficient of variable */
13712  )
13713 {
13714  SCIP_CONSDATA* consdata;
13715  int pos;
13716 
13717  assert(scip != NULL);
13718  assert(cons != NULL);
13719  assert(var != NULL);
13720  assert(!SCIPisInfinity(scip, REALABS(coef)));
13721 
13722  if( SCIPisZero(scip, coef) )
13723  return SCIP_OKAY;
13724 
13725  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
13726  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
13727  {
13728  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
13729  return SCIP_INVALIDCALL;
13730  }
13731 
13732  consdata = SCIPconsGetData(cons);
13733  assert(consdata != NULL);
13734 
13735  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var, &pos) );
13736  if( pos < 0 )
13737  {
13738  SCIP_CALL( addQuadVarTerm(scip, cons, var, 0.0, coef) );
13739  return SCIP_OKAY;
13740  }
13741  assert(pos < consdata->nquadvars);
13742  assert(consdata->quadvarterms[pos].var == var);
13743 
13744  consdata->quadvarterms[pos].sqrcoef += coef;
13745 
13746  /* update flags and invalid activities */
13747  consdata->isconvex = FALSE;
13748  consdata->isconcave = FALSE;
13749  consdata->iscurvchecked = FALSE;
13750  consdata->ispropagated = FALSE;
13751  consdata->ispresolved = consdata->ispresolved && !SCIPisZero(scip, consdata->quadvarterms[pos].sqrcoef);
13752 
13753  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
13754  consdata->activity = SCIP_INVALID;
13755 
13756  return SCIP_OKAY;
13757 }
13758 
13759 /** Adds a bilinear term to a quadratic constraint.
13760  *
13761  * Variables will be added with linear and square coefficient 0.0 if not existing yet.
13762  * If variables are equal, only the square coefficient of the variable is updated.
13763  */
13765  SCIP* scip, /**< SCIP data structure */
13766  SCIP_CONS* cons, /**< constraint */
13767  SCIP_VAR* var1, /**< first variable */
13768  SCIP_VAR* var2, /**< second variable */
13769  SCIP_Real coef /**< coefficient of bilinear term */
13770  )
13771 {
13772  SCIP_CONSDATA* consdata;
13773  int var1pos;
13774  int var2pos;
13775 
13776  assert(scip != NULL);
13777  assert(cons != NULL);
13778  assert(var1 != NULL);
13779  assert(var2 != NULL);
13780  assert(!SCIPisInfinity(scip, REALABS(coef)));
13781 
13782  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
13783  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
13784  {
13785  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
13786  return SCIP_INVALIDCALL;
13787  }
13788 
13789  if( var1 == var2 )
13790  {
13791  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, cons, var1, coef) );
13792  return SCIP_OKAY;
13793  }
13794 
13795  consdata = SCIPconsGetData(cons);
13796  assert(consdata != NULL);
13797 
13798  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var1, &var1pos) );
13799  if( var1pos < 0 )
13800  {
13801  SCIP_CALL( addQuadVarTerm(scip, cons, var1, 0.0, 0.0) );
13802  var1pos = consdata->nquadvars-1;
13803  }
13804 
13805  if( !consdata->quadvarssorted )
13806  {
13807  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
13808  /* sorting may change the position of var1 */
13809  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var1, &var1pos) );
13810  assert(var1pos >= 0);
13811  }
13812 
13813  assert(consdata->quadvarssorted);
13814  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var2, &var2pos) );
13815  if( var2pos < 0 )
13816  {
13817  SCIP_CALL( addQuadVarTerm(scip, cons, var2, 0.0, 0.0) );
13818  var2pos = consdata->nquadvars-1;
13819  }
13820 
13821  assert(consdata->quadvarterms[var1pos].var == var1);
13822  assert(consdata->quadvarterms[var2pos].var == var2);
13823 
13824  SCIP_CALL( addBilinearTerm(scip, cons, var1pos, var2pos, coef) );
13825 
13826  return SCIP_OKAY;
13827 }
13828 
13829 /** Gets the quadratic constraint as a nonlinear row representation. */
13831  SCIP* scip, /**< SCIP data structure */
13832  SCIP_CONS* cons, /**< constraint */
13833  SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
13834  )
13835 {
13836  SCIP_CONSDATA* consdata;
13837 
13838  assert(cons != NULL);
13839  assert(nlrow != NULL);
13840 
13841  consdata = SCIPconsGetData(cons);
13842  assert(consdata != NULL);
13843 
13844  if( consdata->nlrow == NULL )
13845  {
13846  SCIP_CALL( createNlRow(scip, cons) );
13847  }
13848  assert(consdata->nlrow != NULL);
13849  *nlrow = consdata->nlrow;
13850 
13851  return SCIP_OKAY;
13852 }
13853 
13854 /** Gets the number of variables in the linear term of a quadratic constraint. */
13856  SCIP* scip, /**< SCIP data structure */
13857  SCIP_CONS* cons /**< constraint */
13858  )
13859 {
13860  assert(cons != NULL);
13861  assert(SCIPconsGetData(cons) != NULL);
13862 
13863  return SCIPconsGetData(cons)->nlinvars;
13864 }
13865 
13866 /** Gets the variables in the linear part of a quadratic constraint.
13867  * Length is given by SCIPgetNLinearVarsQuadratic.
13868  */
13870  SCIP* scip, /**< SCIP data structure */
13871  SCIP_CONS* cons /**< constraint */
13872  )
13873 {
13874  assert(cons != NULL);
13875  assert(SCIPconsGetData(cons) != NULL);
13876 
13877  return SCIPconsGetData(cons)->linvars;
13878 }
13879 
13880 /** Gets the coefficients in the linear part of a quadratic constraint.
13881  * Length is given by SCIPgetNLinearVarsQuadratic.
13882  */
13884  SCIP* scip, /**< SCIP data structure */
13885  SCIP_CONS* cons /**< constraint */
13886  )
13887 {
13888  assert(cons != NULL);
13889  assert(SCIPconsGetData(cons) != NULL);
13890 
13891  return SCIPconsGetData(cons)->lincoefs;
13892 }
13893 
13894 /** Gets the number of quadratic variable terms of a quadratic constraint.
13895  */
13897  SCIP* scip, /**< SCIP data structure */
13898  SCIP_CONS* cons /**< constraint */
13899  )
13900 {
13901  assert(cons != NULL);
13902  assert(SCIPconsGetData(cons) != NULL);
13903 
13904  return SCIPconsGetData(cons)->nquadvars;
13905 }
13906 
13907 /** Gets the quadratic variable terms of a quadratic constraint.
13908  * Length is given by SCIPgetNQuadVarTermsQuadratic.
13909  */
13911  SCIP* scip, /**< SCIP data structure */
13912  SCIP_CONS* cons /**< constraint */
13913  )
13914 {
13915  assert(cons != NULL);
13916  assert(SCIPconsGetData(cons) != NULL);
13917 
13918  return SCIPconsGetData(cons)->quadvarterms;
13919 }
13920 
13921 /** Ensures that quadratic variable terms are sorted. */
13923  SCIP* scip, /**< SCIP data structure */
13924  SCIP_CONS* cons /**< constraint */
13925  )
13926 {
13927  assert(cons != NULL);
13928  assert(SCIPconsGetData(cons) != NULL);
13929 
13931 
13932  return SCIP_OKAY;
13933 }
13934 
13935 /** Finds the position of a quadratic variable term for a given variable.
13936  *
13937  * @note If the quadratic variable terms have not been sorted before, then a search may reorder the current order of the terms.
13938  */
13940  SCIP* scip, /**< SCIP data structure */
13941  SCIP_CONS* cons, /**< constraint */
13942  SCIP_VAR* var, /**< variable to search for */
13943  int* pos /**< buffer to store position of quadvarterm for var, or -1 if not found */
13944  )
13945 {
13946  assert(cons != NULL);
13947  assert(SCIPconsGetData(cons) != NULL);
13948  assert(var != NULL);
13949  assert(pos != NULL);
13950 
13951  SCIP_CALL( consdataFindQuadVarTerm(scip, SCIPconsGetData(cons), var, pos) );
13952 
13953  return SCIP_OKAY;
13954 }
13955 
13956 /** Gets the number of bilinear terms of a quadratic constraint. */
13958  SCIP* scip, /**< SCIP data structure */
13959  SCIP_CONS* cons /**< constraint */
13960  )
13961 {
13962  assert(cons != NULL);
13963  assert(SCIPconsGetData(cons) != NULL);
13964 
13965  return SCIPconsGetData(cons)->nbilinterms;
13966 }
13967 
13968 /** Gets the bilinear terms of a quadratic constraint.
13969  * Length is given by SCIPgetNBilinTermQuadratic.
13970  */
13972  SCIP* scip, /**< SCIP data structure */
13973  SCIP_CONS* cons /**< constraint */
13974  )
13975 {
13976  assert(cons != NULL);
13977  assert(SCIPconsGetData(cons) != NULL);
13978 
13979  return SCIPconsGetData(cons)->bilinterms;
13980 }
13981 
13982 /** Gets the left hand side of a quadratic constraint. */
13984  SCIP* scip, /**< SCIP data structure */
13985  SCIP_CONS* cons /**< constraint */
13986  )
13987 {
13988  assert(cons != NULL);
13989  assert(SCIPconsGetData(cons) != NULL);
13990 
13991  return SCIPconsGetData(cons)->lhs;
13992 }
13993 
13994 /** Gets the right hand side of a quadratic constraint. */
13996  SCIP* scip, /**< SCIP data structure */
13997  SCIP_CONS* cons /**< constraint */
13998  )
13999 {
14000  assert(cons != NULL);
14001  assert(SCIPconsGetData(cons) != NULL);
14002 
14003  return SCIPconsGetData(cons)->rhs;
14004 }
14005 
14006 /** get index of a variable in linvars that may be decreased without making any other constraint infeasible, or -1 if none */
14008  SCIP* scip, /**< SCIP data structure */
14009  SCIP_CONS* cons /**< constraint */
14010  )
14011 {
14012  SCIP_CONSDATA* consdata;
14013 
14014  assert(cons != NULL);
14015 
14016  consdata = SCIPconsGetData(cons);
14017  assert(consdata != NULL);
14018 
14019  /* check for a linear variable that can be increase or decreased without harming feasibility */
14020  consdataFindUnlockedLinearVar(scip, consdata);
14021 
14022  return consdata->linvar_maydecrease;
14023 }
14024 
14025 /** get index of a variable in linvars that may be increased without making any other constraint infeasible, or -1 if none */
14027  SCIP* scip, /**< SCIP data structure */
14028  SCIP_CONS* cons /**< constraint */
14029  )
14030 {
14031  SCIP_CONSDATA* consdata;
14032 
14033  assert(cons != NULL);
14034 
14035  consdata = SCIPconsGetData(cons);
14036  assert(consdata != NULL);
14037 
14038  /* check for a linear variable that can be increase or decreased without harming feasibility */
14039  consdataFindUnlockedLinearVar(scip, consdata);
14040 
14041  return consdata->linvar_mayincrease;
14042 }
14043 
14044 /** Check the quadratic function of a quadratic constraint for its semi-definiteness, if not done yet. */
14046  SCIP* scip, /**< SCIP data structure */
14047  SCIP_CONS* cons /**< constraint */
14048  )
14049 {
14050  assert(cons != NULL);
14051 
14052  SCIP_CALL( checkCurvature(scip, cons, TRUE) );
14053 
14054  return SCIP_OKAY;
14055 }
14056 
14057 /** Indicates whether the quadratic function of a quadratic constraint is (known to be) convex. */
14059  SCIP* scip, /**< SCIP data structure */
14060  SCIP_CONS* cons /**< constraint */
14061  )
14062 {
14063  SCIP_Bool determined;
14064 
14065  assert(cons != NULL);
14066  assert(SCIPconsGetData(cons) != NULL);
14067 
14068  checkCurvatureEasy(scip, cons, &determined, FALSE);
14069  assert(determined);
14070 
14071  return (SCIPconsGetData(cons)->isconvex);
14072 }
14073 
14074 /** Indicates whether the quadratic function of a quadratic constraint is (known to be) concave. */
14076  SCIP* scip, /**< SCIP data structure */
14077  SCIP_CONS* cons /**< constraint */
14078  )
14079 {
14080  SCIP_Bool determined;
14081 
14082  assert(cons != NULL);
14083  assert(SCIPconsGetData(cons) != NULL);
14084 
14085  checkCurvatureEasy(scip, cons, &determined, FALSE);
14086  assert(determined);
14087 
14088  return (SCIPconsGetData(cons)->isconcave);
14089 }
14090 
14091 /** Computes the violation of a constraint by a solution */
14093  SCIP* scip, /**< SCIP data structure */
14094  SCIP_CONS* cons, /**< constraint */
14095  SCIP_SOL* sol, /**< solution which violation to calculate, or NULL for LP solution */
14096  SCIP_Real* violation /**< pointer to store violation of constraint */
14097  )
14098 {
14099  SCIP_CONSHDLR* conshdlr;
14100  SCIP_CONSDATA* consdata;
14101  SCIP_Bool solviolbounds;
14102 
14103  assert(scip != NULL);
14104  assert(cons != NULL);
14105  assert(violation != NULL);
14106 
14107  conshdlr = SCIPconsGetHdlr(cons);
14108  assert(conshdlr != NULL);
14109 
14110  SCIP_CALL( computeViolation(scip, conshdlr, cons, sol, &solviolbounds) );
14111  /* we don't care here whether the solution violated variable bounds */
14112 
14113  consdata = SCIPconsGetData(cons);
14114  assert(consdata != NULL);
14115 
14116  *violation = MAX(consdata->lhsviol, consdata->rhsviol);
14117 
14118  return SCIP_OKAY;
14119 }
14120 
14121 /** Indicates whether the quadratic constraint is local w.r.t. the current local bounds.
14122  *
14123  * That is, checks whether each variable with a square term is fixed and for each bilinear term at least one variable is fixed.
14124  */
14126  SCIP* scip, /**< SCIP data structure */
14127  SCIP_CONS* cons /**< constraint */
14128  )
14129 {
14130  SCIP_CONSDATA* consdata;
14131  SCIP_VAR* var1;
14132  SCIP_VAR* var2;
14133  int i;
14134 
14135  assert(scip != NULL);
14136  assert(cons != NULL);
14137 
14138  consdata = SCIPconsGetData(cons);
14139  assert(consdata != NULL);
14140 
14141  /* check all square terms */
14142  for( i = 0; i < consdata->nquadvars; ++i )
14143  {
14144  if( consdata->quadvarterms[i].sqrcoef == 0.0 )
14145  continue;
14146 
14147  var1 = consdata->quadvarterms[i].var;
14148  assert(var1 != NULL);
14149 
14150  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var1), SCIPvarGetUbLocal(var1)) )
14151  return FALSE;
14152  }
14153 
14154  for( i = 0; i < consdata->nbilinterms; ++i )
14155  {
14156  var1 = consdata->bilinterms[i].var1;
14157  var2 = consdata->bilinterms[i].var2;
14158 
14159  assert(var1 != NULL);
14160  assert(var2 != NULL);
14161 
14162  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var1), SCIPvarGetUbLocal(var1)) &&
14163  ! SCIPisRelEQ(scip, SCIPvarGetLbLocal(var2), SCIPvarGetUbLocal(var2)) )
14164  return FALSE;
14165  }
14166 
14167  return TRUE;
14168 }
14169 
14170 /** Adds the constraint to an NLPI problem. */
14172  SCIP* scip, /**< SCIP data structure */
14173  SCIP_CONS* cons, /**< constraint */
14174  SCIP_NLPI* nlpi, /**< interface to NLP solver */
14175  SCIP_NLPIPROBLEM* nlpiprob, /**< NLPI problem where to add constraint */
14176  SCIP_HASHMAP* scipvar2nlpivar, /**< mapping from SCIP variables to variable indices in NLPI */
14177  SCIP_Bool names /**< whether to pass constraint names to NLPI */
14178  )
14179 {
14180  SCIP_CONSDATA* consdata;
14181  int nlininds;
14182  int* lininds;
14183  SCIP_Real* linvals;
14184  int nquadelems;
14185  SCIP_QUADELEM* quadelems;
14186  SCIP_VAR* othervar;
14187  const char* name;
14188  int j;
14189  int l;
14190  int lincnt;
14191  int quadcnt;
14192  int idx1;
14193  int idx2;
14194 
14195  assert(scip != NULL);
14196  assert(cons != NULL);
14197  assert(nlpi != NULL);
14198  assert(nlpiprob != NULL);
14199  assert(scipvar2nlpivar != NULL);
14200 
14201  consdata = SCIPconsGetData(cons);
14202  assert(consdata != NULL);
14203 
14204  /* count nonzeros in quadratic part */
14205  nlininds = consdata->nlinvars;
14206  nquadelems = consdata->nbilinterms;
14207  for( j = 0; j < consdata->nquadvars; ++j )
14208  {
14209  if( consdata->quadvarterms[j].sqrcoef != 0.0 )
14210  ++nquadelems;
14211  if( consdata->quadvarterms[j].lincoef != 0.0 )
14212  ++nlininds;
14213  }
14214 
14215  /* setup linear part */
14216  lininds = NULL;
14217  linvals = NULL;
14218  lincnt = 0;
14219  if( nlininds > 0 )
14220  {
14221  SCIP_CALL( SCIPallocBufferArray(scip, &lininds, nlininds) );
14222  SCIP_CALL( SCIPallocBufferArray(scip, &linvals, nlininds) );
14223 
14224  for( j = 0; j < consdata->nlinvars; ++j )
14225  {
14226  linvals[j] = consdata->lincoefs[j];
14227  assert(SCIPhashmapExists(scipvar2nlpivar, consdata->linvars[j]));
14228  lininds[j] = (int) (size_t) SCIPhashmapGetImage(scipvar2nlpivar, consdata->linvars[j]);
14229  }
14230 
14231  lincnt = consdata->nlinvars;
14232  }
14233 
14234  /* setup quadratic part */
14235  quadelems = NULL;
14236  if( nquadelems > 0 )
14237  {
14238  SCIP_CALL( SCIPallocBufferArray(scip, &quadelems, nquadelems) );
14239  }
14240  quadcnt = 0;
14241 
14242  for( j = 0; j < consdata->nquadvars; ++j )
14243  {
14244  assert(SCIPhashmapExists(scipvar2nlpivar, consdata->quadvarterms[j].var));
14245  idx1 = (int)(size_t)SCIPhashmapGetImage(scipvar2nlpivar, consdata->quadvarterms[j].var);
14246  if( consdata->quadvarterms[j].lincoef != 0.0 )
14247  {
14248  assert(lininds != NULL);
14249  assert(linvals != NULL);
14250  lininds[lincnt] = idx1;
14251  linvals[lincnt] = consdata->quadvarterms[j].lincoef;
14252  ++lincnt;
14253  }
14254 
14255  if( consdata->quadvarterms[j].sqrcoef != 0.0 )
14256  {
14257  assert(quadcnt < nquadelems);
14258  assert(quadelems != NULL);
14259  quadelems[quadcnt].idx1 = idx1;
14260  quadelems[quadcnt].idx2 = idx1;
14261  quadelems[quadcnt].coef = consdata->quadvarterms[j].sqrcoef;
14262  ++quadcnt;
14263  }
14264 
14265  for( l = 0; l < consdata->quadvarterms[j].nadjbilin; ++l )
14266  {
14267  othervar = consdata->bilinterms[consdata->quadvarterms[j].adjbilin[l]].var2;
14268  /* if othervar is on position 2, then we process this bilinear term later (or it was processed already) */
14269  if( othervar == consdata->quadvarterms[j].var )
14270  continue;
14271 
14272  assert(quadcnt < nquadelems);
14273  assert(quadelems != NULL);
14274  assert(SCIPhashmapExists(scipvar2nlpivar, othervar));
14275  idx2 = (int)(size_t)SCIPhashmapGetImage(scipvar2nlpivar, othervar);
14276  quadelems[quadcnt].idx1 = MIN(idx1, idx2);
14277  quadelems[quadcnt].idx2 = MAX(idx1, idx2);
14278  quadelems[quadcnt].coef = consdata->bilinterms[consdata->quadvarterms[j].adjbilin[l]].coef;
14279  ++quadcnt;
14280  }
14281  }
14282 
14283  assert(quadcnt == nquadelems);
14284  assert(lincnt == nlininds);
14285 
14286  name = names ? SCIPconsGetName(cons) : NULL;
14287 
14288  SCIP_CALL( SCIPnlpiAddConstraints(nlpi, nlpiprob, 1,
14289  &consdata->lhs, &consdata->rhs,
14290  &nlininds, &lininds, &linvals ,
14291  &nquadelems, &quadelems,
14292  NULL, NULL, &name) );
14293 
14294  SCIPfreeBufferArrayNull(scip, &quadelems);
14295  SCIPfreeBufferArrayNull(scip, &lininds);
14296  SCIPfreeBufferArrayNull(scip, &linvals);
14297 
14298  return SCIP_OKAY;
14299 }
14300 
14301 
14302 /** sets the left hand side of a quadratic constraint
14303  *
14304  * @note This method may only be called during problem creation stage for an original constraint.
14305  */
14307  SCIP* scip, /**< SCIP data structure */
14308  SCIP_CONS* cons, /**< constraint data */
14309  SCIP_Real lhs /**< new left hand side */
14310  )
14311 {
14312  SCIP_CONSDATA* consdata;
14313 
14314  assert(scip != NULL);
14315  assert(cons != NULL);
14316  assert(!SCIPisInfinity(scip, lhs));
14317 
14318  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14319  {
14320  SCIPerrorMessage("constraint is not quadratic\n");
14321  return SCIP_INVALIDDATA;
14322  }
14323 
14324  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) )
14325  {
14326  SCIPerrorMessage("method may only be called during problem creation stage for original constraints\n");
14327  return SCIP_INVALIDDATA;
14328  }
14329 
14330  consdata = SCIPconsGetData(cons);
14331  assert(consdata != NULL);
14332  assert(!SCIPisInfinity(scip, consdata->lhs));
14333 
14334  /* adjust value to not be smaller than -inf */
14335  if( SCIPisInfinity(scip, -lhs) )
14336  lhs = -SCIPinfinity(scip);
14337 
14338  /* check for lhs <= rhs */
14339  if( !SCIPisLE(scip, lhs, consdata->rhs) )
14340  return SCIP_INVALIDDATA;
14341 
14342  consdata->lhs = lhs;
14343 
14344  return SCIP_OKAY;
14345 }
14346 
14347 /** sets the right hand side of a quadratic constraint
14348  *
14349  * @note This method may only be called during problem creation stage for an original constraint.
14350  */
14352  SCIP* scip, /**< SCIP data structure */
14353  SCIP_CONS* cons, /**< constraint data */
14354  SCIP_Real rhs /**< new right hand side */
14355  )
14356 {
14357  SCIP_CONSDATA* consdata;
14358 
14359  assert(scip != NULL);
14360  assert(cons != NULL);
14361  assert(!SCIPisInfinity(scip, -rhs));
14362 
14363  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14364  {
14365  SCIPerrorMessage("constraint is not quadratic\n");
14366  return SCIP_INVALIDDATA;
14367  }
14368 
14369  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) )
14370  {
14371  SCIPerrorMessage("method may only be called during problem creation stage for original constraints\n");
14372  return SCIP_INVALIDDATA;
14373  }
14374 
14375  consdata = SCIPconsGetData(cons);
14376  assert(consdata != NULL);
14377  assert(!SCIPisInfinity(scip, -consdata->rhs));
14378 
14379  /* adjust value to not be greater than inf */
14380  if( SCIPisInfinity(scip, rhs) )
14381  rhs = SCIPinfinity(scip);
14382 
14383  /* check for lhs <= rhs */
14384  if( !SCIPisLE(scip, consdata->lhs, rhs) )
14385  return SCIP_INVALIDDATA;
14386 
14387  consdata->rhs = rhs;
14388 
14389  return SCIP_OKAY;
14390 }
14391 
14392 /** gets the feasibility of the quadratic constraint in the given solution */
14394  SCIP* scip, /**< SCIP data structure */
14395  SCIP_CONS* cons, /**< constraint data */
14396  SCIP_SOL* sol, /**< solution, or NULL to use current node's solution */
14397  SCIP_Real* feasibility /**< pointer to store the feasibility */
14398  )
14399 {
14400  SCIP_CONSDATA* consdata;
14401  SCIP_Bool solviolbounds;
14402 
14403  assert(scip != NULL);
14404  assert(cons != NULL);
14405  assert(feasibility != NULL);
14406 
14407  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14408  {
14409  SCIPerrorMessage("constraint is not quadratic\n");
14410  SCIPABORT();
14411  }
14412 
14413  SCIP_CALL( computeViolation(scip, SCIPconsGetHdlr(cons), cons, sol, &solviolbounds) );
14414 
14415  consdata = SCIPconsGetData(cons);
14416  assert(consdata != NULL);
14417 
14418  if( SCIPisInfinity(scip, consdata->rhs) && SCIPisInfinity(scip, -consdata->lhs) )
14419  *feasibility = SCIPinfinity(scip);
14420  else if( SCIPisInfinity(scip, -consdata->lhs) )
14421  *feasibility = (consdata->rhs - consdata->activity);
14422  else if( SCIPisInfinity(scip, consdata->rhs) )
14423  *feasibility = (consdata->activity - consdata->lhs);
14424  else
14425  {
14426  assert(!SCIPisInfinity(scip, -consdata->rhs));
14427  assert(!SCIPisInfinity(scip, consdata->lhs));
14428  *feasibility = MIN( consdata->rhs - consdata->activity, consdata->activity - consdata->lhs );
14429  }
14430 
14431  return SCIP_OKAY;
14432 }
14433 
14434 /** gets the activity of the quadratic constraint in the given solution */
14436  SCIP* scip, /**< SCIP data structure */
14437  SCIP_CONS* cons, /**< constraint data */
14438  SCIP_SOL* sol, /**< solution, or NULL to use current node's solution */
14439  SCIP_Real* activity /**< pointer to store the activity */
14440  )
14441 {
14442  SCIP_CONSDATA* consdata;
14443  SCIP_Bool solviolbounds;
14444 
14445  assert(scip != NULL);
14446  assert(cons != NULL);
14447  assert(activity != NULL);
14448 
14449  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14450  {
14451  SCIPerrorMessage("constraint is not quadratic\n");
14452  SCIPABORT();
14453  }
14454 
14455  SCIP_CALL( computeViolation(scip, SCIPconsGetHdlr(cons), cons, sol, &solviolbounds) );
14456 
14457  consdata = SCIPconsGetData(cons);
14458  assert(consdata != NULL);
14459 
14460  *activity = consdata->activity;
14461 
14462  return SCIP_OKAY;
14463 }
14464 
14465 /** changes the linear coefficient value for a given quadratic variable in a quadratic constraint data; if not
14466  * available, it adds it
14467  *
14468  * @note this is only allowed for original constraints and variables in problem creation stage
14469  */
14471  SCIP* scip, /**< SCIP data structure */
14472  SCIP_CONS* cons, /**< constraint data */
14473  SCIP_VAR* var, /**< quadratic variable */
14474  SCIP_Real coef /**< new coefficient */
14475  )
14476 {
14477  SCIP_CONSDATA* consdata;
14478  SCIP_Bool found;
14479  int i;
14480 
14481  assert(scip != NULL);
14482  assert(cons != NULL);
14483  assert(var != NULL);
14484 
14485  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14486  {
14487  SCIPerrorMessage("constraint is not quadratic\n");
14488  return SCIP_INVALIDDATA;
14489  }
14490 
14491  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) || !SCIPvarIsOriginal(var) )
14492  {
14493  SCIPerrorMessage("method may only be called during problem creation stage for original constraints and variables\n");
14494  return SCIP_INVALIDDATA;
14495  }
14496 
14497  consdata = SCIPconsGetData(cons);
14498  assert(consdata != NULL);
14499 
14500  /* check all quadratic variables */
14501  found = FALSE;
14502  for( i = 0; i < consdata->nquadvars; ++i )
14503  {
14504  if( var == consdata->quadvarterms[i].var )
14505  {
14506  if( found || SCIPisZero(scip, coef) )
14507  {
14508  consdata->quadvarterms[i].lincoef = 0.0;
14509 
14510  /* remember to merge quadratic variable terms */
14511  consdata->quadvarsmerged = FALSE;
14512  }
14513  else
14514  consdata->quadvarterms[i].lincoef = coef;
14515 
14516  found = TRUE;
14517  }
14518  }
14519 
14520  /* check all linear variables */
14521  i = 0;
14522  while( i < consdata->nlinvars )
14523  {
14524  if( var == consdata->linvars[i] )
14525  {
14526  if( found || SCIPisZero(scip, coef) )
14527  {
14528  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
14529 
14530  /* decrease i by one since otherwise we would skip the coefficient which has been switched to position i */
14531  i--;
14532  }
14533  else
14534  {
14535  SCIP_CALL( chgLinearCoefPos(scip, cons, i, coef) );
14536  }
14537 
14538  found = TRUE;
14539  }
14540  i++;
14541  }
14542 
14543  /* add linear term if necessary */
14544  if( !found && !SCIPisZero(scip, coef) )
14545  {
14546  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
14547  }
14548 
14549  consdata->ispropagated = FALSE;
14550  consdata->ispresolved = FALSE;
14551 
14552  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
14553  consdata->activity = SCIP_INVALID;
14554 
14555  return SCIP_OKAY;
14556 }
14557 
14558 /** changes the square coefficient value for a given quadratic variable in a quadratic constraint data; if not
14559  * available, it adds it
14560  *
14561  * @note this is only allowed for original constraints and variables in problem creation stage
14562  */
14564  SCIP* scip, /**< SCIP data structure */
14565  SCIP_CONS* cons, /**< constraint data */
14566  SCIP_VAR* var, /**< quadratic variable */
14567  SCIP_Real coef /**< new coefficient */
14568  )
14569 {
14570  SCIP_CONSDATA* consdata;
14571  SCIP_Bool found;
14572  int i;
14573 
14574  assert(scip != NULL);
14575  assert(cons != NULL);
14576  assert(var != NULL);
14577  assert(!SCIPisInfinity(scip, REALABS(coef)));
14578 
14579  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14580  {
14581  SCIPerrorMessage("constraint is not quadratic\n");
14582  return SCIP_INVALIDDATA;
14583  }
14584 
14585  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) || !SCIPvarIsOriginal(var) )
14586  {
14587  SCIPerrorMessage("method may only be called during problem creation stage for original constraints and variables\n");
14588  return SCIP_INVALIDDATA;
14589  }
14590 
14591  consdata = SCIPconsGetData(cons);
14592  assert(consdata != NULL);
14593 
14594  /* find the quadratic variable and change its quadratic coefficient */
14595  found = FALSE;
14596  for( i = 0; i < consdata->nquadvars; ++i )
14597  {
14598  if( var == consdata->quadvarterms[i].var )
14599  {
14600  consdata->quadvarterms[i].sqrcoef = (found || SCIPisZero(scip, coef)) ? 0.0 : coef;
14601  found = TRUE;
14602  }
14603  }
14604 
14605  /* add bilinear term if necessary */
14606  if( !found && !SCIPisZero(scip, coef) )
14607  {
14608  SCIP_CALL( addQuadVarTerm(scip, cons, var, 0.0, coef) );
14609  }
14610 
14611  /* update flags and invalidate activities */
14612  consdata->isconvex = FALSE;
14613  consdata->isconcave = FALSE;
14614  consdata->iscurvchecked = FALSE;
14615  consdata->ispropagated = FALSE;
14616  consdata->ispresolved = FALSE;
14617 
14618  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
14619  consdata->activity = SCIP_INVALID;
14620 
14621  /* remember to merge quadratic variable terms */
14622  consdata->quadvarsmerged = FALSE;
14623 
14624  return SCIP_OKAY;
14625 }
14626 
14627 /** changes the bilinear coefficient value for a given quadratic variable in a quadratic constraint data; if not
14628  * available, it adds it
14629  *
14630  * @note this is only allowed for original constraints and variables in problem creation stage
14631  */
14633  SCIP* scip, /**< SCIP data structure */
14634  SCIP_CONS* cons, /**< constraint */
14635  SCIP_VAR* var1, /**< first variable */
14636  SCIP_VAR* var2, /**< second variable */
14637  SCIP_Real coef /**< coefficient of bilinear term */
14638  )
14639 {
14640  SCIP_CONSDATA* consdata;
14641  SCIP_Bool found;
14642  int i;
14643 
14644  assert(scip != NULL);
14645  assert(cons != NULL);
14646  assert(var1 != NULL);
14647  assert(var2 != NULL);
14648  assert(!SCIPisInfinity(scip, REALABS(coef)));
14649 
14650  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14651  {
14652  SCIPerrorMessage("constraint is not quadratic\n");
14653  return SCIP_INVALIDDATA;
14654  }
14655 
14656  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) || !SCIPvarIsOriginal(var1) || !SCIPvarIsOriginal(var2) )
14657  {
14658  SCIPerrorMessage("method may only be called during problem creation stage for original constraints and variables\n");
14659  return SCIP_INVALIDDATA;
14660  }
14661 
14662  if( var1 == var2 )
14663  {
14664  SCIP_CALL( SCIPchgSquareCoefQuadratic(scip, cons, var1, coef) );
14665  return SCIP_OKAY;
14666  }
14667 
14668  consdata = SCIPconsGetData(cons);
14669  assert(consdata != NULL);
14670 
14671  /* search array of bilinear terms */
14672  found = FALSE;
14673  for( i = 0; i < consdata->nbilinterms; ++i )
14674  {
14675  if( (consdata->bilinterms[i].var1 == var1 && consdata->bilinterms[i].var2 == var2) ||
14676  (consdata->bilinterms[i].var1 == var2 && consdata->bilinterms[i].var2 == var1) )
14677  {
14678  if( found || SCIPisZero(scip, coef) )
14679  {
14680  consdata->bilinterms[i].coef = 0.0;
14681 
14682  /* remember to merge bilinear terms */
14683  consdata->bilinmerged = FALSE;
14684  }
14685  else
14686  consdata->bilinterms[i].coef = coef;
14687  found = TRUE;
14688  }
14689  }
14690 
14691  /* add bilinear term if necessary */
14692  if( !found )
14693  {
14694  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, cons, var1, var2, coef) );
14695  }
14696 
14697  /* update flags and invalidate activities */
14698  consdata->isconvex = FALSE;
14699  consdata->isconcave = FALSE;
14700  consdata->iscurvchecked = FALSE;
14701  consdata->ispropagated = FALSE;
14702  consdata->ispresolved = FALSE;
14703 
14704  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
14705  consdata->activity = SCIP_INVALID;
14706 
14707  return SCIP_OKAY;
14708 }
14709 
14710 /** creates a SCIP_ROWPREP datastructure
14711  *
14712  * Initial cut represents 0 <= 0.
14713  */
14715  SCIP* scip, /**< SCIP data structure */
14716  SCIP_ROWPREP** rowprep, /**< buffer to store pointer to rowprep */
14717  SCIP_SIDETYPE sidetype, /**< whether cut will be or lower-equal or larger-equal type */
14718  SCIP_Bool local /**< whether cut will be valid only locally */
14719  )
14720 {
14721  assert(scip != NULL);
14722  assert(rowprep != NULL);
14723 
14724  SCIP_CALL( SCIPallocBlockMemory(scip, rowprep) );
14725  BMSclearMemory(*rowprep);
14726 
14727  (*rowprep)->sidetype = sidetype;
14728  (*rowprep)->local = local;
14729 
14730  return SCIP_OKAY;
14731 }
14732 
14733 /** frees a SCIP_ROWPREP datastructure */
14734 void SCIPfreeRowprep(
14735  SCIP* scip, /**< SCIP data structure */
14736  SCIP_ROWPREP** rowprep /**< pointer that stores pointer to rowprep */
14737  )
14738 {
14739  assert(scip != NULL);
14740  assert(rowprep != NULL);
14741  assert(*rowprep != NULL);
14742 
14743  SCIPfreeBlockMemoryArrayNull(scip, &(*rowprep)->vars, (*rowprep)->varssize);
14744  SCIPfreeBlockMemoryArrayNull(scip, &(*rowprep)->coefs, (*rowprep)->varssize);
14745  SCIPfreeBlockMemory(scip, rowprep);
14746 }
14747 
14748 /** creates a copy of a SCIP_ROWPREP datastructure */
14750  SCIP* scip, /**< SCIP data structure */
14751  SCIP_ROWPREP** target, /**< buffer to store pointer of rowprep copy */
14752  SCIP_ROWPREP* source /**< rowprep to copy */
14753  )
14754 {
14755  assert(scip != NULL);
14756  assert(target != NULL);
14757  assert(source != NULL);
14758 
14759  SCIP_CALL( SCIPduplicateBlockMemory(scip, target, source) );
14760  if( source->coefs != NULL )
14761  {
14762  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*target)->coefs, source->coefs, source->varssize) );
14763  }
14764  if( source->vars != NULL )
14765  {
14766  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*target)->vars, source->vars, source->varssize) );
14767  }
14768 
14769  return SCIP_OKAY;
14770 }
14771 
14772 /** ensures that rowprep has space for at least given number of additional terms
14773  *
14774  * Useful when knowing in advance how many terms will be added.
14775  */
14777  SCIP* scip, /**< SCIP data structure */
14778  SCIP_ROWPREP* rowprep, /**< rowprep */
14779  int size /**< number of additional terms for which to alloc space in rowprep */
14780  )
14781 {
14782  int oldsize;
14783 
14784  assert(scip != NULL);
14785  assert(rowprep != NULL);
14786  assert(size >= 0);
14787 
14788  if( rowprep->varssize >= rowprep->nvars + size )
14789  return SCIP_OKAY; /* already enough space left */
14790 
14791  /* realloc vars and coefs array */
14792  oldsize = rowprep->varssize;
14793  rowprep->varssize = SCIPcalcMemGrowSize(scip, rowprep->nvars + size);
14794 
14795  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &rowprep->vars, oldsize, rowprep->varssize) );
14796  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &rowprep->coefs, oldsize, rowprep->varssize) );
14797 
14798  return SCIP_OKAY;
14799 }
14800 
14801 /** prints a rowprep */
14802 void SCIPprintRowprep(
14803  SCIP* scip, /**< SCIP data structure */
14804  SCIP_ROWPREP* rowprep, /**< rowprep to be printed */
14805  FILE* file /**< file to print to, or NULL for stdout */
14806  )
14807 {
14808  int i;
14809 
14810  assert(scip != NULL);
14811  assert(rowprep != NULL);
14812 
14813  if( *rowprep->name != '\0' )
14814  {
14815  SCIPinfoMessage(scip, file, "[%s](%c) ", rowprep->name, rowprep->local ? 'l' : 'g');
14816  }
14817 
14818  for( i = 0; i < rowprep->nvars; ++i )
14819  {
14820  SCIPinfoMessage(scip, file, "%+g*<%s> ", rowprep->coefs[i], SCIPvarGetName(rowprep->vars[i]));
14821  }
14822 
14823  SCIPinfoMessage(scip, file, rowprep->sidetype == SCIP_SIDETYPE_LEFT ? ">= %g\n" : "<= %g\n", rowprep->side);
14824 }
14825 
14826 /** adds a term coef*var to a rowprep */
14828  SCIP* scip, /**< SCIP data structure */
14829  SCIP_ROWPREP* rowprep, /**< rowprep */
14830  SCIP_VAR* var, /**< variable to add */
14831  SCIP_Real coef /**< coefficient to add */
14832  )
14833 {
14834  assert(scip != NULL);
14835  assert(rowprep != NULL);
14836  assert(var != NULL);
14837 
14838  if( coef == 0.0 )
14839  return SCIP_OKAY;
14840 
14841  SCIP_CALL( SCIPensureRowprepSize(scip, rowprep, 1) );
14842  assert(rowprep->varssize > rowprep->nvars);
14843 
14844  rowprep->vars[rowprep->nvars] = var;
14845  rowprep->coefs[rowprep->nvars] = coef;
14846  ++rowprep->nvars;
14847 
14848  return SCIP_OKAY;
14849 }
14850 
14851 /** adds several terms coef*var to a rowprep */
14853  SCIP* scip, /**< SCIP data structure */
14854  SCIP_ROWPREP* rowprep, /**< rowprep */
14855  int nvars, /**< number of terms to add */
14856  SCIP_VAR** vars, /**< variables to add */
14857  SCIP_Real* coefs /**< coefficients to add */
14858  )
14859 {
14860  assert(scip != NULL);
14861  assert(rowprep != NULL);
14862  assert(vars != NULL || nvars == 0);
14863  assert(coefs != NULL || nvars == 0);
14864 
14865  if( nvars == 0 )
14866  return SCIP_OKAY;
14867 
14868  SCIP_CALL( SCIPensureRowprepSize(scip, rowprep, nvars) );
14869  assert(rowprep->varssize >= rowprep->nvars + nvars);
14870 
14871  /*lint --e{866} */
14872  BMScopyMemoryArray(rowprep->vars + rowprep->nvars, vars, nvars);
14873  BMScopyMemoryArray(rowprep->coefs + rowprep->nvars, coefs, nvars);
14874  rowprep->nvars += nvars;
14875 
14876  return SCIP_OKAY;
14877 }
14878 
14879 #ifdef NDEBUG
14880 #undef SCIPaddRowprepSide
14881 #undef SCIPaddRowprepConstant
14882 #endif
14883 
14884 /** adds constant value to side of rowprep */
14885 void SCIPaddRowprepSide(
14886  SCIP_ROWPREP* rowprep, /**< rowprep */
14887  SCIP_Real side /**< constant value to be added to side */
14888  )
14889 {
14890  assert(rowprep != NULL);
14891 
14892  rowprep->side += side;
14893 }
14894 
14895 /** adds constant term to rowprep
14896  *
14897  * Substracts constant from side.
14898  */
14900  SCIP_ROWPREP* rowprep, /**< rowprep */
14901  SCIP_Real constant /**< constant value to be added */
14902  )
14903 {
14904  assert(rowprep != NULL);
14905 
14906  SCIPaddRowprepSide(rowprep, -constant);
14907 }
14908 
14909 /* computes violation of cut in a given solution
14910  *
14911  * If scaling == 'g', assumes that terms in rowprep are sorted by abs value of coef, in decreasing order.
14912  *
14913  * @param scaling 'o' for no scaling, 'g' for scaling by the absolute value of the maximal coefficient, or 's' for scaling by side
14914  */
14916  SCIP* scip, /**< SCIP data structure */
14917  SCIP_ROWPREP* rowprep, /**< rowprep to be turned into a row */
14918  SCIP_SOL* sol, /**< solution or NULL for LP solution */
14919  char scaling /**< how to scale cut violation: o, g, or s */
14920  )
14921 {
14922  SCIP_Real activity;
14923  SCIP_Real viol;
14924  int i;
14925 
14926  activity = -rowprep->side;
14927  for( i = 0; i < rowprep->nvars; ++i )
14928  {
14929  /* Loose variable have the best bound as LP solution value.
14930  * HOWEVER, they become column variables when they are added to a row (via SCIPaddVarsToRow below).
14931  * When this happens, their LP solution value changes to 0.0!
14932  * So when calculating the row activity for an LP solution, we treat loose variable as if they were already column variables.
14933  */
14934  if( sol != NULL || SCIPvarGetStatus(rowprep->vars[i]) != SCIP_VARSTATUS_LOOSE )
14935  activity += rowprep->coefs[i] * SCIPgetSolVal(scip, sol, rowprep->vars[i]);
14936  }
14937 
14938  if( rowprep->sidetype == SCIP_SIDETYPE_RIGHT )
14939  /* cut is activity <= 0.0 -> violation is activity, if positive */
14940  viol = MAX(activity, 0.0);
14941  else
14942  /* cut is activity >= 0.0 -> violation is -activity, if positive */
14943  viol = MAX(-activity, 0.0);
14944 
14945  switch( scaling )
14946  {
14947  case 'o' :
14948  break;
14949 
14950  case 'g' :
14951  /* in difference to SCIPgetCutEfficacy, we scale by norm only if the norm is > 1.0 this avoid finding cuts
14952  * efficient which are only very slightly violated
14953  * CPLEX does not seem to scale row coefficients up too
14954  * also we use infinity norm, since that seem to be the usual scaling strategy in LP solvers (equilibrium scaling)
14955  */
14956  if( rowprep->nvars > 0 ) /*lint --e{666} */
14957  viol /= MAX(1.0, REALABS(rowprep->coefs[0]));
14958  break;
14959 
14960  case 's' :
14961  {
14962  /*lint --e{666} */
14963  viol /= MAX(1.0, REALABS(rowprep->side));
14964  break;
14965  }
14966 
14967  default:
14968  SCIPerrorMessage("Unknown scaling method '%c'.", scaling);
14969  SCIPABORT();
14970  return SCIP_INVALID;
14971  }
14972 
14973  return viol;
14974 }
14975 
14976 /** Merge terms that use same variable and eliminate zero coefficients.
14977  *
14978  * Terms are sorted by variable (@see SCIPvarComp) after return.
14979  */
14981  SCIP* scip, /**< SCIP data structure */
14982  SCIP_ROWPREP* rowprep /**< rowprep to be cleaned up */
14983  )
14984 {
14985  int i;
14986  int j;
14987 
14988  assert(scip != NULL);
14989  assert(rowprep != NULL);
14990 
14991  if( rowprep->nvars <= 1 )
14992  return;
14993 
14994  /* sort terms by variable index */
14995  SCIPsortPtrReal((void**)rowprep->vars, rowprep->coefs, SCIPvarComp, rowprep->nvars);
14996 
14997  /* merge terms with same variable, drop 0 coefficients */
14998  i = 0;
14999  j = 1;
15000  while( j < rowprep->nvars )
15001  {
15002  if( rowprep->vars[i] == rowprep->vars[j] )
15003  {
15004  /* merge term j into term i */
15005  rowprep->coefs[i] += rowprep->coefs[j];
15006  ++j;
15007  continue;
15008  }
15009 
15010  if( rowprep->coefs[i] == 0.0 )
15011  {
15012  /* move term j to position i */
15013  rowprep->coefs[i] = rowprep->coefs[j];
15014  rowprep->vars[i] = rowprep->vars[j];
15015  ++j;
15016  continue;
15017  }
15018 
15019  /* move term j to position i+1 and move on */
15020  if( j != i+1 )
15021  {
15022  rowprep->vars[i+1] = rowprep->vars[j];
15023  rowprep->coefs[i+1] = rowprep->coefs[j];
15024  }
15025  ++i;
15026  ++j;
15027  }
15028 
15029  /* remaining term can have coef zero -> forget about it */
15030  if( rowprep->coefs[i] == 0.0 )
15031  --i;
15032 
15033  /* i points to last term */
15034  rowprep->nvars = i+1;
15035 }
15036 
15037 /** sort cut terms by absolute value of coefficients, from largest to smallest */
15038 static
15040  SCIP* scip, /**< SCIP data structure */
15041  SCIP_ROWPREP* rowprep /**< rowprep to be sorted */
15042  )
15043 {
15044  int i;
15045 
15046  assert(scip != NULL);
15047  assert(rowprep != NULL);
15048 
15049  /* special treatment for cuts with few variables */
15050  switch( rowprep->nvars )
15051  {
15052  case 0:
15053  case 1:
15054  break;
15055 
15056  case 2:
15057  {
15058  if( REALABS(rowprep->coefs[0]) < REALABS(rowprep->coefs[1]) )
15059  {
15060  SCIP_Real tmp1;
15061  SCIP_VAR* tmp2;
15062 
15063  tmp1 = rowprep->coefs[0];
15064  rowprep->coefs[0] = rowprep->coefs[1];
15065  rowprep->coefs[1] = tmp1;
15066 
15067  tmp2 = rowprep->vars[0];
15068  rowprep->vars[0] = rowprep->vars[1];
15069  rowprep->vars[1] = tmp2;
15070  }
15071  break;
15072  }
15073 
15074  default :
15075  {
15076  SCIP_Real* abscoefs;
15077 
15078  SCIP_CALL( SCIPallocBufferArray(scip, &abscoefs, rowprep->nvars) );
15079  for( i = 0; i < rowprep->nvars; ++i )
15080  abscoefs[i] = REALABS(rowprep->coefs[i]);
15081  SCIPsortDownRealRealPtr(abscoefs, rowprep->coefs, (void**)rowprep->vars, rowprep->nvars);
15082  SCIPfreeBufferArray(scip, &abscoefs);
15083  }
15084  }
15085 
15086  /* forget about coefs that are exactly zero (unlikely to have some) */
15087  while( rowprep->nvars > 0 && rowprep->coefs[rowprep->nvars-1] == 0.0 )
15088  --rowprep->nvars;
15089 
15090  return SCIP_OKAY;
15091 }
15092 
15093 /** try to improve coef range by aggregating cut with variable bounds
15094  *
15095  * Assumes terms have been sorted by rowprepCleanupSortTerms().
15096  */
15097 static
15099  SCIP* scip, /**< SCIP data structure */
15100  SCIP_ROWPREP* rowprep, /**< rowprep to be improve */
15101  SCIP_SOL* sol, /**< solution that we try to cut off, or NULL for LP solution */
15102  SCIP_Real maxcoefrange /**< maximal allowed coefficients range */
15103  )
15104 {
15105  SCIP_VAR* var;
15106  SCIP_Real lb;
15107  SCIP_Real ub;
15108  SCIP_Real ref;
15109  SCIP_Real coef;
15110  SCIP_Real mincoef;
15111  SCIP_Real maxcoef;
15112  SCIP_Real loss[2];
15113  int maxcoefidx;
15114  int pos;
15115 
15116  maxcoefidx = 0;
15117  if( rowprep->nvars > 0 )
15118  {
15119  maxcoef = REALABS(rowprep->coefs[0]);
15120  mincoef = REALABS(rowprep->coefs[rowprep->nvars-1]);
15121  }
15122  else
15123  mincoef = maxcoef = 1.0;
15124 
15125  /* eliminate minimal or maximal coefs as long as coef range is too large
15126  * this is likely going to eliminate coefs that are within eps of 0.0
15127  * if not, then we do so after scaling (or should we enforce this here?)
15128  */
15129  while( maxcoef / mincoef > maxcoefrange )
15130  {
15131  SCIPdebugMsg(scip, "cut coefficients have very large range: mincoef = %g maxcoef = %g\n", mincoef, maxcoef);
15132 
15133  /* max/min can only be > 1 if there is more than one var
15134  * we need this below for updating the max/min coef after eliminating a term
15135  */
15136  assert(rowprep->nvars > 1);
15137 
15138  /* try to reduce coef range by aggregating with variable bounds
15139  * that is, eliminate a term like a*x from a*x + ... <= side by adding -a*x <= -a*lb(x)
15140  * with ref(x) the reference point we try to eliminate, this would weaken the cut by a*(lb(x)-ref(x))
15141  *
15142  * we consider eliminating either the term with maximal or the one with minimal coefficient,
15143  * taking the one that leads to the least weakening of the cut
15144  *
15145  * TODO (suggested by @bzfserra, see !496):
15146  * - Also one could think of not completely removing the coefficient but do an aggregation that makes the coefficient look better. For instance:
15147  * say you have $`a x + 0.1 y \leq r`$ and $`y`$ has only an upper bound, $`y \leq b`$,
15148  * then you can't really remove $`y`$. However, you could aggregate it with $`0.9 \cdot (y \leq b)`$ to get
15149  * $`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)
15150  */
15151 
15152  for( pos = 0; pos < 2; ++pos )
15153  {
15154  var = rowprep->vars[pos ? rowprep->nvars-1 : maxcoefidx];
15155  coef = rowprep->coefs[pos ? rowprep->nvars-1 : maxcoefidx];
15156  lb = SCIPvarGetLbLocal(var);
15157  ub = SCIPvarGetUbLocal(var);
15158  ref = SCIPgetSolVal(scip, sol, var);
15159  assert(coef != 0.0);
15160 
15161  /* make sure reference point is something reasonable within the bounds, preferable the value from the solution */
15162  if( SCIPisInfinity(scip, REALABS(ref)) )
15163  ref = 0.0;
15164  ref = MAX(lb, MIN(ub, ref));
15165 
15166  /* check whether we can eliminate coef*var from rowprep and how much we would loose w.r.t. ref(x) */
15167  if( ((coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT)) )
15168  {
15169  /* we would need to aggregate with -coef*var <= -coef*lb(x) */
15170  if( SCIPisInfinity(scip, -lb) )
15171  loss[pos] = SCIP_INVALID;
15172  else
15173  loss[pos] = REALABS(coef) * (ref - lb);
15174  }
15175  else
15176  {
15177  assert((coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT));
15178  /* we would need to aggregate with -coef*var >= -coef*ub(x) */
15179  if( SCIPisInfinity(scip, ub) )
15180  loss[pos] = SCIP_INVALID;
15181  else
15182  loss[pos] = REALABS(coef) * (ub - ref);
15183  }
15184  assert(loss[pos] >= 0.0); /* assuming SCIP_INVALID >= 0 */
15185 
15186  SCIPdebugMsg(scip, "aggregating %g*<%s> %c= ... with <%s>[%g] %c= %g looses %g\n",
15187  coef, SCIPvarGetName(var), rowprep->sidetype == SCIP_SIDETYPE_RIGHT ? '<' : '>',
15188  SCIPvarGetName(var), ref,
15189  ((coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT)) ? '>' : '<',
15190  ((coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT)) ? lb : ub, loss[pos]);
15191  }
15192 
15193  /*lint --e{777} */
15194  if( loss[0] == SCIP_INVALID && loss[1] == SCIP_INVALID )
15195  break; /* cannot eliminate coefficient */
15196 
15197  /* select position with smaller loss */
15198  pos = (loss[1] == SCIP_INVALID || loss[1] > loss[0]) ? 0 : 1;
15199 
15200  /* now do the actual elimination */
15201  var = rowprep->vars[pos ? rowprep->nvars-1 : maxcoefidx];
15202  coef = rowprep->coefs[pos ? rowprep->nvars-1 : maxcoefidx];
15203 
15204  /* eliminate coef*var from rowprep: increase side */
15205  if( ((coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT)) )
15206  {
15207  /* we aggregate with -coef*var <= -coef*lb(x) */
15208  assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
15209  SCIPaddRowprepConstant(rowprep, coef * SCIPvarGetLbLocal(var));
15210  rowprep->local |= SCIPisGT(scip, SCIPvarGetLbLocal(var), SCIPvarGetLbGlobal(var));
15211  }
15212  else
15213  {
15214  assert((coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT));
15215  /* we aggregate with -coef*var >= -coef*ub(x) */
15216  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
15217  SCIPaddRowprepConstant(rowprep, coef * SCIPvarGetUbLocal(var));
15218  rowprep->local |= SCIPisLT(scip, SCIPvarGetUbLocal(var), SCIPvarGetUbGlobal(var));
15219  }
15220 
15221  /* eliminate coef*var from rowprep: remove coef */
15222  if( pos == 0 )
15223  {
15224  /* set first term to zero */
15225  rowprep->coefs[maxcoefidx] = 0.0;
15226 
15227  /* update index */
15228  ++maxcoefidx;
15229 
15230  /* update maxcoef */
15231  maxcoef = REALABS(rowprep->coefs[maxcoefidx]);
15232  }
15233  else
15234  {
15235  /* forget last term */
15236  --rowprep->nvars;
15237 
15238  /* update mincoef */
15239  mincoef = REALABS(rowprep->coefs[rowprep->nvars-1]);
15240  }
15241  }
15242 
15243  /* if maximal coefs were removed, then there are now 0's in the beginning of the coefs array
15244  * -> move all remaining coefs and vars up front
15245  */
15246  if( maxcoefidx > 0 )
15247  {
15248  int i;
15249  for( i = maxcoefidx; i < rowprep->nvars; ++i )
15250  {
15251  rowprep->vars[i-maxcoefidx] = rowprep->vars[i];
15252  rowprep->coefs[i-maxcoefidx] = rowprep->coefs[i];
15253  }
15254  rowprep->nvars -= maxcoefidx;
15255  }
15256 }
15257 
15258 
15259 /** scales up rowprep if it seems useful */
15260 static
15262  SCIP* scip, /**< SCIP data structure */
15263  SCIP_ROWPREP* rowprep, /**< rowprep to be improve */
15264  SCIP_Real* viol, /**< violation of cut in sol (input and output) */
15265  SCIP_Real minviol /**< minimal violation we try to achieve */
15266  )
15267 {
15268  SCIP_Real scalefactor;
15269  SCIP_Real mincoef;
15270  SCIP_Real maxcoef;
15271 
15272  assert(scip != NULL);
15273  assert(rowprep != NULL);
15274  assert(viol != NULL);
15275 
15276  /* if violation is very small than better don't scale up */
15277  if( *viol < ROWPREP_SCALEUP_VIOLNONZERO )
15278  return;
15279 
15280  /* if violation is already above minviol, then nothing to do */
15281  if( *viol >= minviol )
15282  return;
15283 
15284  /* if violation is sufficiently positive (>10*eps), but has not reached minviol,
15285  * then consider scaling up to reach approx MINVIOLFACTOR*minviol
15286  */
15287  scalefactor = ROWPREP_SCALEUP_MINVIOLFACTOR * minviol / *viol;
15288 
15289  /* 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) */
15290  mincoef = rowprep->nvars > 0 ? REALABS(rowprep->coefs[rowprep->nvars-1]) : 1.0;
15291  maxcoef = rowprep->nvars > 0 ? REALABS(rowprep->coefs[0]) : 1.0;
15292  if( mincoef < ROWPREP_SCALEUP_MAXMINCOEF && scalefactor * maxcoef < ROWPREP_SCALEUP_MAXMAXCOEF && scalefactor * REALABS(rowprep->side) < ROWPREP_SCALEUP_MAXSIDE )
15293  {
15294  int scaleexp;
15295 
15296  /* SCIPinfoMessage(scip, NULL, "scale up by ~%g, viol=%g: ", scalefactor, myviol);
15297  SCIPprintRowprep(scip, rowprep, NULL); */
15298 
15299  /* SCIPscaleRowprep returns the actually applied scale factor */
15300  scaleexp = SCIPscaleRowprep(rowprep, scalefactor);
15301  *viol = ldexp(*viol, scaleexp);
15302 
15303  /* SCIPinfoMessage(scip, NULL, "scaled up by %g, viol=%g: ", ldexp(1.0, scaleexp), myviol);
15304  SCIPprintRowprep(scip, rowprep, NULL); */
15305  }
15306 }
15307 
15308 /** scales down rowprep if it improves coefs and keeps rowprep violated */
15309 static
15311  SCIP* scip, /**< SCIP data structure */
15312  SCIP_ROWPREP* rowprep, /**< rowprep to be improve */
15313  SCIP_Real* viol, /**< violation of cut in sol (input and output) */
15314  SCIP_Real minviol /**< minimal violation we try to keep */
15315  )
15316 {
15317  SCIP_Real scalefactor;
15318 
15319  /* if maxcoef < ROWPREP_SCALEDOWN_MINMAXCOEF (or no terms), then don't consider scaling down */
15320  if( rowprep->nvars == 0 || rowprep->coefs[0] < ROWPREP_SCALEDOWN_MINMAXCOEF )
15321  return;
15322 
15323  /* consider scaling down so that maxcoef ~ 10 */
15324  scalefactor = 10.0 / REALABS(rowprep->coefs[0]);
15325 
15326  /* if minimal violation would be lost by scaling down, then increase scalefactor such that minviol is still reached */
15327  if( *viol > minviol && scalefactor * *viol < minviol )
15328  {
15329  assert(minviol > 0.0); /* since viol >= 0, the if-condition should ensure that minviol > 0 */
15330  assert(*viol > 0.0); /* since minviol > 0, the if-condition ensures viol > 0 */
15331  scalefactor = ROWPREP_SCALEUP_MINVIOLFACTOR * minviol / *viol;
15332  }
15333 
15334  /* scale by approx. scalefactor if scaling down and minimal coef does not get too small
15335  * myviol < minviol (-> scalefactor > 1) or mincoef < feastol before scaling is possible, in which case we also don't scale down
15336  */
15337  if( scalefactor < 1.0 && scalefactor * REALABS(rowprep->coefs[rowprep->nvars-1]) > ROWPREP_SCALEDOWN_MINCOEF )
15338  {
15339  int scaleexp;
15340 
15341  /* SCIPinfoMessage(scip, NULL, "scale down by ~%g, viol=%g: ", scalefactor, myviol);
15342  SCIPprintRowprep(scip, rowprep, NULL); */
15343 
15344  scaleexp = SCIPscaleRowprep(rowprep, scalefactor);
15345  *viol = ldexp(*viol, scaleexp);
15346 
15347  /* SCIPinfoMessage(scip, NULL, "scaled down by %g, viol=%g: ", ldexp(1.0, scaleexp), myviol);
15348  SCIPprintRowprep(scip, rowprep, NULL); */
15349  }
15350 }
15351 
15352 /** rounds almost integral coefs to integrals, thereby trying to relax the cut */
15353 static
15355  SCIP* scip, /**< SCIP data structure */
15356  SCIP_ROWPREP* rowprep, /**< rowprep to be improve */
15357  SCIP_Real* viol /**< violation of cut in sol (input), set to SCIP_INVALID if some coef changed */
15358  )
15359 {
15360  SCIP_Real coef;
15361  SCIP_Real roundcoef;
15362  int i;
15363 
15364  assert(scip != NULL);
15365  assert(rowprep != NULL);
15366  assert(viol != NULL);
15367 
15368  /* Coefficients smaller than epsilon are rounded to 0.0 when added to row and
15369  * coefficients very close to integral values are rounded to integers when added to LP.
15370  * Both cases can be problematic if variable value is very large (bad numerics).
15371  * Thus, we anticipate by rounding coef here, but also modify constant so that cut is still valid (if possible),
15372  * i.e., bound coef[i]*x by round(coef[i])*x + (coef[i]-round(coef[i])) * bound(x).
15373  * Or in other words, we aggregate with the variable bound.
15374  *
15375  * If the required bound of x is not finite, then only round coef (introduces an error).
15376  * @TODO If only the opposite bound is available, then one could move the coefficient
15377  * away from the closest integer so that the SCIP_ROW won't try to round it.
15378  */
15379  for( i = 0; i < rowprep->nvars; ++i )
15380  {
15381  coef = rowprep->coefs[i];
15382  roundcoef = SCIPround(scip, coef);
15383  if( coef != roundcoef && SCIPisEQ(scip, coef, roundcoef) ) /*lint !e777*/
15384  {
15385  SCIP_Real xbnd;
15386  SCIP_VAR* var;
15387 
15388  var = rowprep->vars[i];
15389  if( rowprep->sidetype == SCIP_SIDETYPE_RIGHT )
15390  if( rowprep->local )
15391  xbnd = coef > roundcoef ? SCIPvarGetLbLocal(var) : SCIPvarGetUbLocal(var);
15392  else
15393  xbnd = coef > roundcoef ? SCIPvarGetLbGlobal(var) : SCIPvarGetUbGlobal(var);
15394  else
15395  if( rowprep->local )
15396  xbnd = coef > roundcoef ? SCIPvarGetUbLocal(var) : SCIPvarGetLbLocal(var);
15397  else
15398  xbnd = coef > roundcoef ? SCIPvarGetUbGlobal(var) : SCIPvarGetLbGlobal(var);
15399 
15400  if( !SCIPisInfinity(scip, REALABS(xbnd)) )
15401  {
15402  /* if there is a bound, then relax row side so rounding coef will not introduce an error */
15403  SCIPdebugMsg(scip, "var <%s> [%g,%g] has almost integral coef %.20g, round coefficient to %g and add constant %g\n",
15404  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), coef, roundcoef, (coef-roundcoef) * xbnd);
15405  SCIPaddRowprepConstant(rowprep, (coef-roundcoef) * xbnd);
15406  }
15407  else
15408  {
15409  /* if there is no bound, then we make the coef integral, too, even though this will introduce an error
15410  * however, SCIP_ROW would do this anyway, but doing this here might eliminate some epsilon coefs (so they don't determine mincoef below)
15411  * and helps to get a more accurate row violation value
15412  */
15413  SCIPdebugMsg(scip, "var <%s> [%g,%g] has almost integral coef %.20g, round coefficient to %g without relaxing side (!)\n",
15414  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), coef, roundcoef);
15415  }
15416  rowprep->coefs[i] = coef = roundcoef;
15417  *viol = SCIP_INVALID;
15418  }
15419  }
15420 
15421  /* forget about coefs that became exactly zero by the above step */
15422  while( rowprep->nvars > 0 && rowprep->coefs[rowprep->nvars-1] == 0.0 )
15423  --rowprep->nvars;
15424 }
15425 
15426 /** relaxes almost zero side */
15427 static
15428 void rowprepCleanupSide(
15429  SCIP* scip, /**< SCIP data structure */
15430  SCIP_ROWPREP* rowprep, /**< rowprep to be improve */
15431  SCIP_Real* viol /**< violation of cut in sol (input), set to SCIP_INVALID if some coef changed */
15432  )
15433 {
15434  /* SCIP_ROW handling will replace a side close to 0 by 0.0, even if that makes the row more restrictive
15435  * we thus relax the side here so that it will either be 0 now or will not be rounded to 0 later
15436  */
15437  if( !SCIPisZero(scip, rowprep->side) )
15438  return;
15439 
15440  if( rowprep->side > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT )
15441  rowprep->side = 1.1*SCIPepsilon(scip);
15442  else if( rowprep->side < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT )
15443  rowprep->side = -1.1*SCIPepsilon(scip);
15444  else
15445  rowprep->side = 0.0;
15446 
15447  *viol = SCIP_INVALID;
15448 }
15449 
15450 /* Cleans up and attempts to improve rowprep
15451  *
15452  * Drops small or large coefficients if coefrange is too large, if this can be done by relaxing the cut.
15453  * Scales coefficients and side up to reach minimal violation, if possible.
15454  * Scaling is omitted if violation is very small (ROWPREP_SCALEUP_VIOLNONZERO) or
15455  * maximal coefficient would become huge (ROWPREP_SCALEUP_MAXMAXCOEF).
15456  * Scales coefficients and side down if they are large and if the minimal violation is still reached.
15457  * Rounds coefficients close to integral values to integrals, if this can be done by relaxing the cut.
15458  * Rounds side within epsilon of 0 to 0.0 or +/-1.1*epsilon, whichever relaxes the cut least.
15459  *
15460  * After return, the terms in the rowprep will be sorted by absolute value of coefficient, in decreasing order.
15461  */
15463  SCIP* scip, /**< SCIP data structure */
15464  SCIP_ROWPREP* rowprep, /**< rowprep to be cleaned */
15465  SCIP_SOL* sol, /**< solution that we try to cut off, or NULL for LP solution */
15466  SCIP_Real maxcoefrange, /**< maximal allowed coefficients range */
15467  SCIP_Real minviol, /**< minimal absolute violation the row should achieve (w.r.t. sol) */
15468  SCIP_Real* coefrange, /**< buffer to store coefrange of cleaned up cut, or NULL if not of interest */
15469  SCIP_Real* viol /**< buffer to store absolute violation of cleaned up cut in sol, or NULL if not of interest */
15470  )
15471 {
15472  SCIP_Real myviol;
15473 #ifdef SCIP_DEBUG
15474  SCIP_Real mincoef = 1.0;
15475  SCIP_Real maxcoef = 1.0;
15476 #endif
15477 
15478  assert(maxcoefrange > 1.0); /* not much interesting otherwise */
15479 
15480  /* sort term by absolute value of coef. */
15481  SCIP_CALL( rowprepCleanupSortTerms(scip, rowprep) );
15482 
15483 #ifdef SCIP_DEBUG
15484  if( rowprep->nvars > 0 )
15485  {
15486  maxcoef = REALABS(rowprep->coefs[0]);
15487  mincoef = REALABS(rowprep->coefs[rowprep->nvars-1]);
15488  }
15489 
15490  SCIPinfoMessage(scip, NULL, "starting cleanup, coefrange %g: ", maxcoef/mincoef);
15491  SCIPprintRowprep(scip, rowprep, NULL);
15492 #endif
15493 
15494  /* improve coefficient range by aggregating out variables */
15495  rowprepCleanupImproveCoefrange(scip, rowprep, sol, maxcoefrange);
15496 
15497  /* get current violation in sol */
15498  myviol = SCIPgetRowprepViolation(scip, rowprep, sol, 'o');
15499  assert(myviol >= 0.0);
15500 
15501 #ifdef SCIP_DEBUG
15502  if( rowprep->nvars > 0 )
15503  {
15504  maxcoef = REALABS(rowprep->coefs[0]);
15505  mincoef = REALABS(rowprep->coefs[rowprep->nvars-1]);
15506  }
15507 
15508  SCIPinfoMessage(scip, NULL, "improved coefrange to %g, viol %g: ", maxcoef / mincoef, myviol);
15509  SCIPprintRowprep(scip, rowprep, NULL);
15510 #endif
15511 
15512  /* scale up to increase violation, updates myviol */
15513  rowprepCleanupScaleup(scip, rowprep, &myviol, minviol);
15514 
15515  /* scale down to improve numerics, updates myviol */
15516  rowprepCleanupScaledown(scip, rowprep, &myviol, minviol);
15517 
15518 #ifdef SCIP_DEBUG
15519  SCIPinfoMessage(scip, NULL, "applied scaling, viol %g: ", myviol);
15520  SCIPprintRowprep(scip, rowprep, NULL);
15521 #endif
15522 
15523  /* turn almost-integral coefs to integral values, may set myviol to SCIP_INVALID */
15524  rowprepCleanupIntegralCoefs(scip, rowprep, &myviol);
15525 
15526  /* relax almost-zero side, may set myviol to SCIP_INVALID */
15527  rowprepCleanupSide(scip, rowprep, &myviol);
15528 
15529 #ifdef SCIP_DEBUG
15530  SCIPinfoMessage(scip, NULL, "adjusted almost-integral coefs and sides, viol %g: ", myviol);
15531  SCIPprintRowprep(scip, rowprep, NULL);
15532 #endif
15533 
15534  /* compute final coefrange, if requested by caller */
15535  if( coefrange != NULL )
15536  {
15537  if( rowprep->nvars > 0 )
15538  *coefrange = REALABS(rowprep->coefs[0]) / REALABS(rowprep->coefs[rowprep->nvars-1]);
15539  else
15540  *coefrange = 1.0;
15541  }
15542 
15543  /* If we updated myviol correctly, then it should coincide with freshly computed violation.
15544  * I leave this assert off for now, since getting the tolerance in the EQ correctly is not trivial. We recompute viol below anyway.
15545  */
15546  /* assert(myviol == SCIP_INVALID || SCIPisEQ(scip, myviol, SCIPgetRowprepViolation(scip, rowprep, sol, 'o'))); */
15547 
15548  /* compute final violation, if requested by caller */
15549  if( viol != NULL ) /*lint --e{777} */
15550  *viol = myviol == SCIP_INVALID ? SCIPgetRowprepViolation(scip, rowprep, sol, 'o') : myviol;
15551 
15552  return SCIP_OKAY;
15553 }
15554 
15555 /** scales a rowprep
15556  *
15557  * @return Exponent of actually applied scaling factor, if written as 2^x.
15558  */
15559 int SCIPscaleRowprep(
15560  SCIP_ROWPREP* rowprep, /**< rowprep to be scaled */
15561  SCIP_Real factor /**< suggested scale factor */
15562  )
15563 {
15564  double v;
15565  int expon;
15566  int i;
15567 
15568  assert(rowprep != NULL);
15569  assert(factor > 0.0);
15570 
15571  /* write factor as v*2^expon with v in [0.5,1) */
15572  v = frexp(factor, &expon);
15573  /* adjust to v'*2^expon with v' in (0.5,1] by v'=v if v > 0.5, v'=1 if v=0.5 */
15574  if( v == 0.5 )
15575  --expon;
15576 
15577  /* multiply each coefficient by 2^expon */
15578  for( i = 0; i < rowprep->nvars; ++i )
15579  rowprep->coefs[i] = ldexp(rowprep->coefs[i], expon);
15580 
15581  /* multiply side by 2^expon */
15582  rowprep->side = ldexp(rowprep->side, expon);
15583 
15584  return expon;
15585 }
15586 
15587 /** generates a SCIP_ROW from a rowprep */
15589  SCIP* scip, /**< SCIP data structure */
15590  SCIP_ROW** row, /**< buffer to store pointer to new row */
15591  SCIP_ROWPREP* rowprep, /**< rowprep to be turned into a row */
15592  SCIP_CONSHDLR* conshdlr /**< constraint handler */
15593  )
15594 {
15595  assert(scip != NULL);
15596  assert(row != NULL);
15597  assert(rowprep != NULL);
15598 
15599  SCIP_CALL( SCIPcreateEmptyRowCons(scip, row, conshdlr, rowprep->name,
15600  rowprep->sidetype == SCIP_SIDETYPE_LEFT ? rowprep->side : -SCIPinfinity(scip),
15601  rowprep->sidetype == SCIP_SIDETYPE_RIGHT ? rowprep->side : SCIPinfinity(scip),
15602  rowprep->local && (SCIPgetDepth(scip) > 0), FALSE, TRUE) );
15603 
15604  SCIP_CALL( SCIPaddVarsToRow(scip, *row, rowprep->nvars, rowprep->vars, rowprep->coefs) );
15605 
15606  return SCIP_OKAY;
15607 }
15608 
15609 /** generates a SCIP_ROW from a rowprep */
15611  SCIP* scip, /**< SCIP data structure */
15612  SCIP_ROW** row, /**< buffer to store pointer to new row */
15613  SCIP_ROWPREP* rowprep, /**< rowprep to be turned into a row */
15614  SCIP_SEPA* sepa /**< separator */
15615  )
15616 {
15617  assert(scip != NULL);
15618  assert(row != NULL);
15619  assert(rowprep != NULL);
15620 
15621  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, row, sepa, rowprep->name,
15622  rowprep->sidetype == SCIP_SIDETYPE_LEFT ? rowprep->side : -SCIPinfinity(scip),
15623  rowprep->sidetype == SCIP_SIDETYPE_RIGHT ? rowprep->side : SCIPinfinity(scip),
15624  rowprep->local && (SCIPgetDepth(scip) > 0), FALSE, TRUE) );
15625 
15626  SCIP_CALL( SCIPaddVarsToRow(scip, *row, rowprep->nvars, rowprep->vars, rowprep->coefs) );
15627 
15628  return SCIP_OKAY;
15629 }
SCIP_RETCODE SCIPaddLinearCoefsToNlRow(SCIP *scip, SCIP_NLROW *nlrow, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip.c:32146
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:52
static void rowprepCleanupImproveCoefrange(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Real maxcoefrange)
SCIP_VAR ** SCIPgetLinearVarsQuadratic(SCIP *scip, SCIP_CONS *cons)
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip.h:21975
SCIP_RETCODE SCIPchgSquareCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_RETCODE SCIPincludeConshdlrQuadratic(SCIP *scip)
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
void SCIPintervalDivScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
int SCIPgetNIntVars(SCIP *scip)
Definition: scip.c:11770
SCIP_RETCODE SCIPchgBilinCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Real coef)
static SCIP_Bool conshdlrdataHasUpgrade(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), const char *conshdlrname)
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:46385
SCIP_Bool SCIPisIpoptAvailableIpopt(void)
#define ROWPREP_SCALEUP_VIOLNONZERO
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip.h:21964
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:17268
void SCIPintervalMulSup(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSDATA **consdata, SCIP_Real lhs, SCIP_Real rhs, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadvars, SCIP_QUADVARTERM *quadvarterms, int nbilinterms, SCIP_BILINTERM *bilinterms, SCIP_Bool capturevars)
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip.c:6263
static SCIP_RETCODE propagateBoundsQuadVar(SCIP *scip, SCIP_CONS *cons, SCIP_Real intervalinfty, SCIP_VAR *var, SCIP_Real a, SCIP_INTERVAL b, SCIP_INTERVAL rhs, SCIP_RESULT *result, int *nchgbds)
SCIP_EXPRGRAPH * SCIPgetExprgraphNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr)
static SCIP_DECL_CONSENFOPS(consEnfopsQuadratic)
SCIP_RETCODE SCIPincludeNonlinconsUpgrade(SCIP *scip, SCIP_DECL_NONLINCONSUPGD((*nonlinconsupgd)), SCIP_DECL_EXPRGRAPHNODEREFORM((*nodereform)), int priority, SCIP_Bool active, const char *conshdlrname)
#define ROWPREP_SCALEDOWN_MINCOEF
static void consdataMoveLinearVar(SCIP_CONSDATA *consdata, int oldpos, int newpos)
SCIP_Real SCIPfeastol(SCIP *scip)
Definition: scip.c:45508
SCIP_Bool SCIPconsIsEnabled(SCIP_CONS *cons)
Definition: cons.c:7978
SCIP_Real SCIPgetRowprepViolation(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, char scaling)
SCIP_Bool SCIPintervalIsEmpty(SCIP_Real infinity, SCIP_INTERVAL operand)
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip.h:21958
static SCIP_RETCODE consdataSortBilinTerms(SCIP *scip, SCIP_CONSDATA *consdata)
primal heuristic that tries a given solution
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition: scip.c:30965
SCIP_RETCODE SCIPaddQuadVarQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real lincoef, SCIP_Real sqrcoef)
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:22212
SCIP_VAR * var2
static void rowprepCleanupScaleup(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_Real *viol, SCIP_Real minviol)
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition: scip.c:40680
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip.c:814
#define MAXDNOM
#define SCIP_EVENTTYPE_VARFIXED
Definition: type_event.h:58
#define GAUGESCALE
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8140
SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition: var.c:16961
SCIP_RETCODE SCIPincSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real incval)
Definition: scip.c:38139
static SCIP_RETCODE separatePoint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_Real minefficacy, SCIP_Bool inenforcement, SCIP_RESULT *result, SCIP_Real *bestefficacy)
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip.c:6286
#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)
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46333
Constraint handler for variable bound constraints .
SCIP_Bool SCIPisRelEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46696
SCIP_RETCODE SCIPaddSquareCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
static SCIP_RETCODE propagateBoundsBilinearTerm(SCIP *scip, SCIP_CONS *cons, SCIP_Real intervalinfty, SCIP_VAR *x, SCIP_Real xsqrcoef, SCIP_Real xlincoef, SCIP_VAR *y, SCIP_Real ysqrcoef, SCIP_Real ylincoef, SCIP_Real bilincoef, SCIP_INTERVAL rhs, SCIP_RESULT *result, int *nchgbds)
#define ROWPREP_SCALEDOWN_MINMAXCOEF
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip.c:40502
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip.c:6576
SCIP_RETCODE SCIPchgRhsQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_Real rhs)
int SCIPexprgraphGetNodeNChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12890
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition: scip.h:21993
SCIP_Real SCIPintervalNegateReal(SCIP_Real x)
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17169
SCIP_RETCODE SCIPincludeQuadconsUpgrade(SCIP *scip, SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), int priority, SCIP_Bool active, const char *conshdlrname)
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip.c:6516
static SCIP_DECL_SORTINDCOMP(quadVarTermComp)
#define SCIP_MAXSTRLEN
Definition: def.h:225
static SCIP_RETCODE replaceQuadVarTermPos(SCIP *scip, SCIP_CONS *cons, int pos, SCIP_VAR *var, SCIP_Real coef, SCIP_Real offset)
#define SCIP_DECL_CONSINITPRE(x)
Definition: type_cons.h:114
#define CONSHDLR_DELAYPROP
SCIP_Bool SCIPvarIsInitial(SCIP_VAR *var)
Definition: var.c:16756
SCIP_VAR * var1
void SCIPsortPtrPtrReal(void **ptrarray1, void **ptrarray2, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPaddRowprepTerms(SCIP *scip, SCIP_ROWPREP *rowprep, int nvars, SCIP_VAR **vars, SCIP_Real *coefs)
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip.c:6008
#define SCIPallocClearBlockMemoryArray(scip, ptr, num)
Definition: scip.h:21962
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:28056
static SCIP_RETCODE getImpliedBounds(SCIP *scip, SCIP_VAR *x, SCIP_Bool xval, SCIP_VAR *y, SCIP_INTERVAL *resultant)
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:12530
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip.c:45835
SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
Definition: var.c:16949
int SCIProwGetNNonz(SCIP_ROW *row)
Definition: lp.c:16312
SCIP_RETCODE SCIPcleanupRowprep(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Real maxcoefrange, SCIP_Real minviol, SCIP_Real *coefrange, SCIP_Real *viol)
static SCIP_RETCODE generateCutNonConvex(SCIP *scip, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_Real *ref, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
#define CONSHDLR_PROPFREQ
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:46110
#define INTERIOR_EPS
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17225
static SCIP_DECL_CONSSEPALP(consSepalpQuadratic)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46037
internal methods for NLPI solver interfaces
SCIP_RETCODE SCIPaddRowprepTerm(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_VAR *var, SCIP_Real coef)
static SCIP_RETCODE lockLinearVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_Bool local
SCIP_Bool SCIPconsIsAdded(SCIP_CONS *cons)
Definition: cons.c:8250
SCIP_RETCODE SCIPnlpiCreateProblem(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM **problem, const char *name)
Definition: nlpi.c:211
static SCIP_RETCODE catchVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons)
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip.c:8561
SCIP_NLPSOLSTAT SCIPgetNLPSolstat(SCIP *scip)
Definition: scip.c:31348
const char * SCIProwGetName(SCIP_ROW *row)
Definition: lp.c:16450
SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
Definition: scip.c:18652
static void consdataUpdateLinearActivityUbChange(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real coef, SCIP_Real oldbnd, SCIP_Real newbnd)
static SCIP_RETCODE dropLinearVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons, int linvarpos)
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip.c:18461
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:16735
static SCIP_RETCODE addQuadVarTerm(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real lincoef, SCIP_Real sqrcoef)
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:46409
SCIP_Real SCIPvarGetBestBoundLocal(SCIP_VAR *var)
Definition: var.c:17255
static SCIP_DECL_CONSENABLE(consEnableQuadratic)
static SCIP_RETCODE generateCut(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Real *ref, SCIP_SOL *sol, SCIP_SIDETYPE violside, SCIP_ROW **row, SCIP_Real *efficacy, SCIP_Bool checkcurvmultivar, SCIP_Real minefficacy)
static void consdataUpdateLinearActivityLbChange(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real coef, SCIP_Real oldbnd, SCIP_Real newbnd)
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46372
static SCIP_DECL_NONLINCONSUPGD(nonlinconsUpgdQuadratic)
SCIP_Real SCIPgetRelaxFeastolFactor(SCIP *scip)
Definition: scip.c:34579
#define CONSHDLR_MAXPREROUNDS
SCIP_RETCODE SCIPchgLinearCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
void SCIPintervalSetRoundingMode(SCIP_ROUNDMODE roundmode)
SCIP_SIDETYPE sidetype
static SCIP_DECL_CONSEXITPRE(consExitpreQuadratic)
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4485
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:16391
#define FALSE
Definition: def.h:64
SCIP_Real SCIPadjustedVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real ub)
Definition: scip.c:21674
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:2764
static SCIP_Real getGradientMaxElement(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol)
#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 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
int SCIPgetSubscipDepth(SCIP *scip)
Definition: scip.c:3534
SCIP_RETCODE SCIPincludeConshdlrBasic(SCIP *scip, SCIP_CONSHDLR **conshdlrptr, const char *name, const char *desc, int enfopriority, int chckpriority, int eagerfreq, SCIP_Bool needscons, SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition: scip.c:5866
SCIP_Real * SCIPgetLinearCoefsNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPinfinity(SCIP *scip)
Definition: scip.c:46050
#define CONSHDLR_SEPAPRIORITY
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:9340
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:46122
#define TRUE
Definition: def.h:63
#define SCIPdebug(x)
Definition: pub_message.h:74
SCIP_RETCODE SCIPunmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:28286
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
SCIP_RETCODE SCIPsolveNLP(SCIP *scip)
Definition: scip.c:31325
static SCIP_RETCODE generateCutConvex(SCIP *scip, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_Real *ref, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
SCIP_RETCODE SCIPaddVarLocks(SCIP *scip, SCIP_VAR *var, int nlocksdown, int nlocksup)
Definition: scip.c:21349
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8160
#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:8190
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)
static GRAPHNODE ** active
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:22328
static SCIP_RETCODE removeBilinearTermsPos(SCIP *scip, SCIP_CONS *cons, int nterms, int *termposs)
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip.h:21973
void SCIPaddBilinLinearization(SCIP *scip, SCIP_Real bilincoef, SCIP_Real refpointx, SCIP_Real refpointy, SCIP_Real *lincoefx, SCIP_Real *lincoefy, SCIP_Real *linconstant, SCIP_Bool *success)
Definition: scip.c:33141
#define SCIPdebugMessage
Definition: pub_message.h:77
SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
Definition: scip.c:5920
SCIP_Real SCIPselectSimpleValue(SCIP_Real lb, SCIP_Real ub, SCIP_Longint maxdnom)
Definition: misc.c:8482
static SCIP_RETCODE presolveTryAddAND(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *naddconss)
SCIP_EVENTHDLR * SCIPfindEventhdlr(SCIP *scip, const char *name)
Definition: scip.c:8691
Constraint handler for AND constraints, .
SCIP_RETCODE SCIPnlpiGetSolution(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem, SCIP_Real **primalvalues, SCIP_Real **consdualvalues, SCIP_Real **varlbdualvalues, SCIP_Real **varubdualvalues)
Definition: nlpi.c:535
SCIP_RETCODE SCIPwriteVarsPolynomial(SCIP *scip, FILE *file, SCIP_VAR ***monomialvars, SCIP_Real **monomialexps, SCIP_Real *monomialcoefs, int *monomialnvars, int nmonomials, SCIP_Bool type)
Definition: scip.c:17604
static SCIP_RETCODE mergeAndCleanBilinearTerms(SCIP *scip, SCIP_CONS *cons)
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2902
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:45985
static SCIP_RETCODE chgLinearCoefPos(SCIP *scip, SCIP_CONS *cons, int pos, SCIP_Real newcoef)
static SCIP_RETCODE propagateBoundsCons(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_RESULT *result, int *nchgbds, SCIP_Bool *redundant)
SCIP_RETCODE SCIPcreateLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip.c:37220
static SCIP_DECL_CONSENFOLP(consEnfolpQuadratic)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip.h:22003
SCIP_Real SCIPadjustedVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real lb)
Definition: scip.c:21642
SCIP_Bool SCIPvarIsRemovable(SCIP_VAR *var)
Definition: var.c:16766
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip.h:21956
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:83
static SCIP_RETCODE dropQuadVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons, int quadvarpos)
SCIP_RETCODE SCIPcreateConsBasicQuadratic(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadterms, SCIP_VAR **quadvars1, SCIP_VAR **quadvars2, SCIP_Real *quadcoefs, SCIP_Real lhs, SCIP_Real rhs)
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8150
#define SCIP_EVENTTYPE_BOUNDCHANGED
Definition: type_event.h:108
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip.c:6309
static SCIP_RETCODE registerBranchingCandidatesViolation(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, int *nnotify)
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip.c:1260
#define SCIPdebugMsgPrint
Definition: scip.h:452
#define ROWPREP_SCALEUP_MAXMAXCOEF
#define SCIPdebugMsg
Definition: scip.h:451
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:4237
static void consdataUpdateLinearActivity(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real intervalinfty)
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip.c:6493
SCIP_Real SCIPgetLhsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:7942
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip.c:1336
int SCIPgetNContVars(SCIP *scip)
Definition: scip.c:11860
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: scip.c:27240
SCIP_Real SCIPepsilon(SCIP *scip)
Definition: scip.c:45480
static SCIP_RETCODE lockQuadraticVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
#define SCIP_PRESOLTIMING_FAST
Definition: type_timing.h:43
SCIP_Real SCIPgetRowMaxCoef(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30621
SCIP_RETCODE SCIPaddLinearVarQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
void SCIPintervalSolveUnivariateQuadExpression(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL rhs)
SCIP_RETCODE SCIPcreateConsQuadratic(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadterms, SCIP_VAR **quadvars1, SCIP_VAR **quadvars2, SCIP_Real *quadcoefs, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable)
static SCIP_RETCODE unlockQuadraticVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
int SCIPgetNQuadVarTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPconsIsOriginal(SCIP_CONS *cons)
Definition: cons.c:8180
int SCIPnlrowGetNQuadElems(SCIP_NLROW *nlrow)
Definition: nlp.c:3322
SCIP_RETCODE SCIPcreateConsVarbound(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *var, SCIP_VAR *vbdvar, SCIP_Real vbdcoef, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
#define SCIP_EVENTTYPE_LBCHANGED
Definition: type_event.h:104
const char * SCIPgetProbName(SCIP *scip)
Definition: scip.c:10759
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2996
static SCIP_RETCODE registerBranchingCandidatesGap(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, int *nnotify)
int SCIPgetNBilinTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPnlpiSolve(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem)
Definition: nlpi.c:495
SCIP_RETCODE SCIPheurPassSolTrySol(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *sol)
Definition: heur_trysol.c:236
SCIP_EXPROP SCIPexprgraphGetNodeOperator(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12950
static SCIP_RETCODE consdataSortQuadVarTerms(SCIP *scip, SCIP_CONSDATA *consdata)
#define CONSHDLR_EAGERFREQ
SCIP_RETCODE SCIPnlpiAddVars(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem, int nvars, const SCIP_Real *lbs, const SCIP_Real *ubs, const char **varnames)
Definition: nlpi.c:250
SCIP_RETCODE SCIPchgVarType(SCIP *scip, SCIP_VAR *var, SCIP_VARTYPE vartype, SCIP_Bool *infeasible)
Definition: scip.c:25139
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17179
SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITSOL((*consinitsol)))
Definition: scip.c:6129
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip.h:21970
SCIP_Bool SCIPisConcaveQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Real coef
Definition: type_expr.h:102
#define SCIP_EVENTTYPE_SOLFOUND
Definition: type_event.h:127
void SCIPfreeRowprep(SCIP *scip, SCIP_ROWPREP **rowprep)
SCIP_Real inf
Definition: intervalarith.h:39
SCIP_RETCODE SCIPchgLhsQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_Real lhs)
static SCIP_RETCODE checkCurvature(SCIP *scip, SCIP_CONS *cons, SCIP_Bool checkmultivariate)
SCIP_Real SCIPeventGetNewbound(SCIP_EVENT *event)
Definition: event.c:1162
SCIP_RETCODE SCIPcreateSolCopy(SCIP *scip, SCIP_SOL **sol, SCIP_SOL *sourcesol)
Definition: scip.c:37468
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
Definition: scip.c:1047
SCIP_Bool SCIPconsIsLocked(SCIP_CONS *cons)
Definition: cons.c:8220
SCIP_VAR ** SCIPnlrowGetQuadVars(SCIP_NLROW *nlrow)
Definition: nlp.c:3285
static SCIP_RETCODE presolveTryAddLinearReform(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *naddconss)
static SCIP_RETCODE generateCutFactorableDo(SCIP *scip, SCIP_CONS *cons, SCIP_Real *ref, SCIP_Real multleft, SCIP_Real *coefleft, SCIP_Real multright, SCIP_Real *coefright, SCIP_Real rightminactivity, SCIP_Real rightmaxactivity, SCIP_Real rhs, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
void SCIPmarkRowNotRemovableLocal(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30585
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip.c:6032
SCIP_RETCODE SCIPaddLinearConsToNlpHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_Bool addcombconss, SCIP_Bool addcontconss)
Definition: heur_subnlp.c:2389
static SCIP_DECL_CONSEXIT(consExitQuadratic)
const char * SCIPheurGetName(SCIP_HEUR *heur)
Definition: heur.c:1181
struct SCIP_QuadVarEventData SCIP_QUADVAREVENTDATA
SCIP_Bool SCIPintervalIsEntire(SCIP_Real infinity, SCIP_INTERVAL operand)
void SCIPaddBilinMcCormick(SCIP *scip, SCIP_Real bilincoef, SCIP_Real lbx, SCIP_Real ubx, SCIP_Real refpointx, SCIP_Real lby, SCIP_Real uby, SCIP_Real refpointy, SCIP_Bool overestimate, SCIP_Real *lincoefx, SCIP_Real *lincoefy, SCIP_Real *linconstant, SCIP_Bool *success)
Definition: scip.c:33188
SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
Definition: scip.c:8175
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:4948
#define SCIPerrorMessage
Definition: pub_message.h:45
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4113
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:12459
interval arithmetics for provable bounds
static SCIP_RETCODE removeFixedVariables(SCIP *scip, SCIP_CONS *cons)
void SCIPintervalSetEmpty(SCIP_INTERVAL *resultant)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:45998
SCIP_RETCODE SCIPaddConsLocal(SCIP *scip, SCIP_CONS *cons, SCIP_NODE *validnode)
Definition: scip.c:13079
SCIP_RETCODE SCIPaddNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition: scip.c:31216
SCIP_VAR ** vars
enum SCIP_NlpSolStat SCIP_NLPSOLSTAT
Definition: type_nlpi.h:69
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:13160
SCIP_Real SCIPintervalGetInf(SCIP_INTERVAL interval)
static SCIP_DECL_CONSDELETE(consDeleteQuadratic)
static SCIP_DECL_CONSPARSE(consParseQuadratic)
SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
Definition: lp.c:16500
SCIP_RETCODE SCIPreleaseNlRow(SCIP *scip, SCIP_NLROW **nlrow)
Definition: scip.c:32031
static SCIP_RETCODE presolveUpgrade(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Bool *upgraded, int *nupgdconss, int *naddconss, SCIP_PRESOLTIMING presoltiming)
SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: scip.c:19006
static SCIP_RETCODE catchQuadVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons, int quadvarpos)
SCIP_Real * SCIPgetCoefsLinearVarsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIPInterval sqrt(const SCIPInterval &x)
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip.h:22004
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip.c:45753
int SCIPgetLinvarMayDecreaseQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcheckCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool checkintegrality, SCIP_Bool checklprows, SCIP_Bool printreason, SCIP_RESULT *result)
Definition: scip.c:28346
SCIP_Bool SCIPsortedvecFindPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void *val, int len, int *pos)
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:21477
static SCIP_DECL_CONSCHECK(consCheckQuadratic)
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:7881
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8100
#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:16555
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip.c:6057
static SCIP_DECL_CONSTRANS(consTransQuadratic)
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:2797
constraint handler for quadratic constraints
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4133
SCIP_RETCODE SCIPcreateRowprep(SCIP *scip, SCIP_ROWPREP **rowprep, SCIP_SIDETYPE sidetype, SCIP_Bool local)
#define CONSHDLR_CHECKPRIORITY
#define NULL
Definition: lpi_spx1.cpp:137
SCIP_RETCODE SCIPmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:28258
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:2382
SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:38317
int SCIPgetNNlpis(SCIP *scip)
Definition: scip.c:9479
#define REALABS(x)
Definition: def.h:169
SCIP_RETCODE SCIPsetNLPInitialGuessSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:31293
SCIP_RETCODE SCIPgetNlRowQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_NLROW **nlrow)
SCIP_RETCODE SCIPcreateChild(SCIP *scip, SCIP_NODE **node, SCIP_Real nodeselprio, SCIP_Real estimate)
Definition: scip.c:36877
SCIP_QUADELEM * SCIPnlrowGetQuadElems(SCIP_NLROW *nlrow)
Definition: nlp.c:3332
#define SCIP_CALL(x)
Definition: def.h:316
#define SCIP_EVENTTYPE_LBTIGHTENED
Definition: type_event.h:63
unsigned int SCIP_PRESOLTIMING
Definition: type_timing.h:52
static SCIP_RETCODE disaggregate(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, int *naddconss, int *ndelconss, SCIP_Bool *success)
Definition: cons_soc.c:2829
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46359
#define CONSHDLR_ENFOPRIORITY
SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
Definition: var.c:16973
SCIP_Real sup
Definition: intervalarith.h:40
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46346
void SCIPintervalSet(SCIP_INTERVAL *resultant, SCIP_Real value)
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:16401
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip.c:1353
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8120
static void rowprepCleanupScaledown(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_Real *viol, SCIP_Real minviol)
#define SCIPdebugGetSolVal(scip, var, val)
Definition: debug.h:265
SCIP_RETCODE SCIPaddCut(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip.c:33999
static SCIP_RETCODE rowprepCleanupSortTerms(SCIP *scip, SCIP_ROWPREP *rowprep)
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:50
SCIP_BILINTERM * SCIPgetBilinTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
#define SCIP_EVENTTYPE_BOUNDTIGHTENED
Definition: type_event.h:106
SCIP_RETCODE LapackDsyev(SCIP_Bool computeeigenvectors, int N, SCIP_Real *a, SCIP_Real *w)
SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
Definition: lp.c:16337
SCIP_NLPSOLSTAT SCIPnlpiGetSolstat(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem)
Definition: nlpi.c:509
SCIP_RETCODE SCIPnlpiSetObjective(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem, int nlins, const int *lininds, const SCIP_Real *linvals, int nquadelems, const SCIP_QUADELEM *quadelems, const int *exprvaridxs, const SCIP_EXPRTREE *exprtree, const SCIP_Real constant)
Definition: nlpi.c:300
#define SCIP_EVENTTYPE_UBCHANGED
Definition: type_event.h:105
SCIP_Bool SCIPhasPrimalRay(SCIP *scip)
Definition: scip.c:40351
void SCIPaddSquareSecant(SCIP *scip, SCIP_Real sqrcoef, SCIP_Real lb, SCIP_Real ub, SCIP_Real refpoint, SCIP_Real *lincoef, SCIP_Real *linconstant, SCIP_Bool *success)
Definition: scip.c:33091
int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4515
static SCIP_RETCODE consdataEnsureAdjBilinSize(SCIP *scip, SCIP_QUADVARTERM *quadvarterm, int num)
SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
Definition: scip.c:46073
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:13053
SCIP_RETCODE SCIPgetViolationQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *violation)
SCIP_Bool SCIPvarIsOriginal(SCIP_VAR *var)
Definition: var.c:16684
SCIP_RETCODE SCIPaddBilinTermQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Real coef)
SCIP_RETCODE SCIPnlpiFreeProblem(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM **problem)
Definition: nlpi.c:224
Ipopt NLP interface.
static SCIP_RETCODE computeInteriorPoint(SCIP *scip, SCIP_CONS *cons, char method, SCIP_Bool *success)
static SCIP_RETCODE propagateBoundsTightenVarUb(SCIP *scip, SCIP_CONS *cons, SCIP_Real intervalinfty, SCIP_VAR *var, SCIP_Real bnd, SCIP_RESULT *result, int *nchgbds)
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip.h:21991
SCIP_Real * SCIProwGetVals(SCIP_ROW *row)
Definition: lp.c:16347
SCIP_BOUNDTYPE * SCIPvarGetImplTypes(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17479
#define CONSHDLR_NEEDSCONS
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:982
static SCIP_DECL_CONSINITLP(consInitlpQuadratic)
SCIP_Real side
#define SCIP_Bool
Definition: def.h:61
static SCIP_DECL_CONSFREE(consFreeQuadratic)
SCIP_RETCODE SCIPcatchEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip.c:40434
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip.c:28948
static SCIP_RETCODE presolveDisaggregate(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *naddconss)
SCIP_Bool SCIPexprgraphAreAllNodeChildrenVars(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14552
static void rowprepCleanupIntegralCoefs(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_Real *viol)
#define CONSHDLR_DELAYSEPA
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyQuadratic)
static SCIP_RETCODE registerBranchingCandidatesCentrality(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, int *nnotify)
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:959
static SCIP_RETCODE computeGauge(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons)
static SCIP_RETCODE generateCutFactorable(SCIP *scip, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_Real *ref, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
static const char * paramname[]
Definition: lpi_msk.c:4271
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip.c:30152
SCIP_Real SCIPgetLhsNonlinear(SCIP *scip, SCIP_CONS *cons)
#define NONLINCONSUPGD_PRIORITY
int SCIPgetDepth(SCIP *scip)
Definition: scip.c:42321
SCIP_RETCODE SCIPnlpiSetIntPar(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem, SCIP_NLPPARAM type, int ival)
Definition: nlpi.c:633
constraint handler for nonlinear constraints
int SCIPvarGetNImpls(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17447
void SCIPintervalSolveBivariateQuadExpressionAllScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_Real ax, SCIP_Real ay, SCIP_Real axy, SCIP_Real bx, SCIP_Real by, SCIP_INTERVAL rhs, SCIP_INTERVAL xbnds, SCIP_INTERVAL ybnds)
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip.c:28746
void SCIPmergeRowprepTerms(SCIP *scip, SCIP_ROWPREP *rowprep)
int SCIPvarGetNLocksUp(SCIP_VAR *var)
Definition: var.c:3217
#define MAX(x, y)
Definition: tclique_def.h:75
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:9411
SCIP_NLPTERMSTAT SCIPnlpiGetTermstat(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem)
Definition: nlpi.c:521
static SCIP_DECL_CONSEXITSOL(consExitsolQuadratic)
static SCIP_RETCODE replaceByLinearConstraints(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool *addedcons, SCIP_Bool *reduceddom, SCIP_Bool *infeasible)
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:34094
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:7901
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11249
methods for debugging
static SCIP_RETCODE generateCutLTI(SCIP *scip, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_Real *ref, SCIP_SOL *sol, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
SCIP_RETCODE SCIPcreateEmptyRowSepa(SCIP *scip, SCIP_ROW **row, SCIP_SEPA *sepa, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip.c:30181
static void consdataSortLinearVars(SCIP_CONSDATA *consdata)
SCIP_RETCODE SCIPsetConshdlrDisable(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDISABLE((*consdisable)))
Definition: scip.c:6424
SCIP_RETCODE SCIPdropEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip.c:40468
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip.c:37806
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8080
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8050
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17017
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip.c:40548
SCIP_RETCODE SCIPcreateVar(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_DECL_VARCOPY((*varcopy)), SCIP_VARDATA *vardata)
Definition: scip.c:17314
SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
Definition: scip.c:36572
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:93
#define ROWPREP_SCALEUP_MAXSIDE
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:21403
SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:38268
#define infty2infty(infty1, infty2, val)
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip.c:6470
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata)
#define SCIP_EVENTTYPE_UBTIGHTENED
Definition: type_event.h:65
Constraint handler for linear constraints in their most general form, .
static SCIP_RETCODE createNlRow(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE computeViolations(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool *solviolbounds, SCIP_CONS **maxviolcon)
SCIP_Bool SCIPisCutApplicable(SCIP *scip, SCIP_ROW *cut)
Definition: scip.c:33981
int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition: var.c:16937
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
Definition: scip.c:46061
SCIP_Real * SCIPvarGetImplBounds(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17493
#define CONSHDLR_NAME
#define BMSclearMemory(ptr)
Definition: memory.h:88
static SCIP_Bool consdataCheckBilinTermsSort(SCIP_CONSDATA *consdata)
SCIP_RETCODE SCIPgetRowprepRowCons(SCIP *scip, SCIP_ROW **row, SCIP_ROWPREP *rowprep, SCIP_CONSHDLR *conshdlr)
char name[SCIP_MAXSTRLEN]
SCIP_RETCODE SCIPsetConshdlrEnable(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENABLE((*consenable)))
Definition: scip.c:6401
void * SCIPexprgraphGetNodeVar(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12982
int SCIPgetNBinVars(SCIP *scip)
Definition: scip.c:11725
SCIP_Bool SCIPisLinearLocalQuadratic(SCIP *scip, SCIP_CONS *cons)
static void generateCutLTIcomputeCoefs(SCIP *scip, SCIP_Real xl, SCIP_Real xu, SCIP_Real x0, SCIP_Real yl, SCIP_Real yu, SCIP_Real y0_, SCIP_Real wl, SCIP_Real wu, SCIP_Real w0, SCIP_Real *cx, SCIP_Real *cy, SCIP_Real *cw, SCIP_Real *c0, SCIP_Bool *success)
static SCIP_DECL_CONSENFORELAX(consEnforelaxQuadratic)
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip.c:35163
static SCIP_Bool generateCutLTIfindIntersection(SCIP *scip, SCIP_Real x0, SCIP_Real y0_, SCIP_Real x1, SCIP_Real y1_, SCIP_Real wl, SCIP_Real wu, SCIP_Real *xl, SCIP_Real *yl, SCIP_Real *xu, SCIP_Real *yu)
SCIP_Real * SCIPexprgraphGetNodeQuadraticLinearCoefs(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13065
#define ROWPREP_SCALEUP_MINVIOLFACTOR
int SCIPgetNVars(SCIP *scip)
Definition: scip.c:11680
SCIP_RETCODE SCIPcheckCurvatureQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPnodeGetEstimate(SCIP_NODE *node)
Definition: tree.c:7202
void SCIPenableNLP(SCIP *scip)
Definition: scip.c:30950
static SCIP_RETCODE registerLargeRelaxValueVariableForBranching(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_VAR **brvar)
SCIP_QUADVAREVENTDATA * eventdata
SCIP_VAR ** SCIPvarGetImplVars(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17464
SCIP_RETCODE SCIPcreateConsLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip.c:6201
enum SCIP_ExprCurv SCIP_EXPRCURV
Definition: type_expr.h:93
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip.c:30290
int SCIPgetLinvarMayIncreaseQuadratic(SCIP *scip, SCIP_CONS *cons)
int SCIPgetNLinearVarsQuadratic(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE addBilinearTerm(SCIP *scip, SCIP_CONS *cons, int var1pos, int var2pos, SCIP_Real coef)
SCIP_RETCODE SCIPcreateNLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip.c:37248
static void consdataMoveQuadVarTerm(SCIP_CONSDATA *consdata, int oldpos, int newpos)
int SCIPvarGetNLocksDown(SCIP_VAR *var)
Definition: var.c:3162
static SCIP_RETCODE processCut(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real efficacy, SCIP_Real actminefficacy, SCIP_Bool inenforcement, SCIP_Real *bestefficacy, SCIP_RESULT *result)
void SCIPsort(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
Definition: misc.c:4652
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46024
SCIP_RETCODE SCIPcopyRowprep(SCIP *scip, SCIP_ROWPREP **target, SCIP_ROWPREP *source)
static SCIP_RETCODE consdataCreateEmpty(SCIP *scip, SCIP_CONSDATA **consdata)
static SCIP_DECL_CONSGETNVARS(consGetNVarsQuadratic)
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
Definition: scip.c:46134
SCIP_RETCODE SCIPaddCharParam(SCIP *scip, const char *name, const char *desc, char *valueptr, SCIP_Bool isadvanced, char defaultvalue, const char *allowedvalues, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:4321
SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
Definition: lp.c:16161
int SCIPgetNLinearVarsNonlinear(SCIP *scip, SCIP_CONS *cons)
void SCIPfreeParseVarsPolynomialData(SCIP *scip, SCIP_VAR ****monomialvars, SCIP_Real ***monomialexps, SCIP_Real **monomialcoefs, int **monomialnvars, int nmonomials)
Definition: scip.c:18371
SCIP_RETCODE SCIPgetVarCopy(SCIP *sourcescip, SCIP *targetscip, SCIP_VAR *sourcevar, SCIP_VAR **targetvar, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global, SCIP_Bool *success)
Definition: scip.c:1912
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:11360
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:7911
#define CONSHDLR_DESC
SCIP_RETCODE SCIPsetConshdlrInit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINIT((*consinit)))
Definition: scip.c:6081
SCIP_Real SCIPintervalQuadUpperBound(SCIP_Real infinity, SCIP_Real a, SCIP_INTERVAL b_, SCIP_INTERVAL x)
SCIP_RETCODE SCIPsetConshdlrExit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXIT((*consexit)))
Definition: scip.c:6105
static SCIP_RETCODE dropVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons)
static SCIP_DECL_CONSGETVARS(consGetVarsQuadratic)
#define SCIP_EVENTTYPE_FORMAT
Definition: type_event.h:135
static void rowprepCleanupSide(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_Real *viol)
static SCIP_DECL_CONSCOPY(consCopyQuadratic)
static SCIP_DECL_CONSINIT(consInitQuadratic)
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip.c:27417
static SCIP_RETCODE unlockLinearVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
void SCIPintervalSetRoundingModeUpwards(void)
static SCIP_RETCODE computeReferencePointProjection(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *refsol, SCIP_Real *ref)
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip.c:6225
NLP local search primal heuristic using sub-SCIPs.
static SCIP_RETCODE generateCutSol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_SOL *refsol, SCIP_SIDETYPE violside, SCIP_ROW **row, SCIP_Real *efficacy, SCIP_Bool checkcurvmultivar, SCIP_Real minefficacy, char mode)
SCIP_Real SCIPgetRowLPFeasibility(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30709
SCIP_RETCODE SCIPgetFeasibilityQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *feasibility)
SCIP_RETCODE SCIPsortQuadVarTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPeventGetOldbound(SCIP_EVENT *event)
Definition: event.c:1138
int SCIPscaleRowprep(SCIP_ROWPREP *rowprep, SCIP_Real factor)
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:46397
void SCIPsortDownRealRealPtr(SCIP_Real *realarray1, SCIP_Real *realarray2, void **ptrarray, int len)
SCIP_RETCODE SCIPgetNLPFracVars(SCIP *scip, SCIP_VAR ***fracvars, SCIP_Real **fracvarssol, SCIP_Real **fracvarsfrac, int *nfracvars, int *npriofracvars)
Definition: scip.c:31468
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:16674
SCIP_RETCODE SCIPaggregateVars(SCIP *scip, SCIP_VAR *varx, SCIP_VAR *vary, SCIP_Real scalarx, SCIP_Real scalary, SCIP_Real rhs, SCIP_Bool *infeasible, SCIP_Bool *redundant, SCIP_Bool *aggregated)
Definition: scip.c:25344
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:18427
#define SCIP_Real
Definition: def.h:145
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8130
SCIP_RETCODE SCIPaddVarsToRow(SCIP *scip, SCIP_ROW *row, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip.c:30444
SCIP_RETCODE SCIPaddToNlpiProblemQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *nlpiprob, SCIP_HASHMAP *scipvar2nlpivar, SCIP_Bool names)
SCIP_VAR ** SCIPgetLinearVarsNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip.c:1138
#define MIN(x, y)
Definition: memory.c:75
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip.c:6539
void SCIPintervalMulScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
SCIP_Bool SCIPhaveVarsCommonClique(SCIP *scip, SCIP_VAR *var1, SCIP_Bool value1, SCIP_VAR *var2, SCIP_Bool value2, SCIP_Bool regardimplics)
Definition: scip.c:24623
static SCIP_RETCODE computeReferencePointGauge(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *refsol, SCIP_Real *ref, SCIP_Bool *success)
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8070
static SCIP_RETCODE checkFactorable(SCIP *scip, SCIP_CONS *cons)
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12900
#define SCIP_INVALID
Definition: def.h:165
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8060
void SCIPsortPtrReal(void **ptrarray, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip.c:30892
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:130
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:17281
SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:38011
#define SCIPdebugAddSolVal(scip, var, val)
Definition: debug.h:264
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:16720
static SCIP_DECL_CONSLOCK(consLockQuadratic)
SCIP_RETCODE SCIPcreateConsBounddisjunction(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_BOUNDTYPE *boundtypes, SCIP_Real *bounds, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPparseVarsPolynomial(SCIP *scip, const char *str, SCIP_VAR ****monomialvars, SCIP_Real ***monomialexps, SCIP_Real **monomialcoefs, int **monomialnvars, int *nmonomials, char **endptr, SCIP_Bool *success)
Definition: scip.c:18019
int SCIP_ROUNDMODE
Definition: intervalarith.h:46
void SCIPintervalMulInf(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
void SCIPintervalSub(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:46098
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46011
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:49
static SCIP_DECL_EVENTEXEC(processVarEvent)
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17235
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip.h:21976
static SCIP_RETCODE addLinearCoef(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:16697
SCIP_RETCODE SCIPupdateStartpointHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *solcand, SCIP_Real violation)
Definition: heur_subnlp.c:2423
SCIP_Bool SCIPconsIsMarkedPropagate(SCIP_CONS *cons)
Definition: cons.c:8090
#define CONSHDLR_PROP_TIMING
#define SCIP_DECL_QUADCONSUPGD(x)
static SCIP_DECL_CONSPROP(consPropQuadratic)
SCIP_Real * coefs
SCIP_NLPI ** SCIPgetNlpis(SCIP *scip)
Definition: scip.c:9466
static SCIP_RETCODE delQuadVarTermPos(SCIP *scip, SCIP_CONS *cons, int pos)
SCIP_Real SCIPgetUpperbound(SCIP *scip)
Definition: scip.c:42699
static SCIP_DECL_CONSPRINT(consPrintQuadratic)
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:2845
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:89
SCIP_Bool SCIPisSumLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46232
#define ROWPREP_SCALEUP_MAXMINCOEF
static SCIP_RETCODE presolveDisaggregateMarkComponent(SCIP *scip, SCIP_CONSDATA *consdata, int quadvaridx, SCIP_HASHMAP *var2component, int componentnr)
#define CONSHDLR_SEPAFREQ
static SCIP_RETCODE computeED(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons)
SCIP_QUADVARTERM * SCIPgetQuadVarTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcreateNlRow(SCIP *scip, SCIP_NLROW **nlrow, const char *name, SCIP_Real constant, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadvars, SCIP_VAR **quadvars, int nquadelems, SCIP_QUADELEM *quadelems, SCIP_EXPRTREE *expression, SCIP_Real lhs, SCIP_Real rhs, SCIP_EXPRCURV curvature)
Definition: scip.c:31923
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:13089
SCIP_EXPRGRAPHNODE * SCIPgetExprgraphNodeNonlinear(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE computeViolation(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *solviolbounds)
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
Definition: scip.c:46183
void SCIPprintRowprep(SCIP *scip, SCIP_ROWPREP *rowprep, FILE *file)
constraint handler for bound disjunction constraints
void SCIPintervalAddScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip.c:6153
SCIP_Longint SCIPgetNLPs(SCIP *scip)
Definition: scip.c:41590
#define SCIPABORT()
Definition: def.h:288
SCIP_Real SCIPround(SCIP *scip, SCIP_Real val)
Definition: scip.c:46195
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:16746
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:7945
SCIP_RETCODE SCIPgetRowprepRowSepa(SCIP *scip, SCIP_ROW **row, SCIP_ROWPREP *rowprep, SCIP_SEPA *sepa)
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip.c:38182
static SCIP_RETCODE mergeAndCleanQuadVarTerms(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisInRestart(SCIP *scip)
Definition: scip.c:17277
SCIP_SOL * SCIPeventGetSol(SCIP_EVENT *event)
Definition: event.c:1223
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:4293
#define SCIPduplicateBlockMemory(scip, ptr, source)
Definition: scip.h:21968
static SCIP_RETCODE consdataEnsureLinearVarsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num)
static SCIP_RETCODE enforceConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_Bool solinfeasible, SCIP_RESULT *result)
void SCIPintervalSetRoundingModeDownwards(void)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
Definition: scip.c:46171
SCIP_Bool SCIPisConvexQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPgetPrimalRayVal(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:40369
static SCIP_DECL_CONSDISABLE(consDisableQuadratic)
SCIP_RETCODE SCIPgetActivityQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *activity)
static SCIP_Bool hasQuadvarHpProperty(SCIP *scip, SCIP_CONSDATA *consdata, int idx)
SCIP_Bool SCIPintervalIsSubsetEQ(SCIP_Real infinity, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:4211
void SCIPintervalSolveUnivariateQuadExpressionPositive(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL rhs)
static SCIP_RETCODE catchLinearVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons, int linvarpos)
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:16842
void SCIPaddSquareLinearization(SCIP *scip, SCIP_Real sqrcoef, SCIP_Real refpoint, SCIP_Bool isint, SCIP_Real *lincoef, SCIP_Real *linconstant, SCIP_Bool *success)
Definition: scip.c:33023
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip.h:21995
uint64_t SCIP_EVENTTYPE
Definition: type_event.h:134
void SCIPaddRowprepConstant(SCIP_ROWPREP *rowprep, SCIP_Real constant)
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip.c:5966
static SCIP_RETCODE generateCutUnboundedLP(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_ROW **row, SCIP_Real *rowrayprod, SCIP_Bool checkcurvmultivar)
void SCIPintervalQuad(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_Real sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL xrng)
enum SCIP_SideType SCIP_SIDETYPE
Definition: type_lp.h:58
SCIP_QUADELEM * SCIPexprgraphGetNodeQuadraticQuadElements(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13077